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

时间:2011-05-13 18:39:10

标签: php search cakephp cakephp-1.3

我正在使用CakePHP 1.3.8,我已经安装了CakeDC Search plugin。我有一个Tutorial模型,它与LearningGoal模型处于HABTM关系。

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

我想我一定错过了一些明显的东西。或者搜索插件可能不支持我想要做的事情。有谁知道如何使用这个插件搜索相关的模型?

2 个答案:

答案 0 :(得分:0)

所以这就是我所知道的。您可以将以下内容与搜索插件方向结合起来搜索相关模型。

Tutorial模型中的$ 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组件似乎需要这样。

答案 1 :(得分:0)

我正在使用CakePHP版本2.X

每次我在一个项目中这样做时,我总是花费数小时来弄清楚如何使用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 

如果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

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