Foros del Web » Programando para Internet » PHP » Frameworks y PHP orientado a objetos »

Dudas con POO: getters y setters con DB, arrays multidimensionales...

Estas en el tema de Dudas con POO: getters y setters con DB, arrays multidimensionales... en el foro de Frameworks y PHP orientado a objetos en Foros del Web. Tengo dos dudas que no me dejan dormir y agradecería si alguien pudiese aconsejarme. Bien, imaginemos que tengo el objeto "Usuario" y tiene las propiedades ...
  #1 (permalink)  
Antiguo 14/11/2010, 15:40
 
Fecha de Ingreso: julio-2010
Mensajes: 16
Antigüedad: 14 años, 4 meses
Puntos: 0
Dudas con POO: getters y setters con DB, arrays multidimensionales...

Tengo dos dudas que no me dejan dormir y agradecería si alguien pudiese aconsejarme. Bien, imaginemos que tengo el objeto "Usuario" y tiene las propiedades "Nombre" y "Correo". Hereda de la clase mysql para gestionar las consultas a la base de datos.

Problema 1:
¿Getters y Setters con MySQL?

Código PHP:
Ver original
  1. <?php
  2. class usuario extends mysql {
  3.      private $nombre;
  4.  
  5.      public function __construct($id = null) {
  6.           $this->nombre = $this->getNombre();
  7.           $this->correo = $this->getCorreo();
  8.      }
  9.  
  10.      public function setNombre() {
  11.           $query parent::query();
  12.           while($row = results($query)) {
  13.                return $row["nombre"];
  14.           }
  15.      }
  16.  
  17.      public function getNombre() {
  18.           return $this->nombre;
  19.      }
  20.  
  21.      public function setCorreo() {
  22.           $query parent::query();
  23.           while($row = results($query)) {
  24.                return $row["correo"];
  25.           }
  26.      }
  27.  
  28.      public function getCorreo() {
  29.           return $this->correo;
  30.      }
  31. }
  32. ?>

Bien, esto claramente es poco eficiente. Consultar dos veces la BD pudiendo consultarla una única vez es absurdo. Así pues, decidí unificar haciendo esto:

Código PHP:
Ver original
  1. <?php
  2. class usuario extends mysql {
  3.      private $nombre;
  4.      private $correo;
  5.  
  6.      public function __construct($id = null) {
  7.           $this->setAll();
  8.      }
  9.  
  10.      public function setAll() {
  11.           $query parent::query();
  12.           while($row = results($query)) {
  13.                $this->nombre = $row["nombre"];
  14.                $this->correo = $row["correo"];
  15.           }
  16.      }
  17.  
  18.      public function getNombre() {
  19.           return $this->nombre;
  20.      }
  21.  
  22.      public function getCorreo() {
  23.           return $this->correo;
  24.      }
  25. }
  26. ?>

El problema: Si quiero imprimir solo el correo, también consultará en la BD el nombre y tantos campos como propiedades tenga la clase. Nuevamente, pérdida de eficiencia.
¿Cuál es la mejor forma de hacer esto?

Segundo Problema:
Quiero imprimir los 5 primeros usuarios de la siguiente forma:
Código HTML:
Nombre: Nombre 1
Correo: Correo 1

Nombre: Nombre 2
Correo: Correo 2

(...)

Nombre: Nombre 5
Correo: Correo 5
Usar el siguiente código no sería eficiente. Se hacen 5 consultas a la base de datos cuando se podría hacer 1.

Código PHP:
Ver original
  1. <?php
  2. for($i=1;$i<=5;$i++) {
  3.      $user = new usuario($i); //creamos el objeto para el usuario 1, el 2, el 3... el 5.
  4.      echo $user->getNombre;
  5.      echo $user->getCorreo;
  6. }
  7. ?>

Entonces, decidí crear un array multidimensional en el objeto usuario.

