昔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クラスファイルでも同じ書き方で同様の絞り込みが実現できる。