2009-11-17 15 views
9

Tengo algunos problemas con el método y las condiciones de findPHPS de CakePHP en asociaciones de modelos "más profundos". Hay algunos de estos alrededor, pero no pude encontrar una respuesta a esto hasta ahora.Condiciones en los modelos asociados que usan Model-> find() (CakePHP)

Mis asociaciones de modelo son User hasMany Post hasMany Comment hasMany Vote y Vote belongsTo Comment belongsTo Post belongsTo User respectivamente. Las asociaciones belongsTo usan combinaciones internas ('type' => 'INNER').

¿Cómo puedo encontrar todos los votos de los comentarios de un usuario específico con el método de modelo de CakePHP-> find()?

Utilicé deliberadamente una cadena de cuatro modelos, porque esto parece funcionar para las condiciones de los modelos directamente asociados. Por lo tanto, no es necesario utilizar la columna de retención de clave externa en la tabla vecina (condición 'Post.user_id == 1' en lugar de 'User.id == 1').

En SQL sería:

SELECT v.* 
FROM votes v 
    JOIN comments c ON (v.comment_id = c.id) 
    JOIN posts p ON (c.post_id = p.id) 
    JOIN users u ON (p.user_id = u.id) 
WHERE u.id = 1 

Soy incapaz de reproducir estas uniones usando find() + el comportamiento Containable. Aunque podría simplemente obtener un usuario con todos sus datos, tendría que recopilar todos los votos dentro del conjunto resultante.

No está funcionando como esto (Advertencia: Columna desconocida 'User.id'):

$this->Vote->recursive = 2; // or higher 
$this->Vote->find('all',array('conditions' => array('User.id' => 1))); 

De hecho, esto ni siquiera funciona usando el mensaje en lugar de usuario (VOTO-> comentario-> Publicar) tan pronto como agregue la condición. La consulta SQL fabricada solo une votos y comentarios.

La matriz devuelta solo debe contener los votos que devolverá la consulta SQL anterior, todo lo demás se debe "unir" en el proceso.

Nota: Mi pregunta está muy cerca de éste, lo que me ayudó a empezar: In cakephp how can I do a find with conditions on a related field?

+0

¿Hay alguna razón por la que esté evitando múltiples belongsTo? – cp3

+0

¿Quiere decir que tiene una columna de clave foránea user_id en la tabla de votación y asociar directamente usuario y voto? Eso parece un poco redundante y crea relaciones circulares en mi esquema. "Habiendo dicho eso" funcionaría, supongo. ¿O estoy malinterpretando lo que quieres decir con multiple belongsTo? Si es así, ¿es posible/necesario agregar explícitamente una asociación para Vote belongsTo User y configurarla para "comentar" y votar? – Wolfram

+0

Agregar una clave externa a cada tabla a la que está asociado a través de otra tabla sería demasiado redundante. – BWelfel

Respuesta

16
$joins = array(
      array('table'=>'comments', 
       'alias' => 'Comment', 
       'type'=>'inner', 
       'conditions'=> array(
       'Comment.id = Vote.comment_id' 
      )), 
      array('table'=>'posts', 
       'alias' => 'Post', 
       'type'=>'inner', 
       'conditions'=> array(
       'Post.id = Comment.post_id' 
      )), 
      array('table'=>'users', 
       'alias' => 'User', 
       'type'=>'inner', 
       'conditions'=> array(
       'User.id = Post.user_id','User.id'=>$user_id 
      )) 
     ); 

$votes = $this->Vote->find('all',array('joins'=>$joins,'recursive'=>-1)); 
+0

Súper upvote ... Gracias amigo ... Estaba tan luchando con estas uniones, la referencia de este código me ayudó ... – Fr0zenFyr

1

Esta puede ser una de esas veces que hay que utilizar el query method.

Las llamadas SQL que no puede o no desea realizar a través de otros métodos de modelo (cuidado - hay muy pocas circunstancias, esto es cierto) se pueden hacer utilizando el método query() del modelo.

$votes = $this->Vote->query('SELECT Vote.* FROM votes Vote 
    JOIN comments Comment ON (Vote.comment_id = Comment.id) 
    JOIN posts Post ON (Comment.post_id = Post.id) 
    JOIN users User ON (Post.user_id = User.id) 
    WHERE User.id = 1'); 

Esto debería devolver una matriz de entradas del voto como el método de búsqueda haría.

foreach ($votes as $vote): 
    echo $vote['Vote']['id']; 
endforeach; 
+0

Gracias, conozco la función query() y para qué se usa, pero realmente quería saber cómo "recorrer el modelo" usando find() para inyectar una condición en otro lugar. – Wolfram

0

En lugar de hacer una consulta SQL personalizada, puede unir explícitamente las tablas para filtrar por un campo de una tabla asociada indirectamente. Echar un vistazo a esta página para ver cómo unirse a los votos y usuarios a través de comentarios: http://book.cakephp.org/view/872/Joining-tables

7

utilizar el comportamiento Containable condiciones para llevar a cabo en modelos asociados. Me llevó un poco desenterrar esto, pero funciona como un encanto! Y usa UNIONES IZQUIERDAS, por lo que aún extraerá todos los valores del Modelo original.

See documentation.

Algo como esto debería funcionar:

$this->Vote->Behaviors->attach('Containable'); 
$this->Vote->find('all',array(
          'contain'=>array(
           'Comment'=>array(
            'Post'=>array(
             'User'=>array(
              'conditions'=>array(
               'User.id'=>1, 
              ), 
             ), 
            ), 
           ), 
          ), 
         )); 

Y si desea incluir los datos de usuario de la persona que votó usted podría simplemente añadir un elemento más a la matriz inicial:

$this->Vote->Behaviors->attach('Containable'); 
$this->Vote->find('all',array(
          'contain'=>array(
           'Comment'=>array(
            'Post'=>array(
             'User'=>array(
              'conditions'=>array(
               'User.id'=>1, 
              ), 
             ), 
            ), 
           ), 
           'User', 
          ), 
         )); 

¡Espero que ayude!

+1

Estoy obteniendo un resultado diferente al probar esta técnica: la condición solo se aplica a 'Usuario'. Si no se cumple la condición, solo 'Usuario' se anula mientras se devuelven todos los votos. En verdad, en mi código tengo relaciones HABTM tales que ni siquiera puedo agregar 'Usuario' a la matriz original porque Cake se queja de que Vote no está asociado con el Usuario. En cualquier caso, para mí la condición parece aplicarse solo a la hoja, no a todo el árbol cuando quería todo el árbol. –

+0

Espero que su respuesta me ayude en mi propio problema. Después de 10 minutos, intento en mi contexto, ¡Funciona, genial! Recuerde, ponga 'public $ actsAs = array ('Containable');' dentro de la clase 'AppModel'. –

Cuestiones relacionadas