【问题标题】:CakePHP how to retrieve HABTM data with conditions?CakePHP如何检索带有条件的HABTM数据?
【发布时间】:2012-09-09 03:56:54
【问题描述】:

我使用的是 CakePHP 2.2.2 我有 3 张桌子:餐厅、厨房和 kitchens_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]: Column not found: 1054 Unknown column in 'where 子句'错误。 显然我需要从“HABTM 连接表”中获取数据,但我不知道如何。

【问题讨论】:

    标签: php cakephp has-and-belongs-to-many


    【解决方案1】:

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

    【讨论】:

    • 戴夫,谢谢。您的代码运行良好。一个小问题——是否可以只选择我想要的字段(例如,我只需要公司名称和其他一些信息,而不是所有字段)?我尝试将 'fields' => array('Restaurant.companyname') 添加到函数 getRestaurantByKitchenId (在餐厅模型中),但它不会产生任何影响。
    • @user1327 - 很高兴为您提供帮助。是的,您应该能够将 'fields'=>array() 添加到 Model 方法中。只需将其置于与“加入”相同的级别(不在其中)。您始终可以使用 DebugKit 轻松查看正在运行的查询,并可以据此进行调整。
    • 哦,我真傻。现在一切都按我的意愿进行。再次感谢您。
    • 感谢您的出色回答,再次感谢您为我节省了大量时间
    • 是否可以结合分页使用该方法?
    【解决方案2】:

    你可以不需要使用 [join],因为使用已经设置了 [HABTM] 的关联
    Kitchen 模型 hasAndBelongsToMany 餐厅模型,因此您可以编写如下代码

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

    祝你好运!

    【讨论】:

    • 这不会归还所有厨房吗?
    • 是的,我认为这将归还所有厨房。但是,该代码对于查找模型 A 中的所有记录并显示模型 B 中的相关 HABTM 记录是正确的。
    • 是的,它返回所有厨房,如果你想找到有条件的,你可以使用下面的示例: $this->Kitchen->find('all', array('conditions' => array ('Kitchen.id >' => '5'), 'contain' => array('Restaurant')))
    【解决方案3】:

    有一种比 Dave 提供的解决方案更清洁的方法。

    首先您需要在Kitchen 模型中设置RestaurantKitchen 之间的反向HABTM 关系。

    您只需find 为您感兴趣的Kitchen (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

    【讨论】:

    • 这代表什么? "$this->餐厅->厨房->"
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-14
    • 1970-01-01
    • 1970-01-01
    • 2016-03-14
    • 2011-01-29
    • 2011-10-22
    • 1970-01-01
    相关资源
    最近更新 更多