¿Cómo escribo una consulta de combinación en varias tablas en CakePHP?

¿Puede alguien decirme cómo recuperar el resultado unido de múltiples tablas en cakePHP (usando la architecture cakePHP mvc)? Por ejemplo, tengo tres tablas para unir (tbl_topics, tbl_items, tbl_votes. Su relación se define de la siguiente manera: un tema puede tener muchos elementos y un elemento puede tener muchos votos. Ahora quiero recuperar una lista de temas con el recuento de todos los votos en todos los artículos para cada tema. La consulta SQL para esto se escribe a continuación:

SELECT Topic.*, count(Vote.id) voteCount FROM tbl_topics AS Topic LEFT OUTER JOIN tbl_items AS Item ON (Topic.id = Item.topic_id) LEFT OUTER JOIN tbl_votes AS Vote ON (Item.id = Vote.item_id); 

Mi problema es que puedo hacerlo fácilmente usando la función de consulta $this->->query , pero esto requiere que se escriba código sql en el controlador que no quiero. Estoy tratando de encontrar otra forma de hacerlo (como find() ).

 $markers = $this->Marker->find('all', array('joins' => array( array( 'table' => 'markers_tags', 'alias' => 'MarkersTag', 'type' => 'inner', 'foreignKey' => false, 'conditions'=> array('MarkersTag.marker_id = Marker.id') ), array( 'table' => 'tags', 'alias' => 'Tag', 'type' => 'inner', 'foreignKey' => false, 'conditions'=> array( 'Tag.id = MarkersTag.tag_id', 'Tag.tag' => explode(' ', $this->params['url']['q']) ) ) ))); 

como se menciona en el artículo de nate abele: texto del enlace

Seré honesto aquí y diré que probablemente sea mucho más feliz si solo crea una función en su modelo, algo así como getTopicVotes () y llamando a query () allí. Cualquier otra solución en la que pueda pensar solo la hará más complicada y, por lo tanto, más fea.

Editar:

Dependiendo del tamaño de sus datos, y suponiendo que haya configurado correctamente sus relaciones modelo (tema tiene muchos elementos tiene muchos votos), podría hacer un simple hallazgo (‘todos’) que contenga todos los elementos y votos, y luego hacer algo como esta:

 foreach ($this->data as &$topic) { $votes = Set::extract('/Topic/Item/Vote', $topic); $topic['Topic']['vote_count'] = count($votes); } 

Dos cosas son importantes aquí:

  1. Si tiene muchos datos, probablemente debería olvidarse de este enfoque, será lento como el infierno.
  2. He escrito esto de mi memoria y puede que no se vea así en la vida real y / o puede que no funcione en absoluto 🙂

Puede establecer fácilmente la propiedad “recursiva” en una consulta find ().

 $result = $this->Topic->find('all', array('recursive' => 2)); 

Alternativamente, puede usar el comportamiento Containable en su modelo. Entonces puedes usar:

 $this->Topic->contain(array( 'Item', 'Item.Vote', )); $result = $this->Topic->find('all'); 

o

 $result = $this->Topic->find('all', array( 'contain' => array( 'Item', 'Item.Vote', ), )); 

Lo que necesita es compatibilidad con asociaciones recursivas, lo que no es posible con stock de CakePHP actualmente.
Aunque podría lograrse usando algún truco bindModel
o un comportamiento experimental de asociación recursiva .

Ambas soluciones requerirán que uses código adicional o que confíes en un comportamiento en tu aplicación, pero si te resistes a la tentación de escribir código SQL puro, serás recompensado con la posibilidad de utilizar la paginación de Cake, las condiciones de auto, modelo de magia, etc.