0

两天前我写信询问 andConditions 似乎我不明白这个想法,但事实是两天来我一直坚持使用 CakeDC 的下一步:

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

我有提供 HABTM 功能(表:提供、功能、功能提供),以下在控制器中使用时效果很好:

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 子句'中的未知列 'contain'

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

如果我遗漏了什么,或者在该领域有更多经验的人可以告诉我,或者指出我在哪里可以找到解决方案——也许是食谱中的一个部分?

编辑:还尝试了连接。这在控制器中工作得非常好,返回我需要的所有数据:

$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 = ('feature_id in Array')))

...导致错误:

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

编辑:也许我很愚蠢,很抱歉这么说,但插件的文档很糟糕。

我检查了两次、三次和四次(顺便说一句,至少在搜索表单facepalm的 1 个字段上已经损失了 30 个小时)并且文档中愚蠢的 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

此处描述的方式表示您不需要其他模型,而是将配方与成分相关联,如下所示:

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

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

根据 cakeDC 文档,您需要的模型是 IngredientRecipe,并且在 cakePHP 文档中并未将其指示为强制性内容。即使创建了这个模型,HABTM assoc 也不能正常工作——我也试过了。

现在我需要以我的方式重新编写搜索功能,只使用 cakePHP,尽管我已经花了 30 个小时在它上面……太不高兴了。:(

4

3 回答 3

1

每次我在一个项目中执行此操作时,我总是会花费数小时来弄清楚如何使用 CakeDC 搜索行为来完成它,所以我写了这个来尝试用简单的语言提醒自己我需要做什么。我还注意到,尽管将 CakeDC 搜索插件与关联模型一起使用,这通常是正确的,但没有任何解释,这使得将其修改为自己的项目变得更加困难。

当您有一个“拥有并属于很多”关系并且您想要搜索连接表时,即其中包含两个字段的表,它将其两侧的表以多对多关系连接在一起,您想要从关系中的一个表中创建一个包含 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 

如果 ArosHandover 的所有记录的 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));

ETC...

请注意,我没有将表单元素放置在 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

如果您想进一步解释我为什么做某事,请询问,如果我收到一封电子邮件告诉我您已经问过,如果可以的话,我会给出答复。

于 2014-02-26T14:03:08.587 回答
0

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

@burzum,文档远非正常人。你注意到 'type' => 'checkbox' 的使用并且在任何地方都没有提到它是一种类型吗?更不用说完全缺乏语法以及大量的拼写错误和丢失的介词。我浪费了 2 天的时间,只是为了了解作者的想法并将文字绑定在里面。对此不予置评。

我很高兴经过 5 天的艰苦工作,我成功了。无论如何感谢您的帮助。

于 2013-07-07T14:41:03.750 回答
0

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

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

假设 Book hasAndBelongsToMany Tag 关联。此关系使用 books_tags 表作为连接表,因此您需要将 books 表连接到 books_tags 表,这与 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 如何处理关联和获取数据方面拥有最大的灵活性,但是在大多数情况下,您可以使用其他工具来实现相同的结果,例如正确定义关联、动态绑定模型和使用可包含行为。应谨慎使用此功能,因为在少数情况下,如果与之前描述的用于关联模型的任何技术结合使用,它可能会导致格式错误的 SQL 查询。

此外,您的代码在某处是错误的。

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

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

于 2013-07-04T22:41:22.780 回答