Hasta ahora, en el desarrollo de aplicaciones web nos hemos encontrado siempre con el problema de la cantidad de datos que genera CakePHP en las consultas a los modelos.
En nuestros desarrollos siempre definimos las relaciones en los modelos y al hacer consultas find tenemos el problema de que un nivel de recursividad demasiado elevado nos genera demasiada información, ralentizando la ejecución debido a los joins generados, y un nivel inferior no alcanza para obtener las relaciones que deseamos utilizar. Además, en ocasiones, queremos obtener únicamente un modelo de entre todas las relaciones que componen una determinada entidad.
Esto nos llevaba a tener que utilizar llamadas a la función unbind (o bind, si es el caso) del modelo al vuelo, previamente a la utilización de un find, o bien a tener que dividir la consulta en dos llamadas anidadas en un bucle, reduciendo el nivel de recursividad en ambas. La primera de las soluciones quizás complica excesivamente el desarrollo y la segunda reduce el rendimiento de la aplicación.
El Containable Behavior de CakePHP nos resuelve este problema, ya que nos permite filtrar y limitar los modelos que generan las consultas a los modelos, mejorando el rendimiento de la aplicación con un sencillo modo de empleo.
Para utilizar este comportamiento lo primero que tendremos que hacer es definirlo en el modelo, ya sea utilizando la variable $actAs en la clase modelo, o bien, definiéndolo al vuelo en el controlador:
- En el modelo:
class Noticia extends AppModel { var $actsAs = array('Containable'); } - En el controlador:
$this->Noticia->Behaviors->attach('Containable');
Una vez definido el comportamiento, ya podemos utilizarlo.
Si queremos utilizar un find sin recursividad, es decir:
$this->Noticia->recursive = -1;
$this->Noticia->find('all');
// o bien: $this->Noticia->find('all', array('recursive' => -1));
podríamos utilizar lo siguiente:
$this->Noticia->find('all', array('contain' => false));
o bien, utilizando la siguiente sintaxis:
$this->Noticia->contain();
$this->Noticia->find('all');
A continuación veremos un ejemplo con múltiples opciones de utilización:
/**
* Usuario->Perfil
* Usuario->Cuenta->ResumenCuenta
* Usuario->Noticia->AdjuntoNoticia->HistorialAdjuntoNoticia->NotasHistorial
* Usuario->Noticia->Tag
*/
$this->Usuario->find('all', array(
'contain'=>array(
'Perfil',
'Cuenta' => array(
'ResumenCuenta'
),
'Noticia' => array(
'AdjuntoNoticia' => array(
'fields' => array('id', 'nombre'),
'HistorialAdjuntoNoticia' => array(
'NotasHistorial' => array(
'fields' => array('id', 'nota')
)
)
),
'Tag' => array(
'conditions' => array('Tag.nombre LIKE' => '%feliz%')
)
)
)
));
Utilizando esta configuración obtendremos todos los campos de los modelos Usuario, Perfil, Cuenta y ResumenCuenta; y también las Noticias, aunque de los Adjuntos y su Historial únicamente los campos id y nombre. Y, por último, aquellos Tags que incluyan en su nombre la cadena “feliz”. Las demás relaciones del modelo, si las tuviera, no serían resultado de la búsqueda si no se especifican explícitamente.
Es importante tener en cuenta que incluir una condición a este nivel (por ejemplo, al nivel de Tag) sólo afecta al modelo en el que se ha introducido. Por lo tanto, los usuarios seguirán mostrándose igual aunque el array de Tags esté vacío. Se podrían incluir condiciones al find por el procedimiento común para filtrar elementos, aunque deberemos tener en cuenta la recursividad del find, en el caso de que ésta se establezca, pues incluir un modelo en la variable contain no implica que se pueda establecer condiciones a ese nivel si la recursividad no llega hasta él. Además, debemos tener en cuenta que si no establecemos una recursividad adecuada, no podremos llegar a la obtención de los modelos establecidos. Es recomendable no especificar ningún nivel de recursividad al utilizar este behavior.
En el caso de consultas paginadas, se utilizará la variable contain dentro de la función paginate al igual que hemos hecho en el find.
Existen algunas opciones de configuración del comportamiento, que pueden consultarse en el cookbook, documento del que se ha obtenido la información para la publicación de este post.

La Cake Software Foundation, nos sorprende con un nuevo producto pensado para ayudar a toda la comunidad de su framework.
