jueves, 28 de agosto de 2008

Usar condiciones al definir asociaciones de modelos

En todo el tiempo que llevo usando CakePHP nunca había probado hasta hoy el introducir condiciones en las relaciones entre Models. Es decir, al definir una relación (del tipo que sea) podemos poner condiciones que ha de cumplir el Model relacionado.

De este modo puedes tener dos Modelos relacionados de distintas formas y obtener datos de un modo incluso más fácil que pasando condiciones a un método find. Aunque no he explorado ni mucho menos las posibilidades de esta forma de trabajar, me voy a permitir poner un ejemplo útil de cómo funciona.

Supongamos dos modelos Autor y Post, de modo que Author hasMany Post (y Post belongsTo Author). Ahora supongamos también que Post tiene un campo published para indicar el estado de publicación del Post.

La relación "normal" en Author la definiríamos (minimalísticamente si seguimos todas las convenciones de CakePHP) como:

var $hasMany = array('Post')


Pero ahora, supongamos que nos interesa poder acceder a todos los Post de Author que estén publicados. De acuerdo, podríamos utilizar un find, pero ¿y si definimos una relación basada en esa condición?

'PostPublished' => array(
'className' => 'Post',
'joinTable' => 'posts_authors',
'foreignKey' => 'author_id',
'associationForeignKey' => 'post_id',
'conditions' => 'Posts.published = 1',
)


Pues lo que ocurre es que al hacer una búsqueda de Author, nos devolverá registros relacionados tanto en Post, como en PostPublished. En este caso, todos los Post y todos los Post publicados. En cierto modo, PostPublished es un modelo relacionado "virtual" que podemos manejar igual que uno definido realmente.

En este caso, debemos especificar las claves de la relación para asegurarnos de que se establece correctamente, ya que el nombre de la misma no respeta las convenciones.

(Nota: un uso de esta técnica es una típica página "home" de usuario, en la que mostremos todos sus objetos que cumplan cierta condición. Por ejemplo, tareas pendientes, posts sin publicar, etc.)

Combinado con bindModel y unbindModel o el Containable behavior (para restringir las relaciones y optimizar las query) puedes recabar con facilidad datos sin necesidad de recurrir a condiciones de búsqueda triviales o incluso complejas si las intentamos hacer en asociaciones habtm.

Precisamente ahora estoy estudiando un caso en el que las condiciones de búsqueda resultan bastante complicadas de establecer y los resultados no son los deseados y parece que aplicando esta idea, el problema podría quedar fácilmente resuelto. Ya contaré qué tal me va.

3 comentarios:

Unknown dijo...

Buenas tengo una duda como puedo hacer en cakephp para que me reconozca una llave foranea sin seguir las convenciones de llaveforanea_id?, lo tengo hecho pero no me lista cuando el campo tiene un nombre distinto a la llave foranea estandar.

Mil Gracias

Fran Iglesias dijo...

Hola,

en general puedes hacerlo al definir las propiedades de las asociaciones, poniendo una clave foreignKey para indicar qué campo del modelo es la llave foránea. Puedes ver esto en detalle en el manual

Asociaciones

Unknown dijo...

Hola muchisimas gracias por contestar, pero me gustaria ver algun ejemplo porque le hago de todo y nada que coge la llave foranea con la tabla que deberia, paso los links de las imagenes
http://img546.imageshack.us/img546/8426/municmodel.png
http://img832.imageshack.us/img832/3340/entimodel.png
http://img408.imageshack.us/img408/8151/entidadcontroller.png
http://img708.imageshack.us/img708/6228/cakephp1.png

Muchisimas Gracias.