CakePHP как получить данные HABTM с условиями?

Я использую CakePHP 2.2.2 У меня есть 3 стола: рестораны, кухни и кухни_restaurants - соедините таблицу для HABTM.

В модели ресторана у меня есть:

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

Проблема в том, что у меня есть отдельный контроллер для моей главной страницы, в котором мне нужно получить данные из этих моделей со сложными условиями.

Я добавил

public $uses = array('Restaurant');

на мой главный контроллер страницы, и вот часть, в которой мне нужны ваши советы.

Мне нужно выбрать только те рестораны, где кухня = $id. Я попытался добавить

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

}

и я получил SQLSTATE [42S22]: Столбец не найден: 1054 Неизвестный столбец в ошибке "where clause". Очевидно, мне нужно получить данные из "таблицы соединения HABTM", но я не знаю, как это сделать.

Ответ 1

TL;DR:

Чтобы получить данные, которые ограничены в зависимости от условий, связанных с ассоциацией [HABTM], вам нужно использовать [Соединения].

Объяснение:

Ниже приведен код [Fat Model/Skinny Controller] мантра, поэтому логика в основном всего в модели, и ее просто называют от контроллера.

Примечание: вам не нужны все эти параметры HABTM, если вы следуете [Соглашениям CakePHP] (который, как вам кажется).

Нижеприведенный код не был протестирован (я написал его на этом сайте), но он должен быть близок и, по крайней мере, поможет вам в правильном направлении.

Код:

//Модель ресторана

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;
}

//Любой контроллер

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

Ответ 2

Вам не нужно использовать [join], потому что использование имеет настройку [HABTM] association
Кухонная модель hasAndBelongsToMany модель ресторана, чтобы вы могли закодировать как ниже -

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

Удачи!

Ответ 3

Существует гораздо более чистый способ, чем решение, предоставленное Дейвом.

Сначала вам нужно установить обратную связь HABTM между рестораном и кухней в кухонной модели.

Чем вы просто нарисуете интересующую вас кухню (id = 1), и вы получите ассоциированные рестораны, используя Containable Behavior для фильтрации по полям ресторана.

$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')
));

Источник