CakeDC搜索和标记插件 - 搜索多个标签

时间:2013-05-29 11:42:40

标签: cakephp cakedc

希望我在这里遗漏一些简单的东西。我正在使用我的蛋糕(2.3.4)应用程序的CakeDC搜索和标签插件。

除了按字段功能进行通用搜索外,我希望用户能够按标签搜索。我几乎得到了这个工作,但搜索只会显示搜索单个标签而不是倍数的结果。例如,如果我添加一个带有以下标签的文章 - 黑色,白色,红色。如果我搜索单个标签(例如黑色)而不是全部3个标签,甚至2个标签,那么文章只会在搜索结果中显示...我错过了什么?

继承我的代码:

Article.php模型

class Article extends AppModel {
public $actsAs = array(
    'Upload.Upload' => array(
        'screenshot1' => array (
            'fields' => array (
                'dir' => 'dir'
            ),
            'thumbnailMethod' => 'php',
            'thumbnailSizes' => array(
                'xvga' => '1024x768',
                'vga' => '640x480',
                'thumb' => '80x80'
            ),
        ),
    ),
'Search.Searchable',
'Tags.Taggable'

);

// Search plugin filters
public $filterArgs = array(      
    'title' => array('type' => 'like'),
    'environment' => array('type' => 'like'),
    'description' => array('type' => 'like'),
    'error' => array('type' => 'like'),
    'cause' => array('type' => 'like'),
    'resolution' => array('type' => 'like'),
    'live' => array('type' => 'value'),
    'synced' => array('type' => 'value'),
    'tags' => array('type' => 'subquery', 'method' => 'findByTags', 'field' => 'Article.id'),
    array('name' => 'search', 'type' => 'query', 'method' => 'filterQuery'),
);

// This is the OR query that runs when the user uses the client side signle field search
public function filterQuery($data = array()) {
    if(empty($data['search'])) { // search is the name of my search field
        return array();
    }

    $query = '%'.$data['search'].'%';
    return array(
        'OR' => array(
            'Article.title LIKE' => $query,
            'Article.description LIKE' => $query,
            'Article.error LIKE' => $query,
            )
        );
}

// Find by tags method
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;
}

public $hasAndBelongsToMany = array(
    'Category' => array(
        'className' => 'Category',
        'joinTable' => 'articles_categories',
        'foreignKey' => 'article_id',
        'associationForeignKey' => 'category_id',
        'unique' => 'keepExisting',
        'conditions' => '',
        'fields' => '',
        'order' => '',
        'limit' => '',
        'offset' => '',
        'finderQuery' => '',
        'deleteQuery' => '',
        'insertQuery' => ''
    ),
    'Tag' => array('with' => 'Tagged')
);

控制器方法

public function admin_advancedSearch() {

        // Disable validation for this action
        $this->Article->validate = array();

        // For search plugin
        $this->Prg->commonProcess();

        // Set searched for details
        $this->set('searchedFor', $this->passedArgs);

        // If passed args are all empty
        if ($this->passedArgs) {

            if (empty($this->passedArgs['title']) AND
                empty($this->passedArgs['environment']) AND
                empty($this->passedArgs['description']) AND
                empty($this->passedArgs['error']) AND
                empty($this->passedArgs['cause']) AND
                empty($this->passedArgs['resolution']) AND
                empty($this->passedArgs['live']) AND
                empty($this->passedArgs['synced']) AND
                empty($this->passedArgs['tags'])) {

                    $this->Session->setFlash('Please enter at least one search criteria', 'flash_failure');
                    // Set this var for checks in view
                    $this->set('emptySeach', true);
            } else {

                $paginateConditions = $this->Article->parseCriteria($this->passedArgs);
                $this->paginate = array('conditions' => array(
                                            $paginateConditions),
                                        'limit' => 10,
                                        'order' => array('Article.modified' => 'DESC'));            
                $this->set('articles', $this->paginate());

                // Count number of results
                $count = 0;
                foreach ($this->paginate() as $result) {
                    $count++;
                }

                $this->set('resultsCount', $count);

                // Search was not empty - set flag for view
                $this->set('emptySeach', false);
            }
        }

        // Set layout
        $this->layout = 'admin';

        //debug($this->passedArgs);
    }

所有插件都是从bootstrap成功加载的,搜索工作正常而没有标签。只有输入一个标签,才能使用标签进行搜索....

* 编辑* 如果我从findByTags方法调试$ query,我得到这个:

'SELECT `Tagged`.`foreign_key` FROM `knowledgebase`.`tagged` AS `Tagged` LEFT JOIN `knowledgebase`.`tags` AS `Tag` ON (`Tagged`.`tag_id` = `Tag`.`id`)  WHERE `Tag`.`name` = 'kia, rio, red''

所以看起来它试图在其名称中找到包含所有搜索标签的单个标签。如何将WHERE部分设为IN?

例如:

WHERE `Tag`.`name` IN ('kia', 'rio', 'red')

由于

1 个答案:

答案 0 :(得分:1)

使用“方法”https://github.com/cakedc/search#behavior-and-model-configuration键将搜索参数传递给自定义方法。

此处的示例向您详细说明了其工作原理https://github.com/cakedc/search#full-example-for-modelcontroller-configuration-with-overriding

public $filterArgs = array(
    'some_related_table_id' => array('type' => 'value'),
    'search'=> array('type' => 'like', 'encode' => true, 'before' => false, 'after' => false, 'field' => array('ThisModel.name', 'OtherModel.name')),
    'name'=> array('type' => 'query', 'method' => 'searchNameCondition')
);

public function searchNameCondition($data = array()) {
    $filter = $data['name'];
    $cond = array(
        'OR' => array(
            $this->alias . '.name LIKE' => '' . $this->formatLike($filter) . '',
            $this->alias . '.invoice_number LIKE' => '' . $this->formatLike($filter) . '',
    ));
    return $cond;
}

在自定义方法中使用explode()标记并使它们成为一个数组,以便CakePHP将它们用作IN()或更好(可以变慢)使其成为AND或OR链。