Ver Mensaje Individual
  #6 (permalink)  
Antiguo 16/11/2010, 01:12
limbvirgin
 
Fecha de Ingreso: noviembre-2010
Ubicación: León, Nic.
Mensajes: 13
Antigüedad: 14 años
Puntos: 1
Respuesta: Dudas con POO: getters y setters con DB, arrays multidimensionales...

Lo que hago yo es tratar de emular a un ORM en cosas básicas. Por ejemplo, una persona es una entidad, pero esa persona puede tener varios números telefónicos a los que puede ser contactado, en un esquema de base de datos SQL, necesitaríamos 2 tablas para poder encapsulara a 1 entidad que es "persona".

Este es el esquema de base de datos:

tabla persona, atributos: id, nombre, direccion.
tabla agenda, atributos: id, id_persona, telefono.

Están relacionadas por la llave local agenda.id_persona, y la llave foránea persona.id.

De tal forma que mediante POO accederé a la entidad "persona" mediante una única instancia, la cual tendrá métodos como getNombre, getDireccion, getTelefonos.

//archivo persona.php
Código PHP:
Ver original
  1. <?php
  2. class persona {
  3.    private $nombre;
  4.    private $direccion;
  5.    private $telefonos=array();
  6.  
  7.    public function setNombre($nombre){
  8.       $this->nombre=$nombre;
  9.     }
  10.  
  11.  public function setDireccion($direccion){
  12.       $this->direccion=$direccion;
  13.     }
  14.  
  15.  public function setTelefonos($telefonos){
  16.       $this->telefonos=$telefonos;
  17.     }
  18. }
  19. ?>

Ahora utilizamos una clase llamada dbPersona que es la encargada de acceder a la base de datos, y llenar instancias de la clase persona con los registros tomados de la base de datos.

Archivo dbPersona.php
Código PHP:
Ver original
  1. <?php
  2.  
  3. require_once 'persona.php';
  4.  
  5. class dbPersona {
  6.          private $host = "localhost";
  7.      private $db = "persona";
  8.      private $user = "root";
  9.      private $pass = "nose";
  10.          private $link;
  11.  
  12.     public function __construct(){
  13.         $this->conectar();
  14.      }
  15.      private function conectar(){
  16.         $link=mysql_connect($this->host, $this->user, $this->pass) or die ("Error.");
  17.           mysql_select_db($this->db ,$link) or die("Error.");
  18. $this->link=$link;
  19.      }
  20.    public function getAll(){  //DEVUELVE UNA COLECCION DE CLASES, NO UNA COLECCION DE ARRAYS
  21.     $result=mysql_query("SELECT * FROM persona", $this->link);
  22.     $personas=array();
  23.     while($row=mysql_fetch_array($result)){
  24.      $personas[]=$this->fetch($row);
  25.      }
  26.      return $personas;
  27.     }
  28.    public function getById($id){  //DEVUELVE UNA INSTANCIA DE LA CLASE PERSONA SEGUN EL ID.
  29.       $result=mysql_query("SELECT * FROM persona WHERE id='$id'",$this->link);
  30.       $row=mysql_fetch_array($result);
  31.       $persona=$this->fetch($row);
  32.       return $persona;
  33.    }
  34.  
  35.    private function getTelefonos($id_persona){
  36.    $result=mysql_query("SELECT telefono FROM agenda WHERE id_persona='$id_persona'",$this->link);
  37.     $telefonos=array();
  38.      while($row=mysql_fetch_array($result)) $telefonos[]=$row['telefono'];
  39.    
  40.      return $telefonos;
  41.  
  42.   }
  43.  
  44.  private function fetch($row){
  45.    $persona=new persona();
  46.    $persona->setId($row['id']);
  47.    $persona->setNombre($row['nombre']);
  48.    $persona->setDireccion($row['direccion'];
  49.    $telefonos=$this->getTelefonos($row['id']);
  50.    $persona->setTelefonos($telefonos);
  51.    return $persona;
  52.   }
  53. }
  54. ?>

Los archivos anteriores corresponden a la capa Modelo ( según el modelo MVC).

Para acceder a los datos de una persona:

Archivo index.php
Código PHP:
Ver original
  1. <?php
  2. require_once 'dbPersona.php';
  3. $db= new dbPersona();
  4. $personas= $db->getAll();
  5.  
  6. foreach($personas as $persona){
  7.   echo $persona->getNombre();
  8.   foreach($persona->getTelefonos() as $telefono){
  9.     echo $telefono;
  10.   }
  11. }
  12. ?>

De esta manera logramos encapsular los registros de una tabla relacional en entidades manejables desde una única instancia. A esto se le llama persistencia.

Debo aclarar que no utilizo la interfaz mysql de PHP sino la interfaz mysqli, así que no certifico la calidad del código jojojo ;)

