April 7th, 2008 Category: Zend Framework
23 Comments »
Con esta clase nosotros vamos a poder generar nuestras querys. Agregar todas las cláusulas que consideremos necesarias, de forma ordenada, y obteniendo algunas ventajas con respecto a la manera tradicional.
Hay dos formas de acceder a esta clase usando el método directamente de la clase abstracta Zend_Db_Adapter_Abstract
Ejemplo:
1
<?php
2 $db = Zend_Db::factory(...opciones...);
3 $select = $db->select();
4 ?>
O especificando el adaptador de la base de datos.
Ejemplo:
1
<?php
2 $db = Zend_Db::factory(...opciones...);
3 $select = new Zend_Db_Select($db);
4 ?>
Nosotros una vez creado la instancia de Zend_Db_Select, podemos ir agregando tantas cláusulas como necesitemos.
1
<?php
2 $select->select();
3 $select->from( 'tabla' );
4 $select->where( ' id=1 ' );
5 $select->order( 'nombre' );
6 ?>
Y de esta manera vamos a crear una query con la siguiente forma
SELECT * FROM tabla WHERE id=1 ORDER BY nombre
Nosotros podríamos optimizar este código usando interfaces fluidas.
Las interfaces fluidas tienen un método principal ( select() ), que va a recibir los mensajes de los métodos posteriores.
Si nuestro código anterior lo generamos usando interfaces fluidas nos quedaría de la siguiente forma.
1
<?php
2 $select->select()
3 ->from( 'tabla' )
4 ->where( ' id=1 ' )
5 ->order( 'nombre' );
6 ?>
hay casos donde no nos va a convenir usar la forma de interfaz fluida y vamos a usar la forma “no fluida”, y eso será cuando tengamos que validar algo antes, o ejecutar algo entre métodos.
Cláusula FROM
A veces necesitamos crear un alias a la tabla, un string que identifique a la tabla dentro de nuestra Query. Para hacerlo nosotros vamos a enviar los parámetros a from(), en forma de array.
Por ejemplo para decir que la tabla usuarios tiene el alias us.
1
<?php
2 $query = $db->select()
3 ->from( array('us' => 'usuarios') );
4 ?>
De esta manera nuestro select nos va a quedar de la siguiente forma
SELECT * FROM usuarios As us
Si nosotros al método from() no le especificamos que columna queremos que nos traiga, nos va a traer todas ( * ), pero si queremos especificar esto, vamos a enviarle los campos que queremos que nos muestre en un array, como segundo parámetro del from();
por ejemplo:
Si quisiéramos decirle al query, que nos devuelva solo el id, y el nombre del registro, tendríamos que crear el siguiente código
1
<?php
2 $select = $db->select()
3 ->from(array('us' => 'usuarios'),
4 array('id_usuario', 'nombre_usuario'));
5 ?>
O si a esos campos los tenemos que relacionar con el alias de la tabla nos quedaría de la siguiente forma
1
<?php
2 $select = $db->select()
3 ->from(array('us' => 'usuarios'),
4 array('us.id_usuario', 'us.nombre_usuario'));
5 ?>
O si además queremos agregarle alias a nuestros campos podemos hacerlo de la misma forma que lo hacíamos con la tabla
1
<?php
2 $select = $db->select()
3 ->from(array('us' => 'usuarios'),
4 array('id'=>'us.id_usuario', 'nombre'=>'us.nombre_usuario'));
5 ?>
Agregando más tablas a la consulta
Muchas veces necesitamos relacionar tablas usando los famosos JOIN, para hacerlo con Zend es realmente fácil, como todo con Zend
Si quisiéramos listar la cantidad de productos relacionado con un proveedor, la consulta tendría que ser así
1
<?php
2 $select = $db->select()
3 ->from(array('p1'=>'productos')
4 ->join(array('p2'=>'proveedores'),' p2.id_proveedor = p1.id_proveedor');
5 ?>
En el primer parámetro del join ingresamos la tabla a relacionar, y en el segundo parámetro la condición para relacionar esta tabla con la primera.
Existe un tercer parámetro y son la cantidad de columnas de la tabla que queremos listar y enviamos estos campos en una tabla de la misma forma que lo usamos en el from().
Inner Join método: join() joinInner().
Left Join método: joinLeft().
Rigth Join método: joinRight().
Full Join método joinFull().
Hay dos casos que no reciben los parámetros de la misma manera, son Cross Join, y Natural Join. Estos reciben en el primer parámetro la tabla, y en el segundo las columnas a listar.
Cross Join método: joinCross().
Natural Join método: joinNatural().
La cláusula WHERE.
La cláusula WHERE recibe dos parámetros el primero es la condición explicita, por ejemplo
1
<?php
2 $select = $db->select()
3 ->from('productos')
4 ->where( 'estado = 1' );
5 ?>
El segundo parámetro es una variable para el valor que puede estar ocultado por un símbolo de pregunta (?), esto se usa para usar como variable.
por ejemplo
1
<?php
2 $estado = 1;
3 $select = $db->select()
4 ->from('productos')
5 ->where( 'estado = ?', $estado )
6 ?>
El segundo parámetro va a reemplazar en la consulta al símbolo ‘?’.
Si nosotros quisiéramos agregar mas de una condición, tenemos dos opciones, en el primer parámetro agregar al string un AND u OR otra condición, o agregar otra llamada al método where()
por ejemplo
1
<?php
2 $hoy = date("Y-m-d");
3 $estado = 1;
4 $select = $db->select()
5 ->from('productos')
6 ->where( 'estado = ?', $estado )
7 ->where( 'fecha < ?', $hoy);
8 ?>
cada vez que agregamos un where(), el sistema lo transforma en un AND condición, si nosotros quisiéramos agregar una condición y que esta condición sea un OR, tendríamos que usar el método orWhere(), con las mismas características que el where().
por ejemplo
1
<?php
2 $hoy = date("Y-m-d");
3 $estado = 1;
4 $select = $db->select()
5 ->from('productos')
6 ->where( 'estado = ?', $estado )
7 ->orWhere( 'fecha < ?', $hoy);
8 ?>
Cláusula GROUP BY.
tendríamos que agregar tantos group(), como agrupamientos queramos por ejemplo
1
<?php
2 $select = $db->select()
3 ->from( 'productos' )
4 ->group( 'fecha' )
5 ?>
Cláusula HAVING.
Agregamos al select(), el método having, con la expresión que queramos. Por ejemplo
1
<?php
2 $select = $db->select()
3 ->from( 'productos', array( ‘precio’ )
4 ->group( 'fecha' )
5 ->having( ‘precio > 35’ )
6 ?>
También existe el método orHaving(), para que puedan agregar a la consulta.
Cláusula ORDER
Si nosotros queremos que los registros se ordenen por una o mas columnas tenemos que usar el método order() dentro de nuestro select().
Si nosotros quisiéramos ordenar primero en forma Descendente por precio, y despues en forma ascendente por Nombre, tendríamos el siguiente código.
1
<?php
2 $select = $db->select()
3 ->from( 'productos', array( ‘precio’ )
4 ->order(array( ‘precio DESC’, ‘nombre’ ));
5 ?>
Cláusula LIMIT
Si quisiéramos limitar la cantidad de registros vamos a usar el método limit(). Esta cláusula esta compuesto de dos parámetros, desde y cuantos. Si nosotros quisiéramos que nos traiga los primeros 10 registros tendríamos que decirle limit(1,10).
Otro ejemplo seria si necesitamos que nos traiga 10 registros a partir del registro 20, tendríamos que usar limit(20,10).
1
<?php
2 $select = $db->select()
3 ->from( 'productos' )
4 ->limit(20,10);
5 ?>
además nosotros tenemos la posibilidad de usar pageLimit(), que también consta de dos parámetros.
Cláusula DISTINCT
Solo distinct(), sin ningún parámetro por ejemplo
1
<?php
2 $select = $db->select()
3 ->distinct()
4 ->from( 'productos' )
5 ?>
Cláusula FOR UPDATE
Al igual que distinct(), no lleva parámetros
1
<?php
2 $select = $db->select()
3 ->forUpdate()
4 ->from( 'productos' )
5 ?>
Estas son todas los métodos que necesitamos para armar nuestros Quero.
Para ejecutarlos vamos a usar query(), y para mostrar todos los registros fetchaAll().
1
<?php
2 $select = $db->select()
3 ->from( ‘productos’ );
4 $sql = $db->query($select);
5 $rows = $sql->fetchAll();
6 ?>
Todo lo que tenga que ver con Base de datos siempre tenemos que ubicarlo dentro de nuestro modelo, no dentro del controlador o de la vista, siempre en el modelo.
Fuente Zend_Db_Select
Gracias Santiago por la definicion de Fluent Interface
Invitame una Cerverza
Comentar
23 Responses
creo que se te han pasado unos punto y coma(;) en los ejemplos de "Where"
...
->where('', '');
->where('', '');
...
class Productos extends Zend_Db_Table_Abstract
{
protected $_name = “productos”;
public function findAll()
{
$this->fetchAll( $this->select()->where( ‘estado = 0′ ));
}
}
protected $_name = “tabla_2”;
protected $_name = “tabla_3”;
Es asi?
Un abrazo
Puede ser que no necesites crear un modelo para una tabla, o puede ser que no necesites una tabla para un modelo.
Si vos tenes que hacer un inner join, con Zend_Db_Select. Tenes que agregar el nombre de la tabla. Con la que queres joinear (no existe este verbo, lo acabo de inventar).
pero te podes evitar el hecho de agregar el from
$this->select()->join(array('p'=>'proveedores'))
se entiende?
$this->select()->join(array(’p'=>’proveedores’))
esa clase, tengo que extenderla?, creo que no hace falta, que dicha clase no es un modelo.
Es asi?
Si tenes una clase que no es un modelo, o una funcion, o directamente un codigo suelto por ahi, no existe la necesidad, pero si vas a tener que que instanciar la clase Zend_Db, como esta en este articulo.
En el proximo post, voy a hacer una conexion a la base de datos, y un modelo de ejemplo, por ahi eso te ayude a entenderlo mejor.
Saludos.
Un abrazo.
Que en este caso el modelo se encarga de la logica de negocio.
Lo que pasa es que Zend_Db_Table no soporta Join.
Hay que utilizar unos trucos para poder hacer join entre varias tablas. Utilizo una clase modifica para ZF 1.5.x y >
de esta web :
http://www.assembla.com/spaces/riskle/documents
Y desde poco utilizo vista MySQL 5.
La ultima solución creo que la mejor pero lo que pasa es no muy practico gestionar las "vistas" con phpMyAdmin. Mejor utilizar programas como Navicat o algo así.
Si le interesa alguien le puede mandar estas clases.
Por otro lado, si vos queres traer los datos de TU tabla, y los joins, solo lo usas para filtrar, ahi es otro cantar, a partir de la version 1.5.x con solo llamar a setIntegrity(false), es suficiente para que te deje joinear, pero No podes traer dato de otras tablas simplemente porque rompe con el patron.
Tambien podes usar Zend_Db_Table_Relationships, para crear un modelo que se relacione con otros. Aca tenes un link de como usarlo
http://bolsadeideas.cl/zsamer/2008/08/implementar-orm-en-zend-framework-db-table/
En mi trabajo actual estamos usando varios ejemplos con este sistema, y anda bastante bien.
O sea no el formulario, sino, la parte de aceptacion de usuario e inclusion en la tabla, te pregunto pk quizas el framework ya tenga algo previsto para esto.
Gracias y disculpa la molestia.
yo tengo un problema, y es que tengo una consulta a una base de datos, pero quiero poder realizar la misma consulta a otras bases de datos, ese tema ya lo tengo medio controlado.
El problema es que las estructuras de las bases de datos son las mismas pero el nombre de las tablas que quiero consultar no (de echo es solo una tabla de cada base de datos).
Quiero poder modificar esa tabla (solo el nombre de la tabla) y que realize exactamente lo mismo (realmente es una modificacion de la pagina web para añadirle funcionalidaes).
Creo que podria hacer algo asi para seleccionar un nombre de tabla o otro dependiendo de la url que se ingrese.
protected function _setupTableName()
{
//dependiendo de la url elegimos
if url= *.com
$this->_name = 'table1';
parent::_setupTableName();
elseif url = *.fr
$this->_name = 'table2';
parent::_setupTableName();
}
Como podria hacer el select? yo lo tengo asi actualmente:
public function getLastQueryErrorsByHour($date,$date_next,$hour){
$select = " select EXTRACT(HOUR from temp.fecha) as hora, count(*) as total
from (
select *
from table1
where fecha between '".$date."' AND ".$date_next."'
and root_cause like 'coldfusion.runtime.RequestTimedOutException%'
) as temp
group by hora
order by 1;";
$stmt =$this->_db->query($select);
$result = $stmt->fetchAll();
return $result;
}
Me podrias dar la alternativa con los select() ->from()->where() ??
donde la tabla es la anterior seleccionada con el if? Porque no se hacerlo.
Gracias.
Si la tabla tiene otro nombre lo mejor seria usar otro modelo.
Igual. Lo que estas haciendo es bastante rebuscado.
Lo mas optimo es renombrar una de las dos tablas, asi te evitas el problema
el codigo es asi:
select *
from table
where fecha between '".$date."' AND ".$date1."' ;
como trabajar con between en zend?
esta consulta como seria en Zend_Db_Select o Db_Table?
->where(' fecha between '".$date."' AND ".$date1." ') ;



salu2