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

PHP OO Duda con ORM casero

Estas en el tema de Duda con ORM casero en el foro de Frameworks y PHP orientado a objetos en Foros del Web. Hola, Estoy intentando crear un ORM sencillo para mi framework, para eso me he guiado en el tutorial de GatorV http://web2development.blogspot.com/...iverecord.html y revisando el código ...
  #1 (permalink)  
Antiguo 13/04/2011, 12:05
Avatar de destor77  
Fecha de Ingreso: noviembre-2004
Ubicación: Gálvez, Santa Fe, Argentina
Mensajes: 2.654
Antigüedad: 19 años, 5 meses
Puntos: 43
Duda con ORM casero

Hola,
Estoy intentando crear un ORM sencillo para mi framework, para eso me he guiado en el tutorial de GatorV
http://web2development.blogspot.com/...iverecord.html

y revisando el código de otros frameworks que he usado. Bien como resultado he obtenido esto:
Código PHP:
Ver original
  1. abstract class Modelo {
  2.     protected $table;
  3.     protected $keyField;
  4.     protected $db;
  5.     protected $fields = array();
  6.     private $_columns;
  7.     private $Config;
  8.     private $seteados = 0;
  9.     public $error = '';
  10.  
  11.     public function __construct() {
  12.         $this->db = Database::singleton();
  13.         $this->iniciar();
  14.  
  15.     }
  16.  
  17.  
  18.     protected function iniciar() {
  19.         //si no hay seteada una tabla corto el proceso y muestro el error.
  20.         $this->Config = Config::singleton();
  21.         if( !$this->table ) {
  22.             error_log("[".date("F j, Y, G:i")."] [E_USER_NOTICE] [tipo Modelo] No se seteo ninguna tabla para el modidelo: ".get_class($this)."\n", 3,$this->Config->get('root').'/errores.log');
  23.             die('No se seteo ninguna tabla para el modelo: '.get_class($this));
  24.         }
  25.  
  26.         //obtengo los campos de la tabl
  27.         $query = "SHOW FIELDS FROM ".$this->table;
  28.         $command = $this->db->QueryArray($query);
  29.  
  30.         $fields = array();
  31.         $primary = '';
  32.  
  33.         //recorro los campos y los guardo en un arrgeglo
  34.         for($i=0;$i<count($command);$i++) {
  35.             $fields[$command[$i]['Field']] = array(
  36.                     "name" => $command[$i]['Field'],
  37.                     "type" => $command[$i]['Type'],
  38.                     "defaultValue" => $command[$i]['Default'],
  39.                     "key" => $command[$i]['Key'],
  40.             );
  41.             //obtengo  la clave primaria
  42.             if( $command[$i]['Key'] === "PRI" ) {
  43.                 $primary = $command[$i]['Field'];
  44.             }
  45.             $this->fields[$command[$i]['Field']] = '';
  46.         }
  47.  
  48.         $this->_columns = $fields;
  49.  
  50.         if( empty( $primary ) ) {
  51.             throw new Exception( "No se encontro la columna clave para la tabla: " . $this->table );
  52.         }
  53.  
  54.         $this->keyField = $primary;
  55.     }
  56.  
  57.  
  58.     public function info() {
  59.         return array(
  60.                 "name" => $this->table,
  61.                 "columns" => $this->_columns,
  62.                 "primary" => $this->keyField,
  63.         );
  64.     }
  65.  
  66.  
  67.     public function traerClavePrimaria() {
  68.         return $this->keyField;
  69.     }
  70.  
  71.  
  72.  
  73.     public function buscarPorPk($id) {
  74.         //valido si el parametro es una arreglo o no
  75.         if(is_array($id)) {
  76.             $valor = $id[$this->keyField];
  77.         }
  78.         else {
  79.             $valor = $id;
  80.         }
  81.  
  82.         $sql = "SELECT * FROM `%s` WHERE `%s`='%s' LIMIT 1";
  83.         $sql = sprintf($sql, $this->table, $this->keyField, $valor);
  84.         $consulta=$this->db->QuerySingleRowArray($sql);
  85.         if(!$consulta) {
  86.             $consulta=$this->db->Error();
  87.         }
  88.         foreach ($consulta as $key => $value) {
  89.             if(!is_numeric($key)) {
  90.                 $this->$key = $value;
  91.                 $this->fields[$key] = $value;
  92.             }
  93.         }
  94.  
  95.         return $this;
  96.     }
  97.  
  98.  
  99.     public function buscarTodos() {
  100.         $sql = "SELECT * FROM ".$this->table;
  101.         $consulta = $this->db->QueryArray($sql);
  102.         if(!$consulta) {
  103.             $this->error = $this->db->Error();
  104.         }
  105.         return $consulta;
  106.     }
  107.  
  108.  
  109.     public function nuevo($valores) {
  110.         $vacio = 0;
  111.         //recorro los valores enviados y los voy asignando a los campos del registro
  112.         foreach ($valores as $key => $val) {
  113.             if(empty ($val) && $key != $this->keyField) {
  114.                 $vacio++;
  115.             }
  116.             $insertar[$key] = "'".trim($val)."'";
  117.         }
  118.  
  119.         if($vacio == count($this->fields)) {
  120.             $this->error = "Todos los campos estan vacios o los campos no existe en la tabla.<br/>";
  121.             return false;
  122.         }
  123.         else {
  124.             $consulta = $this->db->InsertRow($this->table, $insertar);
  125.             if(!$consulta) {
  126.                 return false;
  127.                 $this->error = $this->db->Error();
  128.             }
  129.             else {
  130.                 //$consulta = $this->db->GetLastInsertID();
  131.                 return true;
  132.             }
  133.         }
  134.  
  135.     }
  136.  
  137.  
  138.     public function actualizar($valores) {
  139.         $vacio = 0;
  140.         //recorro los valores enviados y los voy asignando a los campos del registro
  141.         foreach ($valores as $key => $val) {
  142.             //valido si el campo existe en la tabla
  143.             if($key === $this->keyField) {
  144.                 $filtro[$this->keyField] = $val;
  145.             }
  146.             if(empty ($val)) {
  147.                 $vacio++;
  148.             }
  149.             $actualizar[$key] = "'".trim($val)."'";
  150.         }
  151.  
  152.         if($vacio == count($this->fields)) {
  153.             $this->error = "Todos los campos estan vacios o los campos no existe en la tabla.<br/>";
  154.             return false;
  155.         }
  156.         else {
  157.             //actualizo el registro
  158.             $consulta = $this->db->UpdateRows($this->table, $actualizar, $filtro);
  159.             if(!$consulta) {
  160.                 $this->error = $this->db->Error();
  161.                 return false;
  162.             }
  163.             else {
  164.                 return true;
  165.             }
  166.         }
  167.     }
  168.  
  169.     public function guardar() {
  170.         //valido si se seteadon los campos automaticamente.
  171.         // si no estan seteados es porque se hizo a mano desde el controlador
  172.         if(!$this->seteados) {
  173.             //recorro los campos y voy asignando los valores
  174.             foreach ($this->fields as $key => $value) {
  175.                 $this->fields[$key] = $this->$key;
  176.             }
  177.         }
  178.  
  179.         // valido si en los campos seteados esta la clave primaria par saber si es
  180.         // una actualizacion o un nuevo registro
  181.         if(empty($this->fields[$this->keyField])) {
  182.             return $this->nuevo($this->fields);
  183.         }
  184.         else {
  185.             return $this->actualizar($this->fields);
  186.         }
  187.     }
  188.  
  189.  
  190.     public function setearCampos($data) {
  191.         //Recorro el arreglo y lo asigno a los campos del registro
  192.         foreach ($data as $key => $value) {
  193.             //valido si existe la clave en el arreglo de los campos y lo asigno al campo
  194.             if(array_key_exists($key, $this->fields)) {
  195.                 $this->fields[$key] = $value;
  196.             }
  197.             //valido si existe la clave primaria en el arreglo si no existe la seteo en vacio.
  198.             if(!array_key_exists($this->keyField, $data)) {
  199.                 $this->fields[$this->keyField] = '';
  200.             }
  201.         }
  202.         //cambio el estado de la bandera seteados
  203.         $this->seteados = 1;
  204.     }
  205.  
  206.  
  207.     public function borrarPorPk($id) {
  208.         $filtro[$this->keyField] = $id;
  209.         $consulta = $this->db->DeleteRows($this->table, $filtro);
  210.  
  211.         if(!$consulta) {
  212.             $this->error = $this->db->Error();
  213.             return false;
  214.         }
  215.         else {
  216.             return true;
  217.         }
  218.  
  219.     }
  220.  
  221.  
  222.     public function borrarTodo() {
  223.         $consulta = $this->db->TruncateTable($this->table);
  224.         if(!$consulta) {
  225.             $this->error = $this->db->Error();
  226.             return false;
  227.         }
  228.         else {
  229.             return true;
  230.         }
  231.  
  232.     }
  233. }

