2012-09-16 12 views
10

Yo uso CakePHP 2.2.2 Tengo 3 mesas: restaurantes, cocinas y cocinas_restaurantes - mesa para HABTM.CakePHP cómo recuperar datos HABTM con condiciones?

En el modelo de restaurante que he:

public $hasAndBelongsToMany = array(
    'Kitchen' => 
     array(
      'className'    => 'Kitchen', 
      'joinTable'    => 'kitchens_restaurants', 
      'foreignKey'    => 'restaurant_id', 
      'associationForeignKey' => 'kitchen_id', 
      'unique'     => true, 
      'conditions'    => '', 
      'fields'     => 'kitchen', 
      'order'     => '', 
      'limit'     => '', 
      'offset'     => '', 
     ), 

El problema es que no tengo controlador separado para mi página principal en la que necesito para recuperar datos de estos modelos con condiciones complejas.

que añade

public $uses = array('Restaurant'); 

a mi controlador principal página y aquí viene la parte en la que necesito sus consejos.

Necesito seleccionar solo aquellos restaurantes donde la cocina = $ id. He intentado añadir

public function index() { 
$this->set('rests', $this->Restaurant->find('all', array(
'conditions' => array('Restaurant.active' => "1", 'Kitchen.id' => "1") 
))); 

} 

y llegué SQLSTATE [42S22]: La columna no encontrado: 1054 Desconocido columna en 'cláusula where' error. Obviamente necesito obtener datos de "HABTM join table" pero no sé cómo.

Respuesta

23

TLDR:

para recuperar los datos que está limitado debido a las condiciones contra un [ HABTM ] 's asociación, es necesario utilizar [ Joins ].

Explicación:

El código siguiente sigue el mantra [ Fat Model/Skinny Controller ], por lo que la lógica es en su mayoría todos en el modelo, y simplemente se llama a partir de un controlador.

Nota: No necesita todos esos parámetros HABTM si sigue el [ CakePHP conventions ] (que parece que es).

El siguiente código no se ha probado (lo escribí en este sitio), pero debe ser bastante cerrado y, al menos, llegar en la dirección correcta.

Código:

// restaurante modelo

public $hasAndBelongsToMany = array('Kitchen'); 

/** 
* Returns an array of restaurants based on a kitchen id 
* @param string $kitchenId - the id of a kitchen 
* @return array of restaurants 
*/ 
public function getRestaurantsByKitchenId($kitchenId = null) { 
    if(empty($kitchenId)) return false; 
    $restaurants = $this->find('all', array(
     'joins' => array(
      array('table' => 'kitchens_restaurants', 
       'alias' => 'KitchensRestaurant', 
       'type' => 'INNER', 
       'conditions' => array(
        'KitchensRestaurant.kitchen_id' => $kitchenId, 
        'KitchensRestaurant.restaurant_id = Restaurant.id' 
       ) 
      ) 
     ), 
     'group' => 'Restaurant.id' 
    )); 
    return $restaurants; 
} 

// Cualquier controlador

public function whateverAction($kitchenId) { 
    $this->loadModel('Restaurant'); //don't need this line if in RestaurantsController 
    $restaurants = $this->Restaurant->getRestaurantsByKitchenId($kitchenId); 
    $this->set('restaurants', $restaurants); 
} 
+1

de Dave, gracias. Tu código funciona muy bien. Una pequeña pregunta: ¿es posible seleccionar solo los campos que quiero (por ejemplo, solo necesito el nombre de la empresa, y alguna otra información, no todos los campos)? He intentado agregar 'fields' => array ('Restaurant.companyname') a la función getRestaurantsByKitchenId (en el modelo Restaurants) pero no causa ningún efecto. – user1327

+0

@ user1327 - Me alegra ayudar. Sí, debería poder agregar 'fields' => array() al método Model. Simplemente póngalo en el mismo nivel que 'une' (no dentro). Siempre puede usar DebugKit para ver fácilmente qué consultas se están ejecutando, y puede modificarlas según eso. – Dave

+0

Oh, tonto yo. Ahora todo funciona como yo quiero. Una vez mas, Gracias. – user1327

1

No se puede necesitar el uso [unirse], ya que el uso ha de ajustar [HABTM] 's asociación
modelo de cocina tieneAndBelongsToMany modelo de restaurante para que pueda codificar como abajo

KitchensControllers 
<?php 
    public function index() { 
    $this->Kitchen->recursive = 0; 
    $kitchens = $this->Kitchen->find('all', array('contain' => array('Restaurant'))); 
    $this->set('kitchens', $kitchens); 
    } 
?> 

¡Buena suerte!

+1

no es esto devolver todas las cocinas? – tsukimi

+0

Sí, creo que esto devolvería todas las cocinas. Sin embargo, el código es correcto para encontrar todos los registros en el Modelo A y mostrar los registros HABTM relacionados del Modelo B. – Joseph

+0

sí, devuelve todas las cocinas, si desea consultar las condiciones, puede usar la siguiente muestra: $ this -> Cocina-> buscar ('todo', matriz ('condiciones' => matriz ('Kitchen.id>' => '5'), 'contener' => matriz ('Restaurante'))) –

1

Hay una manera mucho más limpia que la solución provista por Dave.

Primero debe establecer la relación inversa entre HABTM restaurante y cocina en el Modelo cocina.

De lo que acaba de hacer un encuentran para la cocina le interesa (id = 1) y obtendrá los restaurantes asociados, utilizando Containable Behavior para el filtrado por restaurante campos.

$this->Restaurant->Kitchen->Behaviors->attach('containable'); // Enable Containable for Kitchen Model 

$this->Restaurant->Kitchen->find('first', array(
    'recursive' => -1 // don't collect other data associated to Kitchen for performance purpose 
    'conditions' => array('Kitchen.id' => 1), 
    'contain' => array('Restaurant.active = 1') 
)); 

Source

Cuestiones relacionadas