CakeDC搜索插件在使用HABTM查询时使用复杂条件

时间:2013-07-04 20:43:20

标签: php cakephp cakedc

我2天前写过关于andConditions的问题,似乎我不明白这个想法,但事实是两天后我现在仍然坚持使用CakeDC的下一步:

如何在CakeDC搜索插件的“查询”方法中实现复杂的HABTM条件?

我提供HABTM功能(表格:优惠,功能,功能_offers),以下工作在控制器中使用时效果很好:

debug($this->Offer->find('all', array('contain' => array(
                'Feature' => array(
                    'conditions' => array(                                
                            'Feature.id in (8, 10)',
                        )
                )
            )
                )
        )
);

当我想在搜索中使用相同的条件时出现问题:

public $filterArgs = array(
    array('name' => 'feature_id', 'type' => 'query', 'method' => 'findByFeatures'),
);


........

public function findByFeatures($data = array()) {
    $conditions = '';
    $featureID = $data['feature_id'];

    if (isset($data['feature_id'])) {
        $conditions = array('contain' => array(
                'Feature' => array(
                    'conditions' => array(
                        'Feature.id' => $data['feature_id'],
                                        )
                                    )
                                )
                            );
    }

    return $conditions;        
}

我收到错误:

  

错误:SQLSTATE [42S22]:找不到列:1054未知列   'where子句'中包含'contains'

这让我觉得我无法在搜索中执行此搜索和/或使用可包含的行为。

如果我在该领域有更多经验的人,请告诉我,如果我遗漏了某些东西或指出我到底在哪里寻找解决方案 - 也许是食谱中的一个部分?

编辑:还试过加入。这在控制器中工作得很好,返回了我需要的所有数据:

$options['joins'] = array(
    array('table' => 'features_offers',
        'alias' => 'FeaturesOffers',
        'type' => 'inner',
        'conditions' => array(
            'Offer.id = FeaturesOffers.offer_id'
        ),
        array('table' => 'features',
            'alias' => 'F',
            'type' => 'inner',
            'conditions' => array(
                'F.id = FeaturesOffers.feature_id'
            ),
        )
    ),
);

$options['conditions'] = array(
    'feature_id in (13)' //. $data['feature_id']
);

debug($this->Offer->find('all', $options));

...当我尝试输入搜索方法时,我只在SQL的where子句中获取返回的条件

  

