2009-07-27 19 views
6

Tak więc staram się przyjmować dobre metody programowania obiektowego z PHP. Większość (czytaj wszystkie) moich projektów dotyczy bazy danych MySQL. Mój bezpośredni problem dotyczy modelu użytkowników, który muszę opracować.Dziedziczenie PHP i MySQL

Mój obecny projekt ma agentów i potencjalnych klientów. Zarówno agenci, jak i potencjalni klienci to użytkownicy o dużej liczbie tych samych informacji. Tak więc, oczywiście, chcę, aby agenci klasowi i liderzy klasy rozszerzyli użytkowników tej samej klasy. Teraz moje pytanie brzmi następująco:

Jak najlepiej obsłużyć SQL do ładowania tych obiektów? Nie chcę wykonywać wielu instrukcji SQL podczas tworzenia instancji agenta lub potencjalnego klienta. Jednak logika mówi mi, że kiedy konstruktor Użytkownicy jest uruchamiany, powinien wykonać instrukcję SQL, aby załadować wspólne informacje między agentami i namiarami (nazwa użytkownika, hasło, adres e-mail, dane kontaktowe itp.). Logic mówi mi również, że kiedy uruchamiany jest konstruktor Agentów lub Leadów, chcę wykonać SQL, aby załadować dane unikalne dla klasy Agenci lub Leads .... Ale, znowu, logika również mówi mi, że to zły pomysł na wykonanie 2 Instrukcje SQL za każdym razem, gdy potrzebuję agenta lub potencjalnego klienta (ponieważ może być ich tysiące).

Próbowałem szukać przykładów tego, jak to się zwykle robi bez powodzenia ... Być może szukam czegoś niewłaściwego?

Odpowiedz

7

Zasadniczo są trzy podejścia do tego problemu (z których jeden będę eliminują natychmiast):

  1. Jedna tabela na klasy (jest to jeden będę wyeliminować);
  2. Typ rekordu z opcjonalnymi kolumnami; i
  3. Typ rekordu z tabelą podrzędną w zależności od typu, do którego się przyłącza.

Dla uproszczenia generalnie polecam (2). Więc gdy już masz swój stół:

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY, 
    type VARCHAR(10), 
    name VARCHAR(100) 
); 

gdzie typ może być "AGENT" lub "LEAD" (na przykład). Alternatywnie możesz użyć kodów jednego rodzaju. Następnie można rozpocząć wypełnianie pustych miejsc modelem obiektu:

  • Masz klasę nadrzędną użytkownika;
  • Masz dwie klasy dzieci: potencjalnego klienta i agenta;
  • Te dzieci mają stały typ.

i powinno się dość łatwo osadzić.

Jeśli chodzi o ładowanie w jednym zestawieniu, używałbym jakiejś fabryki. Zakładając te Barebone klasy:

class User { 
    private $name; 
    private $type; 
    protected __construct($query) { 
    $this->type = $query['type']; 
    $this->name = $query['name']; 
    } 
    ... 
} 

class Agent { 
    private $agency; 
    public __construct($query) { 
    parent::constructor($query); 
    $this->agency = $query['agency']; 
    } 
    ... 
} 

class Lead { 
    public __consruct($query) { 
    parent::constructor($query); 
    } 
    ... 
} 

fabryka mogłaby wyglądać następująco:

public function loadUserById($id) { 
    $id = mysql_real_escape_string($id); // just in case 
    $sql = "SELECT * FROM user WHERE id = $id"; 
    $query = mysql_query($sql); 
    if (!query) { 
    die("Error executing $sql - " . mysql_error()); 
    } 
    if ($query['type'] == 'AGENT') { 
    return new Agent($query); 
    } else if ($query['type'] == 'LEAD') { 
    return new Lead($query); 
    } else { 
    die("Unknown user type '$query[type]'"); 
    } 
} 

Alternatywnie, można mieć metoda fabryka być statyczna metoda na, powiedzmy, klasa użytkownika i/lub użyć tabela odnośników dla typów do klas.

Być może zanieczyszczanie klas takim zasobem wyników zapytania jest wątpliwym projektem w najostrzejszym sensie OO, ale jest proste i działa.

+0

Bardzo podoba mi się ten pomysł, tak myślę. Ale najbardziej nęka mnie to, gdzie wykonać SQL, aby załadować wszystkie dane ... Nie mogę umieścić go w klasie User, ponieważ w zależności od typu potrzebuję innego SQL. Nie chcę umieszczać tego wszystkiego w klasie Agent i Lead, ponieważ znaczna część kodu byłaby taka sama i chcę uniknąć kopiowania i wklejania ... Idealnie, chciałbym, aby klasa User mogła załadować informacje wspólne i klasy Agent/Lead, aby załadować unikalne informacje ...... ale potem wykonuję 2 instrukcje SQL za każdym razem, gdy uruchamiam agenta lub potencjalnego klienta, co jest niepożądane ..... – SpaDusA

+0

Możesz to zrobić w 1 instrukcji SQL. Powiedz mi jednak, czego używasz do załadowania konkretnego użytkownika? Co przekazujesz? Identyfikator? Coś innego? – cletus

+0

Mam 2 funkcje ładowania: loadAll i loadById. Każdy Ołów/Agent ma imię, nazwisko, nazwę użytkownika, hasło, 2 numery telefonów, adres e-mail. Prowadzący ma obszar zainteresowania i "jak o nas słyszałeś". Agent ma zasięg i języki, którymi się posługują. – SpaDusA

0

Czy kiedykolwiek będziesz mieć użytkownika, który nie jest potencjalnym klientem lub agentem? Czy ta klasa naprawdę musi w ogóle pobierać dane z bazy danych?

Jeśli tak, to dlaczego nie przeciągnąć zapytania SQL do funkcji, którą można przesłonić podczas tworzenia klasy potomnej.

+0

To jest rzeczywiście zalecenie innych facetów w zespole. Jedynym powodem, dla którego nie chciałem wstawić SQL do funkcji, którą mógłbym zastąpić, jest to, że większość SQL jest taka sama w 3 klasach; Nie chciałem kopiować i wklejać funkcji ... Wolę dziedziczyć SQL, że tak powiem ... Czy to w ogóle jest jasne? – SpaDusA

0

Nie możesz dziedziczyć, powiedzmy szkieletu SQL, a następnie użyć funkcji w każdej z podklas do wypełnienia zapytania w oparciu o jego potrzeby?

Korzystanie z naprawdę podstawowy przykład:

<?php 
//our query which could be defined in superclass 
$query = "SELECT :field FROM :table WHERE :condition"; 

//in our subclass 
$field = "user, password, email"; 
$table = "agent"; 
$condition = "name = 'jim'"; 

$dbh->prepare($query); 
$sth->bindParam(':field', $field); 
$sth->bindParam....;//etc 

$sth->execute(); 
?> 

Jak widać mój przykład nie jest niesamowite, ale powinny pozwalają zobaczyć, co mi chodzi. Jeśli twoje zapytanie jest bardzo podobne między podklasami, myślę, że moja sugestia może zadziałać.

Oczywiście potrzebne będą pewne poprawki, ale prawdopodobnie podejmie to podejście.