2009-07-27 18 views
6

Así que estoy tratando de adoptar buenas técnicas de programación orientadas a objetos con PHP. La mayoría (leer todos) de mis proyectos involucran una base de datos MySQL. Mi problema inmediato trata del modelo de usuarios que necesito desarrollar.PHP Herencia y MySQL

Mi proyecto actual tiene agentes y clientes potenciales. Tanto los agentes como los clientes potenciales son usuarios con mucha de la misma información. Entonces, obviamente, quiero una clase Agents y una clase Leads para extender una clase común Usuarios. Ahora, mi pregunta es la siguiente:

¿Cómo se debe manejar el SQL para cargar estos objetos? No quiero ejecutar varias declaraciones SQL cuando instancia un agente o un cliente potencial. Sin embargo, la lógica me dice que cuando el constructor de Usuarios se dispara, debe ejecutar una declaración SQL para cargar la información común entre Agentes y Clientes potenciales (nombre de usuario, contraseña, correo electrónico, información de contacto, etc.). La lógica también me dice que cuando se activa el constructor Agentes o Leads, quiero ejecutar SQL para cargar los datos exclusivos de la clase Agents o Leads .... Pero, de nuevo, la lógica también me dice que es una mala idea ejecutar 2 Declaraciones de SQL cada vez que necesito un agente o cliente potencial (ya que puede haber miles de cada uno).

He intentado buscar ejemplos de cómo esto se maneja generalmente sin éxito ... ¿Tal vez estoy buscando algo equivocado?

Respuesta

7

usted tiene básicamente tres enfoques a este problema (una de las cuales voy a eliminar de inmediato):

  1. una tabla por clase (este es el que yo elimino);
  2. Un tipo de registro con columnas opcionales; y
  3. Un tipo de registro con una tabla secundaria según el tipo al que se una.

Por simplicidad, generalmente recomiendo (2). Así que una vez que tenga su tabla:

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

donde tipo puede ser 'agente' o 'líder' (por ejemplo). Alternativamente, puedes usar códigos de tipo de personaje. A continuación, puede comenzar a completar los espacios en blanco con el modelo de objetos:

  • Tiene una clase principal de usuario;
  • Tienes dos clases secundarias: Plomo y agente;
  • Esos niños tienen un tipo fijo.

y debe colocarse en su lugar con bastante facilidad.

En cuanto a cómo cargar en una declaración, usaría algún tipo de fábrica. Asumiendo estas clases 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); 
    } 
    ... 
} 

una fábrica podría tener este aspecto:

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

Alternativamente, usted podría tener el método de fábrica sea un método estático en, por ejemplo, la clase de usuario y/o usar una tabla de búsqueda para los tipos a clases.

Tal vez la contaminación de las clases con el recurso de resultados de la consulta es un diseño cuestionable en el sentido OO más estricto, pero es simple y funciona.

+0

Me gusta mucho esta idea, creo. Pero lo que más me molesta es dónde ejecutar el SQL para cargar todos los datos ... No puedo ponerlo en la clase User porque dependiendo del tipo, necesitaré SQL diferente. No quiero poner todo en la clase Agente y Plomo porque gran parte del código sería el mismo y quiero evitar copiar y pegar ... Idealmente, me gustaría que la clase de Usuario pueda cargar el información común y las clases Agente/Cliente potencial para cargar la información única ... pero luego estoy ejecutando 2 instrucciones SQL cada vez que instancia un Agente o Cliente potencial, lo cual es indeseable ... – SpaDusA

+0

Puede hacerlo en 1 declaración SQL. Dime, ¿qué estás usando para cargar un usuario en particular? ¿Qué pasas? Una identificación? ¿Algo más? – cletus

+0

Tengo 2 funciones de carga: loadAll y loadById. Cada líder/agente tiene un nombre, apellido, nombre de usuario, contraseña, 2 números de teléfono, dirección de correo electrónico. Un líder tiene un área de interés y un '¿cómo se enteró de nosotros?' Un agente tiene un área de cobertura y qué idiomas hablan. – SpaDusA

0

¿Alguna vez tendrá un usuario que no sea un cliente potencial o un agente? ¿Realmente esa clase necesita extraer datos de la base de datos?

Si lo hace, ¿por qué no hacer que la consulta SQL entre en una función que puede anular cuando crea la clase secundaria?

+0

Esta es realmente la recomendación de los otros muchachos en el equipo. La única razón por la que no quería poner el SQL en una función que pudiera anular es porque gran parte del SQL es el mismo en las 3 clases; No quería tener que copiar y pegar las funciones ... Preferiría heredar el SQL, por así decirlo ... ¿Está claro para nada? – SpaDusA

0

¿No podría heredar, decir un esqueleto del SQL, luego usar una función en cada subclase para completar la consulta en función de sus necesidades?

Utilizando un ejemplo muy básico:

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

Como se puede ver mi ejemplo no es sorprendente, pero debería permitirle ver lo que quiero decir. Si su consulta es muy similar entre subclases, entonces creo que mi sugerencia podría funcionar.

Obviamente, necesitará algunos ajustes, pero es probable que sea el enfoque que tomaría.