2012-09-16 43 views
10

我使用CakePHP 2.2.2 我有3個表格:餐廳,廚房和廚房餐廳 - HABTM連接表。CakePHP如何檢索具有條件的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'); 

我的主要頁面控制器和這裏來,我需要你的建議的一部分。

我只需要選擇那些kitchen = $ id的餐廳。 我試着添加

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

} 

和我SQLSTATE [42S22]:列未找到:在 'where子句' 錯誤1054未知列。 顯然我需要從「HABTM連接表」中獲取數據,但我不知道如何。

回答

23

TLDR:

要檢索是基於對一個[ HABTM ]的關聯條件有限的數據,你需要使用[ Joins ]

說明:

下面的代碼如下[ Fat Model/Skinny Controller ]曼陀羅,因此,所述邏輯大多都在模型中,並且只是獲取從控制器調用。

注意:如果您按照[ CakePHP conventions ](看起來您是),則不需要所有這些HABTM參數。

下面的代碼沒有經過測試(我在這個網站上寫過),但它應該相當貼近,至少讓你在正確的方向。

代碼:

//餐廳模型

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); 
} 
+1

戴夫,謝謝。你的代碼工作得很好。一個小問題 - 是否可以只選擇我想要的字段(例如,我只需要公司名稱和其他信息,而不是所有字段)?我嘗試將'fields'=> array('Restaurant.companyname')添加到函數getRestaurantsByKitchenId(在Restaurants模型中),但它不會產生任何影響。 – user1327

+0

@ user1327 - 很高興提供幫助。是的,您應該可以將'fields'=> array()添加到Model方法。只要把它放在與'連接'(不在)相同的水平。您始終可以使用DebugKit輕鬆查看正在運行的查詢,並可以基於此進行調整。 – Dave

+0

哦,傻了。現在一切都按我想要的那樣工作。再一次 - 謝謝。 – user1327

1

你不能使用需要[加入],因爲使用已經設置[HABTM]的協會
廚房模型hasandBelongsToMany餐廳模型,以便您可以編碼爲波紋管

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

祝你好運!

+1

不會這樣返回所有的廚房? – tsukimi

+0

是的,我認爲這將返回所有的廚房。但是,該代碼對於查找模型A中的所有記錄並顯示來自模型B的相關HABTM記錄是正確的。 – Joseph

+0

是的,如果要查找具有可用作波紋管樣品的條件的所有廚房,則返回所有廚房: $ this - > find('all',array('conditions'=> array('Kitchen.id>'=>'5'),'contains'=> array('Restaurant'))) –

1

有比Dave提供的解決方案更清潔的方法。

首先,你需要設置餐廳之間的反向關係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') 
)); 

Source