También aclaro que la parte del modelo lo genero con un script que creé para facilitarme las cosas, pues escribir la parte del Modelo puede llegar a ser doloroso, pues consume tiempo, y es algo repetitivo, pero vale la pena el esfuerzo porque es mucho más fácil alimentar a los demás archivos de la capa Controlador y Vista con métodos intuitivos y objetos encapsulados (todo dentro de un mismo paquete, para una persona: su nombre, dirección, y lista de números telefónicos).

La conexión la hago en otro archivo "conectar.php" del cual heredo para todas la clases que accedan a la base de datos.

En resumen, en vez de acceder a los datos como simples arrays:
echo $persona['nombre'];

Lo hacemos mediante POO, donde $persona no es un array sino una clase:
echo $persona->getNombre();

Acceder a los atributos mediante métodos da mucha mayor flexibilidad.

A como puedes notar, el controlador "index.php" es bastante sencillo y extremadamente simple de comprender.

Recuerda que el código de la capa Modelo (en este ejemplo la clase persona y dbPersona) sólo se escribe una vez,
así que vale la pena el esfuerzo, porque así liberas de mucho peso y complejidad a la capa Controlador y Vista, que suele ser la parte dinámica
de una aplicación, y la parte que puede crecer y crecer, y es lo que cambia más durante el ciclo de vida de una aplicación.

Ahora, para el problema de "eficiencia" donde sólo quisieras mostrar el nombre de la persona, pero sin tener que cargar todos los datos de esa persona y
perder el tiempo cargando esos datos, podríamos hacer que al llamar al método getNombre, si el atributo nombre no ha sido establecido, haga una
consulta a la base de datos; así sólo se irán cargando dinámicamente los datos necesarios.

Código PHP:
Ver original
  1. require_once 'dbPersona.php';
  2.  
  3. class persona {
  4. private $id;
  5. private $nombre;
  6.  
  7. public function setNombre($nombre){
  8.  $this->nombre=$nombre;
  9. }
  10.  
  11. public funcion getNombre(){
  12.  if(!isset($this->nombre){
  13.   $db = new dbPersona();
  14.    $this->nombre=$db->getNombre($this->id);
  15.    }
  16.  return $this->nombre;
  17.  }
  18. }

El método getAll de la clase dbPersona, de primas a primeras sólo se encargaría de devolver una colección de clases
semi vacías, donde sólo se inicialicen los id;

Código PHP:
Ver original
  1. public function getAll(){
  2. $result="SELECT id FROM persona";
  3.  
  4. $personas=array();
  5.  
  6. while ($row=mysql_fetch_array($result)){
  7. $persona=new $persona();
  8. $persona->setId($row['id']);
  9. $personas[]=$persona;
  10. }
  11.  
  12. return $personas;
  13. }
  14.  
  15. public function getNombre($id){
  16. "SELECT nombre FROM persona WHERE id='$id'";
  17. return $nombre;
  18. }

En nuestro controlador el flujo de datos se vería así
Código PHP:
Ver original
  1. require_once 'dbPersona.php';
  2.  
  3. $db= new dbPersona();
  4. $personas=$db->getAll(); //devuelve clases donde sólo los id han sido inicializados
  5.  
  6. foreach ($personas as $persona){
  7.  
  8. echo $persona->getNombre()// como el atributo nombre está vacío, hace la consulta  a la DB.
  9. //imprime el nombre;
  10.  
  11. echo $persona->getNombre()//el atributo nombre ya ha sido inicalizado, por ende no ejecuta la consulta,
  12. // y devuelve el valor inmediatamente.
  13.  
  14. }

Aunque en realidad no sé qué tan eficiente - o no- puede ser eso jojo.

A modo de tip, en mi tiempo libre durante 2 días escribí un script para crear el 80% de la capa de Modelo (me falta pulir el script :P )
una vez terminado, sólo modifico un archivo YAMAL en el cual escribo lo siguiente:
Código XML:
Ver original
  1. all:
  2.  database:
  3.     host: localhost
  4.     user: root
  5.     pass: nose
  6.     esquema: curso
  7.  modelo:
  8.    persona: id, nombre, apellido, direccion
  9.    agenda: id, id_persona, telefono
----

Eso es todo, luego ejecuto el script y casi casi se me genera todo el código necesario. jojojo.

Así que ánimo. Imagino que habrán mejores maneras de hacerlo, pero mientras continuo aprendiendo, seguiré trabajando así por el momento ;)

Última edición por limbvirgin; 16/11/2010 a las 02:14