entonces para usarlo en mi modelo hago algo asi:
Código PHP:
Ver original
  1. class usuario extends Modelo{
  2. protected $table = 'usuarios';
  3. }

y en mi controlador puedo hacer esto:
Código PHP:
Ver original
  1. //cargo el modelo
  2. $this->modelo('usuarios');
  3.  
  4. $this->usuarios->nombre = 'juan';
  5. $this->usuarios->apellido= 'perez';
  6. $this->usuarios->edad= '25';
  7. $this->usuarios->guardar();

o si los datos vienen por get/post puedo usar esto:
Código PHP:
Ver original
  1. //cargo el modelo
  2. $this->modelo('usuarios');
  3.  
  4. $this->usuarios->setearCampos($_REQUEST);
  5. $this->usuarios->guardar();

Hasta ahí todo de maravilla, el problema lo tengo cuando en mi tabla hay 2 claves primarias (los programas para diseñar base de datos, cuando tienes una campo que es una clave foranea de otra tabla, lo ponen como clave primaria), siempre me toma la segunda clave en vez de la primera. Como puedo evitar esto, sin necesidad de eliminar las claves de más que tengo?
Desde ya muchas gracias
  #2 (permalink)  
Antiguo 13/04/2011, 12:32
Avatar de masterpuppet
Software Craftsman
 
