2009-07-27 6 views
6

Donc j'essaie d'adopter de bonnes techniques de programmation orientées objet avec PHP. La plupart (lire tout) de mes projets impliquent une base de données MySQL. Mon problème immédiat concerne le modèle d'utilisateurs que je dois développer.PHP Inheritance et MySQL

Mon projet actuel a des agents et des prospects. Les agents et les prospects sont des utilisateurs avec une grande partie de la même information. Donc, évidemment, je veux une classe Agents et une classe Leads pour étendre une classe commune Users. Maintenant, ma question est la suivante:

Comment mieux gérer le SQL pour charger ces objets? Je ne veux pas exécuter plusieurs instructions SQL lorsque j'instancie un agent ou un prospect. Cependant, la logique me dit que lorsque le constructeur Utilisateurs est déclenché, il doit exécuter une instruction SQL pour charger les informations communes entre Agents et Leads (nom d'utilisateur, mot de passe, email, informations de contact, etc.). Logic me dit aussi que lorsque le constructeur Agents ou Leads est déclenché, je veux exécuter SQL pour charger les données uniques à la classe Agents ou Leads .... Mais, encore une fois, la logique me dit aussi que c'est une mauvaise idée d'exécuter 2 Déclarations SQL chaque fois que j'ai besoin d'un agent ou d'un prospect (car il peut y en avoir des milliers).

J'ai essayé de chercher des exemples de la façon dont cela est généralement géré sans succès ... Peut-être que je suis juste à la recherche de la mauvaise chose?

Répondre

7

Vous avez essentiellement trois approches de ce problème (dont je vais tout de suite): éliminons

  1. Une table par classe (ce qui est celui que j'éliminerons);
  2. Type d'enregistrement avec colonnes facultatives;
  3. Type d'enregistrement avec une table enfant en fonction du type auquel vous vous joignez.

Par simplicité, je recommande généralement (2). Donc, une fois que vous avez votre table:

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

où type peut être (par exemple) 'AGENT' ou 'LEAD'. Vous pouvez également utiliser un code de type de caractère. Vous pouvez ensuite commencer à remplir les blancs avec le modèle objet:

  • Vous avez une classe parent utilisateur;
  • Vous avez deux classes enfants: Lead et Agent;
  • Ces enfants ont un type fixe.

et il devrait tomber en place assez facilement.

Quant à la façon de charger dans une déclaration, je voudrais utiliser une sorte d'usine. En supposant que ces classes barebones:

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); 
    } 
    ... 
} 

une usine pourrait ressembler à ceci:

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]'"); 
    } 
} 

Sinon, vous pourriez avoir la méthode de fabrication est une méthode statique, par exemple, la classe utilisateur et/ou utiliser un table de recherche pour les types aux classes.

Peut-être polluer les classes avec la ressource de résultat de requête comme cela est un design discutable dans le sens OO le plus strict, mais c'est simple et cela fonctionne.

+0

J'aime vraiment cette idée, je pense. Mais ce qui me dérange le plus c'est l'endroit où exécuter le SQL pour charger toutes les données ... Je ne peux pas le mettre dans la classe User car selon le type, j'ai besoin de SQL différent. Je ne veux pas tout mettre dans la classe Agent et Lead car une grande partie du code serait la même et je veux éviter de copier et coller ... Idéalement, je voudrais que la classe User puisse charger le informations communes et les classes Agent/Lead pour charger l'information unique ...... mais alors j'exécute 2 instructions SQL chaque fois que j'instancie un agent ou un plomb, ce qui n'est pas souhaitable ..... – SpaDusA

+0

Vous pouvez le faire dans 1 instruction SQL. Dites-moi cependant, qu'est-ce que vous utilisez pour charger un utilisateur en particulier? Qu'est-ce que vous passez? Un identifiant? Autre chose? – cletus

+0

J'ai 2 fonctions de chargement: loadAll et loadById. Chaque responsable/agent a un prénom, nom de famille, nom d'utilisateur, mot de passe, 2 numéros de téléphone, adresse e-mail. Un chef de file a un domaine d'intérêt et un «comment avez-vous entendu parler de nous». Un agent dispose d'une zone de couverture et de quelles langues il parle. – SpaDusA

0

Avez-vous déjà un utilisateur qui n'est pas un prospect ou un agent? Est-ce que cette classe a vraiment besoin de tirer des données de la base de données? Si tel est le cas, pourquoi ne pas placer la requête SQL dans une fonction que vous pouvez remplacer lorsque vous créez la classe enfant.

+0

C'est en fait la recommandation des autres gars de l'équipe. La seule raison pour laquelle je n'ai pas voulu mettre le SQL dans une fonction que je pourrais remplacer est parce qu'une grande partie du SQL est la même dans les 3 classes; Je ne voulais pas avoir à copier et coller les fonctions ... Je préférerais de beaucoup hériter du SQL, pour ainsi dire ... Est-ce clair? – SpaDusA

0

Pourriez-vous hériter d'un squelette SQL, puis utiliser une fonction dans chaque sous-classe pour compléter la requête en fonction de ses besoins?

l'aide d'un exemple très basique:

<?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(); 
?> 

Comme vous pouvez le voir mon exemple n'est pas étonnant, mais devrait vous permettre de voir ce que je veux en venir. Si votre requête est très similaire entre les sous-classes, je pense que ma suggestion pourrait fonctionner.

De toute évidence, il faudra un peu de peaufinage, mais c'est probablement l'approche que je prendrais.