WHERE((joins =(Array))AND(conditions =('array'中的'feature_id)))

...导致错误:

  

SQLSTATE [42S22]:找不到列:1054'where子句'中的未知列'加入'

编辑:也许我很愚蠢而且很遗憾地说,但插件的文档很糟糕。

我检查了双倍,三倍和四倍(顺便说一句,至少在搜索表单的一个字段中已经丢失了30个小时 facepalm )并且文档中的愚蠢findByTags仍然没有任何意义对我来说。

public function findByTags($data = array()) {
    $this->Tagged->Behaviors->attach('Containable', array('autoFields' => false));
    $this->Tagged->Behaviors->attach('Search.Searchable');
    $query = $this->Tagged->getQuery('all', array(
        'conditions' => array('Tag.name'  => $data['tags']),
        'fields' => array('foreign_key'),
        'contain' => array('Tag')
    ));
    return $query;
}

据我了解

$this->Tagged

应该是HABTM协会模型的名称。

这与cakePHP的标准相差甚远:http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#hasandbelongstomany-habtm

这里描述的方式说,你不需要另一个模型,而是将Recipe与Ingredient相关联,如下所示:

class Recipe extends AppModel {
    public $hasAndBelongsToMany = array(
        'Ingredient' =>
            array(
                'className'              => 'Ingredient',
                'joinTable'              => 'ingredients_recipes',
                'foreignKey'             => 'recipe_id',
                'associationForeignKey'  => 'ingredient_id',
                'unique'                 => true,
                'conditions'             => '',
                'fields'                 => '',
                'order'                  => '',
                'limit'                  => '',
                'offset'                 => '',
                'finderQuery'            => '',
                'deleteQuery'            => '',
                'insertQuery'            => ''
            )
    );
}

意味着您可以从Recipe访问HABTM关联表数据,而无需定义模型“IngredientRecipe”。

根据cakeDC文档,您需要的模型是IngredientRecipe,并且未在cakePHP文档中指明为必需的。即使创建了这个模型,HABTM assoc也无法正常使用它 - 我也试过了。

现在我需要以我的方式重新编写搜索功能,只使用cakePHP,即使我已经花了30个小时......所以不开心。 :(

3 个答案:

答案 0 :(得分:1)

每次我在一个项目中这样做时,我总是花费数小时来弄清楚如何使用CakeDC搜索行为来做到这一点,所以我写这篇文章试图用简单的语言提醒自己我需要做什么。我也注意到虽然Using the CakeDC search plugin with associated models这通常是正确的,但是没有任何解释使得将它修改为一个人自己的项目变得更加困难。

如果你有一个“拥有并且属于许多”的关系,并且你想要搜索连接表,即其中包含两个字段的表,它们将它们的两侧的表连接在一起许多关系,您希望创建一个子查询,其中包含关系中其中一个表的ID列表。将检查关系另一侧的表中的ID以查看它们是否在该记录中,如果它们是,则将选择主表中的记录。

在以下示例中

SELECT Handover.id, Handover.title, Handover.description
FROM handovers AS Handover 
WHERE Handover.id in 
(SELECT ArosHandover.handover_id
FROM aros_handovers AS ArosHandover 
WHERE ArosHandover.aro_id IN (3) AND ArosHandover.deleted != '1') 
LIMIT 20 

如果AroHandover的aro_id为3,则会选择所有记录,然后Handover.id用于决定选择哪个切换记录。

关于如何使用CakeDC搜索行为执行此操作。

首先,将字段放入搜索表单:

echo $this->Form->create('Handover', array('class' => 'form-horizontal'));?>
echo $this->Form->input('aro_id', array('options' => $roles, 'multiple' => true, 'label' => __('For', true), 'div' => false,  true));

等...

请注意,我没有将表单元素放在ArosHandover数据空间中;另一种说法是,当发送表单请求时,字段aro_id将被放置在名为Handover的数组下。

在变量$ filterArgs:

下的模型中
'aro_id' => array('name' => 'aro_id', 'type' => 'subquery', 'method' => 'findByAros', 'field' => 'Handover.id')

注意类型是'子查询',如上所述,您需要创建子查询以便能够找到适当的记录,并通过将类型设置为子查询,告诉CakeDC创建SQL的子查询片段。该方法是将编写代码的函数名称。 field元素是将出现在

上面的示例查询的这一部分中的字段的名称
WHERE Handover.id in 

然后编写将返回子查询的函数:

    function findByAros($data = array()) 
    {
    $ids = ''; //you need to make a comma separated list of the aro_ids that are going to be checked
    foreach($data['aro_id'] as $k => $v)
    {
      $ids .= $v . ', ';
    }
    if($ids != '')
    {
      $ids = rtrim($ids, ', ');
    }
  //you only need to have these two lines in if you have not already attached the behaviours in the ArosHandover model file
    $this->ArosHandover->Behaviors->attach('Containable', array('autoFields' => false));
    $this->ArosHandover->Behaviors->attach('Search.Searchable');

    $query = $this->ArosHandover->getQuery('all',
       array(
         'conditions' => array('ArosHandover.aro_id IN (' . $ids . ')'),
         'fields' => array('handover_id'),  //the other field that you need to check against, it's the other side of the many-to-many relationship 
         'contain' => false //place this in if you just want to have the ArosHandover table data included
       )
    );
    return $query;
  }

在切换控制器中:

public $components = array('Search.Prg', 'Paginator'); //you can also place this into AppController
public $presetVars = true; //using $filterArgs in the model configuration 
public $paginate = array(); //declare this so that you can change it

// this is the snippet of the search form processing
public function admin_find()
  {
    $this->set('title_for_layout','Find handovers');
    $this->Prg->commonProcess();
    if(isset($this->passedArgs) && !empty($this->passedArgs))
    {//the following line passes the conditions into the Paginator component
      $this->Paginator->settings = array('conditions' => $this->Handover->parseCriteria($this->passedArgs));
      $handovers = $this->Paginator->paginate(); // this gets the data
      $this->set('handovers', $handovers); // this passes it to the template

如果你想进一步解释为什么我做了什么,请问,如果我收到一封电子邮件,告诉我你已经问过,如果我能够,我会给出答案。

答案 1 :(得分:0)

这不是插件的问题,而是如何构建关联。您需要正确加入它们以搜索这三个表。检查CakePHP默认情况下如何从HABTM关联中获取数据。

http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#joining-tables

  

假设Book hasAndBelongsToMany Tag关联。这种关系使用   books_tags表作为连接表,因此您需要加入books表   到books_tags表,这与标签表:

$options['joins'] = array(
    array('table' => 'books_tags',
        'alias' => 'BooksTag',
        'type' => 'inner',
        'conditions' => array(
            'Books.id = BooksTag.books_id'
        )
    ),
    array('table' => 'tags',
        'alias' => 'Tag',
        'type' => 'inner',
        'conditions' => array(
            'BooksTag.tag_id = Tag.id'
        )
    )
);

$options['conditions'] = array(
    'Tag.tag' => 'Novel'
);
  

$ books = $ Book-> find('all',$ options);使用连接可以让你拥有   CakePHP处理关联和获取的最大灵活性   数据,但在大多数情况下,您可以使用其他工具来实现   相同的结果,如正确定义关联,绑定模型   在运行中并使用Containable行为。这个功能应该是   小心使用,因为在某些情况下,它可能导致形成不良   SQL查询是否与任何前面描述的技术结合使用   用于关联模型。

你的代码也错了。

Column not found: 1054 Unknown column 'contain' in 'where clause'

这意味着以某种方式调用$ Model-> contains()。我在你的代码中没有看到这样的调用,所以它必须在其他地方。如果找不到模型方法,则通常会将字段名称作为列发生此错误。

答案 2 :(得分:0)

我想与大家分享使用插件处理HABTM搜索的解决方案:Using the CakeDC search plugin with associated models

@burzum,文档远非好人。你注意到使用'type'=> '复选框'并且在任何地方都没有提到它是一种类型? 更不用说完全缺乏语法和大量的错别字和缺少介词。我失去了2天只是为了弄清楚作者的想法并将那些词绑在那里。没有评论。

我很高兴在上坡工作5天后我做到了。无论如何,谢谢您的帮助。