Optimizando find y paginate en cakephp
Hay un dicho para programación en ingles, "do it simple" que es en lo que se basan los frameworks o al menos lo intentan.
La gran ventaja de cake (como framework) es que agiliza mucho el proceso de codificación mientras se trabaja con vistas, componentes y controladores.
Pero creo que hay algunas carencias en los modelos. Una de ellas
es el metodo "find".
Algo tan simple como crear una variable string con una SQL del tipo:
$sSQL="SELECT Company.id, Company.name,
Company.description, Company.location,
Company.created, Company.status, Company.size
FROM companies AS Company
WHERE
(
(Company.name = 'Future Holdings')
OR
(Company.name = 'Steel Mega Works')
)
AND
(
(Company.status = 'active')
OR(NOT (Company.'status' IN ('inactive', 'suspended')))
)";
para despues ser utilizada como argumento en el metodo "query()" y asi obtener un array ($arResultado) con estas condiciones
$arResutlado = $this->query($sSQL);
...
//aqui tratas $arResultado como desees
...
Se convierte en un proceso un poco complejo (si se desea recuperar con find()) como el siguiente:
//Se genera un array anidado de 5 niveles
$arCondicion = array(
'OR' => array(
array('Company.name' => 'Future Holdings'),
array('Company.name' => 'Steel Mega Works')
),
'AND' => array(
array(
'OR'=>array(
array('Company.status' => 'active'),
'NOT'=>array(
array('Company.status'=> array('inactive', 'suspended'))
)
)
)
)
);
$arResultado = $this->ModelName->find('all',$arCondicion);
Si lo que deseamos es paginar entonces ya no podemos recurrir a "query()" porque obligatoriamente se tiene que utilizar el metodo de controlador "paginate()"
$arItemsEnPagina=$this->paginate('ModelName',$arCondicion);
$this->set('arItemsEnPagina',$arItemsEnPagina);
En la vista
//Mostramos el listado
foreach($arItemsEnPagina as $arItem)
{
echo $arItem['ModelName']['ModelField'];
}
//Mostramos los botones de navegación
if($paginator->numbers())
{
echo $paginator->first('|<');
echo $paginator->prev('<<');
echo '<span> | </span>' ;
echo $paginator->numbers();
echo '<span> | </span>' ;
echo $paginator->next('>>');
echo $paginator->last('>|');
}
En el caso que el paginado se haga con datos devueltos por un único modelo (es decir, no relacionado) el proceso dentro de su complejidad es más simple.
Pero si intervienen otros modelos (relaciones con otras tablas) habria que crear todas las relaciones (binds) previamente, de lo contrario devolvera "cakeError" el codigo de los binds dependiendo de la cantidad de niveles relacionados (JOINS) puede hacer el codigo más dificil de entender.
Lo mejor para el paginado seria una clase tipo componente en cuyo constructor se le pase cualquier array cuyo primer nivel siempre sea un indice númerico y el numero de items por pagina a mostrar.
Algo como:
//Recupero cualquier tipo de dato indexado en primer nivel
//por un entero
$arDatosAPaginar = $this->ModelName->get_datos_x();
$oPaginator = new CPaginator($arDatosAPaginar,8);
$arItemsPorPagina = $oPaginator->get_items();
$arBotones = $oPaginator->get_botones();
$this->set('arItemsPorPagina',$arItemsPorPagina);
$this->set('arBotones',$arBotones);
Autor: Eduardo A. F.
Publicado: 17-04-2011 19:14
Actualizado: 02-07-2011 16:17