2012-09-16 27 views
10

Tôi sử dụng CakePHP 2.2.2 Tôi có 3 bảng: nhà hàng, nhà bếp và bếp_restaurants - tham gia bàn cho HABTM.CakePHP cách truy xuất dữ liệu HABTM với các điều kiện?

Trong mô hình nhà hàng tôi có:

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

Vấn đề là tôi có bộ điều khiển riêng biệt cho trang chính của tôi trong đó tôi cần phải lấy dữ liệu từ các mô hình này với điều kiện phức tạp.

tôi thêm

public $uses = array('Restaurant'); 

để điều khiển trang chính của tôi và ở đây có một phần mà tôi cần lời khuyên của bạn.

Tôi chỉ cần chọn những nhà hàng có nhà bếp = $ id. Tôi đã cố gắng thêm

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

} 

và tôi đã nhận SQLSTATE [42S22]: Cột không tìm thấy: 1054 Unknown cột trong 'mệnh đề where' lỗi. Rõ ràng là tôi cần lấy dữ liệu từ "bảng tham gia HABTM" nhưng tôi không biết làm thế nào.

Trả lời

23

TLDR:

Để lấy dữ liệu đó là hạn chế dựa trên các điều kiện đối với hiệp hội một [ HABTM ] 's, bạn cần phải sử dụng [ Joins ].

Giải thích:

Đoạn code dưới đây theo [ Fat Model/Skinny Controller ] thần chú, vì vậy logic chủ yếu là tất cả trong mô hình, và chỉ được gọi từ một bộ điều khiển.

Lưu ý: Bạn không cần tất cả các thông số HABTM đó nếu bạn theo dõi [ CakePHP conventions ] (có vẻ như bạn đang ở đó).

Mã dưới đây chưa được kiểm tra (tôi đã viết nó trên trang này), nhưng nó phải khá gần gũi và ít nhất giúp bạn đi đúng hướng.

Code:

// Restaurant mô hình

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

// Bất kỳ điều khiển

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

Dave, cảm ơn bạn. Mã của bạn hoạt động rất tốt. Một câu hỏi nhỏ - chỉ có thể chọn các trường tôi muốn (ví dụ: tôi chỉ cần tên công ty và một số thông tin khác, không phải tất cả các trường)? Tôi đã cố gắng thêm 'fields' => array ('Restaurant.companyname') vào hàm getRestaurantsByKitchenId (trong mô hình Nhà hàng) nhưng nó không gây ra bất kỳ hiệu ứng nào. – user1327

+0

@ user1327 - Rất vui được trợ giúp. Có, bạn sẽ có thể thêm 'fields' => array() vào phương thức Model. Chỉ cần đặt nó ở cấp độ tương tự như 'tham gia' (không phải trong vòng). Bạn luôn có thể sử dụng DebugKit để dễ dàng xem những truy vấn nào đang được chạy và có thể tinh chỉnh dựa trên đó. – Dave

+0

Ồ, ngớ ngẩn tôi. Bây giờ mọi thứ hoạt động như tôi muốn. Cảm ơn bạn một lần nữa. – user1327

1

Bạn không thể cần sử dụng [tham gia], bởi vì sử dụng đã thiết lập [HABTM] 's hiệp hội
mô hình nhà bếp hasAndBelongsToMany nhà hàng mô hình để bạn có thể mã như dưới đây

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

Chúc may mắn!

+1

sẽ không trả lại tất cả các nhà bếp? – tsukimi

+0

Vâng, tôi nghĩ rằng điều này sẽ trả lại tất cả các nhà bếp. Tuy nhiên, mã là chính xác để tìm tất cả các bản ghi trong Mẫu A và hiển thị các bản ghi HABTM liên quan từ Mẫu B. – Joseph

+0

có, nó trả về tất cả các nhà bếp, nếu bạn muốn tìm với điều kiện bạn có thể sử dụng như dưới đây: $ -> Kitchen-> find ('all', array ('conditions' => array ('Kitchen.id>' => '5'), 'contains' => mảng ('Nhà hàng'))) –

1

Có một cách sạch hơn nhiều so với giải pháp do Dave cung cấp.

Trước tiên, bạn cần phải thiết lập một mối quan hệ HABTM ngược giữa Restaurantbếp trong bếp Model.

Hơn bạn chỉ cần thực hiện một tìm cho bếp bạn quan tâm (id = 1) và bạn sẽ nhận được những nhà hàng có liên quan, sử dụng Containable Behavior để lọc bởi Restaurant lĩnh vực.

$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

Các vấn đề liên quan