Fecha de Ingreso: enero-2008
Ubicación: Montevideo, Uruguay
Mensajes: 3.550
Antigüedad: 16 años, 3 meses
Puntos: 845
Respuesta: Duda con ORM casero

Que tal destor77,

No entiendo bien el problema que tenes, pero si el software que estas utilizando para diseñar la bbdd te esta creando claves compuestas con las que son foraneas, directamente no utilices el programa, me podrías decir cual es ?, y el problema cual es exactamente ? le queres agregar soporte para claves compuestas a tu AR ?

Fuera de todo esto, a no ser que tus modelos sean simples y las relaciones sean muy básicas, te sugiero que utilices Doctrine, crear un ORM, no es una tarea simple es algo muy complejo.

Saludos.
__________________
http://es.phptherightway.com/
thats us riders :)
  #3 (permalink)  
Antiguo 13/04/2011, 16:49
 
Fecha de Ingreso: diciembre-2007
Mensajes: 178
Antigüedad: 16 años, 3 meses
Puntos: 1
Respuesta: Duda con ORM casero

Una consulta masterpuppet:

Doctrine se puede utilizar en cualquier proyecto?
  #4 (permalink)  
Antiguo 14/04/2011, 07:36
Avatar de masterpuppet
Software Craftsman
 
Fecha de Ingreso: enero-2008
Ubicación: Montevideo, Uruguay
Mensajes: 3.550
Antigüedad: 16 años, 3 meses
Puntos: 845
Respuesta: Duda con ORM casero

Que tal grey,

Doctrine se puede utilizar standalone, tiene dependencias con partes especificas de Symfony(Console - Yaml) pero ya vienen en el paquete que descargas, así que lo puedes utilizar en cualquier proyecto, teniendo siempre en cuenta que las versiones 1.x corren sobre PHP 5.2.3+ y las 2.x sobre PHP 5.3+

