「CakeDC search plugin」をインストール

プラグインをGithubからダウンロードします。

CakeDC / search

インストールは「app」→「plugin」に「search」というフォルダ名で入れておきます。

データベース

データベースはこんな感じです。

Posts

idbigint(20)
titlevarchar(100)
textvarchar(255)

Tags

idbigint(20)
titlevarchar(100)

PostsTags

post_idbigint(20)
tag_idvarchar(100)

とりあえず一つのFieldから検索する。

とりあえず一つのFieldから検索してみます。これはとても簡単。
ここではPostモデルのtitleフィールドを検索してみます。

[Model] post.php
class Post extends AppModel {
public $name = 'Post';
public $actsAs = array('Search.Searchable');
public $filterArgs = array(
array('name' => 'title', 'type' => 'like'),
);
}
[Controller] posts_controller.php
class PostsController extends AppController {
public $name = 'posts';
public $components = array('Search.Prg');
public $presetVars = array(
array('field' => 'title', 'type' => 'value'),
);
function index() {
$this->Prg->commonProcess();
$this->paginate['conditions'] = $this->Post->parseCriteria($this->passedArgs);
$this->set("result", $this->paginate());
}
}
[View] posts_controller.php
echo $this->Form->create('Post', array(
'url' => array_merge(array('action' => 'index'), $this->params['pass'])
));
echo $this->Form->input('title', array('div' => false));
echo $this->Form->submit('検索');
echo $this->Form->end();

「title」を検索させるフィールドに変更してください。
これだけでいけるはずです。

一つのinput(テキストボックス)から二つのFieldから検索する。

たとえばブログのサイト内検索だったらタイトルだけじゃなくて記事テキストも検索したいと思うんですよ。
ここではサンプルデータベースの例からPostモデルの「title」と「text」フィールドを検索してみます。

[Model] post.php
class Post extends AppModel {
public $name = 'Post';
public $actsAs = array('Search.Searchable');
public $filterArgs = array(
array('name' => 'title', 'type' => 'query', 'method' => 'orConditions'),
);
public function orConditions($data = array()) {
$filter = $data['title'];
$cond = array(
'OR' => array(
$this->alias . '.title LIKE' => '%' . $filter . '%',
$this->alias . '.text LIKE' => '%' . $filter . '%',
));
return $cond;
}
}

独自な処理をする場合は「$filterArgs」のtypeを「query」にしてメソッドを記述します。
検索するフィールドを追加する場合は「orConditions」の「OR」に追加していきます。

input(テキストボックス)からHABTMを検索する。

次はHABTMです。
検索したテキストをタグにもヒットさせたいなと。

モデルの「$hasAndBelongsToMany」は規則通りにしてればある程度省略できますが、省略してしまうとサーチプラグインでは問題があったりするみたいなので、ある程度ちゃんとに書きます。
「with」とかがポイントらしいです。

[Model] post.php
public $hasAndBelongsToMany = array(
'Tag' => array(
'className' => 'Tag',
'joinTable' => 'posts_tags',
'foreignKey' => 'post_id',
'associationForeignKey' => 'tag_id',
'with' => 'PostsTag',
'unique' => true
),
);
[Model] posts_tag.php
public $belongsTo = array(
'Tag' => array(
'className' => 'Tag',
'foreignKey' => 'tag_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Post' => array(
'className' => 'Post',
'foreignKey' => 'post_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);

HABTMの場合は「$filterArgs」のtypeを「subquery」にするらしいです。メソッドも変更します。

[Model] post.php
public $filterArgs = array(
array('name' => 'title', 'type' => 'subquery', 'method' => 'findByTags', 'field' => 'Post.id'),
);
public function findByTags($data = array()) {
$this->PostsTag->Behaviors->attach('Containable', array('autoFields' => false));
$this->PostsTag->Behaviors->attach('Search.Searchable');
$query = $this->PostsTag->getQuery('all',array(
'conditions' => array(
'Tag.title' => $data['title']
),
'fields' => array('post_id'),
'contain' => array('Tag')
));
return $query;
}

これでTagモデルの「title」フィールドが検索されると思います。

一つのinput(テキストボックス)から複数のFieldとHABTMも検索する。

もうここまできたらHABTMだけといわずPost側のFieldも一緒に検索したいなと。
単純に考えれば上記のサンプルを合体させればいけそうな気がするんですが。

[Model] post.php
public function findByTags($data = array()) {
$this->PostsTag->Behaviors->attach('Containable', array('autoFields' => false));
$this->PostsTag->Behaviors->attach('Search.Searchable');
$filter = $data['title'];
$query = $this->PostsTag->getQuery('all',array(
'conditions' => array(
'or' => array(
array('Tag.title' => $filter),
$this->alias . '.title LIKE' => '%' . $filter . '%',
$this->alias . '.text LIKE' => '%' . $filter . '%',
)
),
'fields' => array('post_id'),
'contain' => array('Tag')
));
return $query;
}

「or」にlikeを追加していくだけでした。
結果的にほぼGithubのサンプルでできたので、どこではまる必要があったんだという感じですが、、、、。

参考サイト
Search Plugin for CakePHPで簡単検索機能実装
CakePHP の Search Plugin で HABTM なモデルを検索する
CakeDCのsearch pluginの記事が少ないので1個置いときますね。