martes, 19 de abril de 2011

Custom Find DRY

Una de las cosas que más me gusta de los custom find en CakePHP es la flexibilidad que pueden proporcionar a partir de una sintaxis única y sencilla.

Recientemente me he dado cuenta de cómo usarlos para evitar duplicaciones innecesarias de código.

Como ya sabrás, un método para custom find tiene esta signatura básica:

function _findCustom($state, $query, $results = array())
Este método se llamaría públicamente así

$model->find('custom' [, $options]);

La llamada $model->find('custom') hace, a grandes rasgos, lo siguiente:

  1. Normaliza las opciones que se han pasado para crear un array, que contiene los datos necesarios para generar la query que se hará a la base de datos.
  2. Llama a _findCustom para incluir las modificaciones que éste método haga en la query.
  3. Convierte la query en SQL y obtiene el resultado de la base de datos
  4. Llama una segunda vez a _findCustom para procesar el array de resultados.

Lo interesante es que nada nos impide llamar desde otros métodos del modelo a _findCustom pasándole el parámetro $state (que puede ser 'before' o 'after', según queremos obtener el resultado de la modificación de $query o de $results, respectivamente.

¿Para qué sirve? Supongamos que tenemos un _findCustom más o menos complejo en el que especificamos varios joins, conditions, etc, para un cierto tipo de búsqueda. Supongamos también que necesitamos hacer un cierto número de variantes de esa búsqueda, cambiando tan sólo algunas condiciones.

Pues bien, en ese caso podríamos llamar internamente desde nuestro segundo método _find a _findCustom con los parámetros extra para que genere el query (o bien, obtener el query y luego modificarlo). Por ejemplo:

function _findVariant($state, $query, $array()) {
    if ($state === 'before') {
         $extraQuery = array('conditions' => array('field' => 'value'));
         $query = Set::merge($query, $extraQuery);
         $query = $this->_findCustom('before', $query);
    }
    return $results;
}