Saludos.
__________________
http://es.phptherightway.com/
thats us riders :)
  #5 (permalink)  
Antiguo 14/04/2011, 08:48
Avatar de destor77  
Fecha de Ingreso: noviembre-2004
Ubicación: Gálvez, Santa Fe, Argentina
Mensajes: 2.654
Antigüedad: 19 años, 5 meses
Puntos: 43
Respuesta: Duda con ORM casero

Cita:
Iniciado por masterpuppet Ver Mensaje
Que tal destor77,

No entiendo bien el problema que tenes, pero si el software que estas utilizando para diseñar la bbdd te esta creando claves compuestas con las que son foraneas, directamente no utilices el programa, me podrías decir cual es ? y el problema cual es exactamente ?
Como dije arriba el problema lo tengo cuando en mi tabla hay mas de una clave primaria. Yo uso MySQL Workbench 5.2 CE para el diseño de las base de datos. Y cuando hago una relacion de 1:N entre dos tablas, donde esta la clave foránea me pone 2 claves primarias por ejemplo si yo armo una relacion entre 2 tablas así:




y despues cuando lo exporto a phpmyadmin me queda así:




como verás me crea dos claves primaría y mi clase siempre me toma la segunda, en caso de tener mas claves me toma siempre la última.

Cita:
Iniciado por masterpuppet Ver Mensaje
le queres agregar soporte para claves compuestas a tu AR ?
si la idea es que pueda soportar claves compuesta y que pueda identificar cual es la mas importante, por ejemplo un id autoincremental respecto de otra clave.

Cita:
Iniciado por masterpuppet Ver Mensaje
Fuera de todo esto, a no ser que tus modelos sean simples y las relaciones sean muy básicas, te sugiero que utilices Doctrine, crear un ORM, no es una tarea simple es algo muy complejo.
Analicé de usar doctine, pero no me gusto para nada eso de tener que andar seteando los campos de la tabla en la clase. En http://www.doctrine-project.org/proj...n-to-models/en los ejemplos que muestra hay que crear al menos 3 clases por tabla. Si bien no busco competir con doctrine jajaja, lo que busco es ahorrar tiempo de codificación/configuración.
Y si por el momento mis tablas y relaciones son muy basica, a lo sumo relaciones entre 2 a 4 tablas como mucho.

Saludos
  #6 (permalink)  
Antiguo 14/04/2011, 12:24
Avatar de masterpuppet
Software Craftsman
 
Fecha de Ingreso: enero-2008
Ubicación: Montevideo, Uruguay
Mensajes: 3.550
Antigüedad: 16 años, 3 meses
Puntos: 845
Respuesta: Duda con ORM casero

Cita:
Como dije arriba el problema lo tengo cuando en mi tabla hay mas de una clave primaria. Yo uso MySQL Workbench 5.2 CE para el diseño de las base de datos. Y cuando hago una relacion de 1:N entre dos tablas, donde esta la clave foránea me pone 2 claves primarias por ejemplo si yo armo una relacion entre 2 tablas así:
Me parece que es un error de concepto, estas creando una relación 1:N identifying cuando no lo debería ser, un producto no depende de una categoría para existir, la relación debería ser 1:N non-identifying, las claves foráneas te las representa con un rombo en rojo(al menos era así).

Cita:
si la idea es que pueda soportar claves compuesta y que pueda identificar cual es la mas importante, por ejemplo un id autoincremental respecto de otra clave.
Suerte con esto destor77, hay ORM's que no lo soportan y simplemente te obligan a tener siempre una clave primaria no compuesta, te sugiero este camino, si lo que vas a hacer es simple.