Código PHP:
Ver original
  1. <?php
  2. class usuario extends mysql {
  3.      private $nombre;
  4.      private $correo;
  5.  
  6.      public function __construct($id = null) {
  7.           $this->nombre = array();
  8.           $this->correo = array();
  9.           $query parent::query(/*ÚLTIMOS 5 USUARIOS*/);
  10.           while($row = results($query)) {
  11.                $nombre = $row["nombre"];
  12.                $correo = $row["correo"];
  13.  
  14.                array_push($this->nombre, $nombre); //tenemos todos los nombres en un arreglo
  15.                array_push($this->correo, $correo); //tenemos todos los correos en un arreglo
  16.           }
  17.      }
  18.  
  19.      public function getAll() {
  20.           $usuarios = array(); //vamos a crear el array multidimensional
  21.           $i = 0;
  22.           foreach($this->nombre as $nombre) {
  23.                $usuarios[] = array("nombre" => $nombre, "correo" => $this->correo[$i]);
  24.                $i++
  25.           }
  26. }
  27. ?>

Ahora tengo un arreglo multidimensional con todos los datos de los 5 últimos usuarios. Y para imprimir los datos:

Código PHP:
Ver original
  1. <?php
  2. $objeto = new usuario();
  3. $getall = $objeto->getAll();
  4. foreach($getall as $usuario) {
  5.      echo "Nombre ".$usuario["nombre"];
  6.      echo "Correo ".$usuario["correo"];
  7. }
  8. ?>

¿Está ideado correctamente? ¿Hay alternativas mejores? Por favor, me gustaría que aquellos expertos en POO me comentasen cómo lo ven o dijesen cómo lo harían ellos.

Gracias.
  #2 (permalink)  
Antiguo 14/11/2010, 23:24
Avatar de GatorV
$this->role('moderador');
 
Fecha de Ingreso: mayo-2006
Ubicación: /home/ams/
Mensajes: 38.567
Antigüedad: 18 años, 6 meses
Puntos: 2135
Respuesta: Dudas con POO: getters y setters con DB, arrays multidimensionales...

Te recomiendo leer un poco, vas bien pero te recomendaria leer precisamente de los patrones ActiveRecord y ActiveTable, con ellos vas a poder trabajar de forma más ordenada tus datos y vas a poder comprender de una forma más sencilla como manejar lo que quieres hacer

Saludos.
  #3 (permalink)  
Antiguo 15/11/2010, 08:00
 
Fecha de Ingreso: febrero-2009
Mensajes: 218
Antigüedad: 15 años, 9 meses
Puntos: 9
Respuesta: Dudas con POO: getters y setters con DB, arrays multidimensionales...

La clase usuario no debiera heredar la clase mysql por el simple hecho de la conexion, creo que tendrías que leer bien el concepto de herencia.
  #4 (permalink)  
Antiguo 15/11/2010, 08:33
 
Fecha de Ingreso: julio-2010
Mensajes: 16
Antigüedad: 14 años, 4 meses
Puntos: 0
Respuesta: Dudas con POO: getters y setters con DB, arrays multidimensionales...

Cita:
Iniciado por fernandozunni Ver Mensaje
La clase usuario no debiera heredar la clase mysql por el simple hecho de la conexion, creo que tendrías que leer bien el concepto de herencia.
Bueno, en realidad el código lo escribí para ilustrar lo que quería decir en el post. En mis clases originales no hereda de una clase mysql, sino de otro objeto. Claramente tienes toda la razón, no tiene sentido heredar de la clase base de datos, sino instanciarla.

Leeré sobre ActiveRecord y ActiveTable y veré qué puedo hacer para mejorar la clase, aunque estoy viendo por internet muchos detractores de su uso.

Gracias a los dos por contestar.
  #5 (permalink)  
Antiguo 15/11/2010, 09:47
Avatar de GatorV
$this->role('moderador');
 
Fecha de Ingreso: mayo-2006
Ubicación: /home/ams/
Mensajes: 38.567
Antigüedad: 18 años, 6 meses
Puntos: 2135
Respuesta: Dudas con POO: getters y setters con DB, arrays multidimensionales...

Claro es siempre mejor usar un ORM para mantener tus objetos lo más desacoplados de la Base de Datos y así es más transparente el uso, pero para proyectos pequeños yo prefiero usar ActiveRecord/Table para eso.

Saludos.
  #6 (permalink)  
Antiguo 16/11/2010, 01:12
 
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
  #7 (permalink)  
Antiguo 16/11/2010, 04:14
Avatar de masterpuppet
Software Craftsman
 
Fecha de Ingreso: enero-2008
Ubicación: Montevideo, Uruguay
Mensajes: 3.550
Antigüedad: 16 años, 10 meses
Puntos: 845
Respuesta: Dudas con POO: getters y setters con DB, arrays multidimensionales...

ORM es genial, pero agrega una capa de complejidad que no todo proyecto amerita.
Te invito a que le eches un ojo a Doctrine.

Zend 2 + Doctrine 2 = Priceless :)
  #8 (permalink)  
Antiguo 16/11/2010, 08:31
 
Fecha de Ingreso: junio-2009
Mensajes: 156
Antigüedad: 15 años, 6 meses
Puntos: 3
Respuesta: Dudas con POO: getters y setters con DB, arrays multidimensionales...

Cita:
Zend 2 + Doctrine 2 = Priceless :)
Hola, esto quiere decir que Doctrine 2, vendrá de forma nativa en ZF 2.0 ?

Si alguien me puede aclarar esto... porque no lo sabía.

Saludos.
  #9 (permalink)  
Antiguo 16/11/2010, 09:44
Avatar de GatorV
$this->role('moderador');
 
Fecha de Ingreso: mayo-2006
Ubicación: /home/ams/
Mensajes: 38.567
Antigüedad: 18 años, 6 meses
Puntos: 2135
Respuesta: Dudas con POO: getters y setters con DB, arrays multidimensionales...

No, pero se puede integrar fácilmente, hay varios sitios en internet donde te indican como acoplar Zend y Doctrine. Zend al ser un framework desacoplado te permite intercambiar componentes sin tener que hacer mucho esfuerzo.

Saludos.
  #10 (permalink)  
Antiguo 18/11/2010, 08:08
 
Fecha de Ingreso: junio-2009
Mensajes: 156
Antigüedad: 15 años, 6 meses
Puntos: 3
Respuesta: Dudas con POO: getters y setters con DB, arrays multidimensionales...

Hola, y pregunto: que ventaja tiene (si es que tiene) utilizar Doctrine sobre Zend_Db ?
Yo cuando trabajo con ZF, utilizo Zend_DB.

Saludos.
  #11 (permalink)  
Antiguo 18/11/2010, 09:03
Avatar de GatorV
$this->role('moderador');
 
Fecha de Ingreso: mayo-2006
Ubicación: /home/ams/
Mensajes: 38.567
Antigüedad: 18 años, 6 meses
Puntos: 2135
Respuesta: Dudas con POO: getters y setters con DB, arrays multidimensionales...

Zend_Db no es un ORM, ni le pisa los talones a un ORM, es un simple puente de acceso, entre tus tablas y para accesarlas de una forma orientada a objetos, pero es mejor usar un ORM como tal (para proyectos más grandes).

Saludos.

Etiquetas: arrays, poo
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta

SíEste tema le ha gustado a 1 personas




La zona horaria es GMT -6. Ahora son las 11:26.