LoginSignup
2
2

More than 5 years have passed since last update.

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

Posted at

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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2