Cita:
Analicé de usar doctine, pero no me gusto para nada eso de tener que andar seteando los campos de la tabla en la clase. En http://www.doctrine-project.org/proj...n-to-models/en los ejemplos que muestra hay que crear al menos 3 clases por tabla. Si bien no busco competir con doctrine jajaja, lo que busco es ahorrar tiempo de codificación/configuración.
Y si por el momento mis tablas y relaciones son muy basica, a lo sumo relaciones entre 2 a 4 tablas como mucho.
Es un ejemplo de como se implementa, en la realidad no se hace a mano, se utiliza YML, tanto para los modelos como para los fixtures(datos de prueba) y por medio de la consola se generan tanto las entidades como la bbdd, es mas había un plugin para el workbench que te hacia el export para Doctrine generandote el YML, te sugiero que lo mires con detenimiento.

Saludos.
__________________
http://es.phptherightway.com/
thats us riders :)

Última edición por masterpuppet; 14/04/2011 a las 12:46
  #7 (permalink)  
Antiguo 15/04/2011, 07:36
 
Fecha de Ingreso: diciembre-2009
Ubicación: Misiones
Mensajes: 867
Antigüedad: 14 años, 4 meses
Puntos: 65
Respuesta: Duda con ORM casero

han usado esta libreria? http://www.phpactiverecord.org/
  #8 (permalink)  
Antiguo 15/04/2011, 09:20
Avatar de masterpuppet
Software Craftsman
 
Fecha de Ingreso: enero-2008
Ubicación: Montevideo, Uruguay
Mensajes: 3.550
Antigüedad: 16 años, 3 meses
Puntos: 845
Respuesta: Duda con ORM casero

Que tal Dany_s,

no la he utilizado, pero hay que tener un par de cosas en cuenta, corre sobre PHP 5.3+, y utiliza AR, mi sugerencia es, que a no ser que quieras por alguna razón especifica el AR, utilices Doctrine 2, la joya de los ORM's para PHP.

Saludos.
__________________
http://es.phptherightway.com/
thats us riders :)
  #9 (permalink)  
Antiguo 19/04/2011, 07:14
Avatar de Triby
Mod on free time
 
Fecha de Ingreso: agosto-2008
Ubicación: $MX->Gto['León'];
Mensajes: 10.106
Antigüedad: 15 años, 8 meses
Puntos: 2237
Respuesta: Duda con ORM casero

destor77, no se si todavia sigues trabajando con esto o estas cambiando a un ORM como doctrine o similar, pero a ver si puedo aportar algo:

Sugerencia 1: Detecta clave primaria por propiedad auto_increment
Código PHP:
Ver original
  1. //obtengo  la clave primaria
  2.             if( $command[$i]['Extra'] === "auto_increment" ) {
  3.                 $primary = $command[$i]['Field'];
  4.             }

Sugerencia 2: Permite establecer directamente la clave primaria
Código PHP:
Ver original
  1. // Por medio de una funcion
  2. public function ponerPrimaria($keyField) {
  3.         $this->keyField = $keyField;
  4. }
  5.  
  6. // Definiendolo desde la clase
  7. class usuario extends Modelo{
  8.     protected $table = 'usuarios';
  9.     protected $keyField = 'id';
  10.  
  11. }

Pero esto es poco flexible, porque imagino que habra alguna tabla que no requiera un campo auto incrementable y que ademas tenga la clave primaria se componga de dos o mas campos.

Como ejemplo, yo uso una tabla de configuracion de 3 campos:
cfg_module
cfg_variable
cfg_value
Clave primaria: cfg_module, cfg_variable

Supongo que tendrias que considerar que $this->keyField pueda ser array('campo1', 'campo2', ... 'campoN').

Aparte, si cada que se abre una pagina de tu sitio se va a realizar una consulta por cada tabla para extraer los campos, hay la posibilidad de que cuando tengas muchos visitantes se sature el servidor de bases de datos.

P.D. Justo estoy trabajando en una clase que me permita mantener por separado todas las consultas SQL, de forma que si cambio de MySQL a otro motor, solo tenga que copiar y adaptar este archivo. Curiosamente, lo que hice es muy similar a lo tuyo... pero no copie!!!
__________________
- León, Guanajuato
- GV-Foto

Etiquetas: casero, orm
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




La zona horaria es GMT -6. Ahora son las 15:03.