Posted at

phpフレームワークで柔軟な検索項目条件の絞り込みを実現する方法

昔phpフレームワークを勉強している時思いついた実装方法。

とりあえずFuelPHPで書いているけど他のフレームワークでも似たような事ができるはず。


想定する対象の画面・機能

管理画面などでよくある、「複数の検索条件を任意にANDで繋げて絞り込みを行う」という機能。

例えばユーザのデータであれば


  • メールアドレスと名前の検索フォームがある

  • メールアドレスの欄にワードを入れればメールアドレスに、名前の欄にワードを入れれば名前に対する検索が実行される

  • 両方にワードを入れれば双方に一致するAND検索となる

という風な挙動を想定。


想定する検索のパターン


  • statusは完全一致する(公開、非公開など、ステータスをselectで選択する事をイメージ)

  • name, descriptionは部分一致する(入力されたキーワードと部分一致するかテキスト検索するイメージ)

  • created_atは日付の範囲内に含まれるか(登録日時が範囲指定内にあるか検索するイメージ)


実装の手順

まず、Modelクラスに検索の条件の情報を入力する。

これにより絞り込みを行うメソッドはget_by_params()


classes/model/product.php

class Model_Product extends Model_Abstract

{
protected static $_search_cond = array(
'status' => array('field' => 'status', 'pattern' => 'equal'),
'type' => array('field' => 'name', 'pattern' => 'like'),
'name' => array('field' => 'description', 'pattern' => 'like'),
'date_from' => array('field' => 'created_at', 'pattern' => 'date_larger'),
'date_to' => array('field' => 'created_at', 'pattern' => 'date_smaller'),
);

public static function get_by_params($params){
$query = self::query();
$query = self::add_query_params($params);
return $query->get();
}
}


Model_Abstractには次のような形でadd_query_params()を実装する。


classes/model/abstract.php

class Model_Abstract extends \Orm\Model_Soft

{
public static function add_query_params($query, $params){
if(!empty($params)){
$search_cond = static::$_search_cond;
foreach ($params as $key => $param){
if(empty($search_cond[$key])){
continue;
}
$field = $search_cond[$key]['field'];
$pattern = $search_cond[$key]['pattern'];
switch ($pattern){
case 'like':
// 半角スペースで区切られている場合、そのワードの分だけ分割してAND検索する。
$param_splits = explode(' ', $param);
foreach ($param_splits as $param_split){
if($param_split == ''){
continue;
}
// LIKEのワイルドカードを入力されていた場合のためエスケープ
$string = '%' . str_replace(array('%', '_'), array('\%', '\_'), $param_split) . '%';
$query->where($field, 'LIKE', $string);
}
break;
case 'equal':
// 「未指定」を'0'で表す事を想定。この方法だと0の完全一致は動作しなくなるので、例外となる文字は決めておく
if($param == '0'){
continue;
}
$query->where($field, $param);
break;
case 'date_larger':
$query->where($field, '>=', $param);
break;
case 'date_smaller':
// これは、「YYYY-mm-ddまで」と指定した時、「YYYY-mm-dd 23:59:59」までを検索範囲に含めるための措置
$date = date('Y-m-d', strtotime($param . ' + 1 Day'));
$query->where($field, '<', $date);
break;
// この他、必要に応じてINなどのパターンを追加する事も出来る。
default:
break;
}
}
}
return $query;
}
}

コントローラから次のように呼び出す。

これで、POSTパラメータに応じて自動的に絞り込み検索が実行される。


classes/controller/product.php

class Controller_Product extends Controller_Application

{
public function action_index(){
$product_data = Model_Item::get_by_params(\Input::post());
}
}


メリット


  • 原則として絞り込みの処理条件をクラス内のパラメータ記述だけで制御できる。

  • 検索条件を追加する時は$_search_condの変更だけで済むし、他のModelクラスファイルでも同じ書き方で同様の絞り込みが実現できる。