将 CakeDC 搜索插件与相关模型一起使用


Using the CakeDC search plugin with associated models

我正在使用CakePHP 1.3.8,并且安装了CakeDC搜索插件。我有一个教程模型,它与学习目标模型处于HABTM关系中。

我在教程控制器中有一个搜索操作和视图,通过它我可以成功搜索教程模型中的字段。我还想使用同一表单上的学习目标复选框过滤我的教程搜索结果。我尝试将各种参数添加到教程的$filterArgs和教程控制器的$presetVars。我还尝试将相关$filterArgs移动到学习目标模型。我尚未能够成功触发$filterArgs学习目标的条目。

我想我一定错过了一些明显的东西。或者,也许搜索插件不支持我正在尝试执行的操作。有谁知道如何使用此插件搜索相关模型?

这就是我想出的。您可以将以下内容与搜索插件说明相结合,以搜索相关模型。

教程模型中的$filterArgs部分必须如下所示:

var $filterArgs = array(
  array('name' => 'LearningGoal', 'type' => 'subquery', 'method' => 'findByLearningGoals', 'field' => 'Tutorial.id'),
);

下面是教程模型中的支持函数:

function findByLearningGoals($data = array()) {
  $ids = explode('|', $data['LearningGoal']);
  $ids = join(',', $ids);
  $this->LearningGoalsTutorial->Behaviors->attach('Containable', array('autoFields' => false));
  $this->LearningGoalsTutorial->Behaviors->attach('Search.Searchable');
  $query = $this->LearningGoalsTutorial->getQuery('all',
     array(
       'conditions' => array('LearningGoalsTutorial.learning_goal_id IN (' . $ids . ')'),
       'fields' => array('tutorial_id'),
     )
  );
  return $query;
}

在 TutorialsController 中,$presetVars应如下所示:

public $presetVars = array(
  array('field' => 'LearningGoal', 'type' => 'checkbox', 'model' => 'Tutorial'),
);

在TutorialsController中的搜索操作中,我做到了:

$this->LearningGoal = $this->Tutorial->LearningGoal;

Prg 组件似乎需要这个。

我正在使用CakePHP版本2.X

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

当您具有"具有并属于多个"关系并且想要搜索连接表时,即具有两个字段的表,该字段将多对多关系中两侧的表连接在一起,您希望创建一个子查询,其中包含关系中其中一个表中的 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));

等。。。

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

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