スポンサーリンク

CakePHP3.3でfriendsofcake/search (ver2.3)の使い方メモ

Web開発

CakePHPに限らず、全てのCMSやフレームワークで問題になるのは、フレームワークのアップデートですね。PHPのバージョンアップも相まって、現場はいつも頭を抱える事になります。

Laravel程ではありませんが、CakePHPも使い方や仕様が変わり、プラグインもそれに追随して変更になりました。よく使うFriendsOfCake/searchもCakePHP3.6のタイミングで使用法が変わり戸惑っています。しばらくアップデートする時間も無いので、旧版のFriendsOfCake/searchの使い方をまとめておこうと思います。今回はCakePHP3系で自分の周りでの使用者が多いCakePHP3.0~3.3に対応していたFriendsOfCake/search2.3系を、本家説明を翻訳しながら見直していきます。(途中)

本家の説明
https://github.com/FriendsOfCake/search/tree/2.3.0

 

スポンサーリンク

インストール方法

インストールはcomposerで行います。
作成しているCakePHP プロジェクトルートディレクトリ(composer.jsonがある場所)に移動し、下記コマンドを実行。

php composer.phar require friendsofcake/search

※このコマンドでは最新版がインストールされます。

インストールが完了したら以下のコマンドを実行します。

./bin/cake plugin load Search

すると「config/bootstrap.php」ファイルに、以下の記述が追記されます。
上記のコマンドを実行しなくても、自分で直接記入してもOKです。

Plugin::load('Search');
スポンサーリンク

使い方

このプラグインは、3つの要素で構成されて部分があり、これらを構成してアプリケーションに含める必要があります。

テーブルクラス(Table class)設定

テーブルクラスのセットアップは、主に3つの手順が必要です。
1、使用するモデルのテーブルクラスに use Search\Managerステートメントを追加
2、検索のフィルタリングをテーブルクラスのfunction initializeに記述
3、検索フィルターを設定

フィルタリング条件の追加は、メソッドチェーン記法で行います。add()メソッドを使用してフィルターを追加したり、組み込みフィルター用にvalue()、like()などの特定のメソッドを使用したりできます。

add()メソッドの1番目の引数はフィールド、2番目の引数はケーキのドット表記を使用してプラグインからフィルターをロードするフィルターです。 3つ目は、フィルター固有のオプションの配列です。さまざまなフィルタでサポートされている利用可能なオプションの説明については、「オプション」セクションを参照してください。

<?php
//MyCakeProject/src/Model/Table/ExamplesTable //テーブルクラスに設定
namespace App\Model\Table;
use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;

use Search\Manager; //★追記する

class ExampleTable extends Table {

    public function initialize(array $config)
    {
        parent::initialize();

        //★検索対象のテーブルクラスに検索プラグインのビヘイビアを追加
        $this->addBehavior('Search.Search');

        //★フィルタリングの条件を記述
        $this->searchManager()
            ->value('author_id')
            //LIKE検索を使うための記載 add('q1','Search.Like')について
            //ここで'q1'は、フォームからのパラメタ指定変数
            //以下の例では'q1'に指定された文字列を、'title'と'Authors.name'に対して検索
            //結合先テーブルのフィールドを検索するには'Authors.name'と指定する
            ->add('q1', 'Search.Like', [
                'before' => true,
                'after' => true,
                'fieldMode' => 'or',
                'comparison' => 'LIKE',
                'wildcardAny' => '*',
                'wildcardOne' => '?',
                'field' => ['title', 'Authors.name']
            ])
            //独自検索を行う場合の add('q2','Search.Callback')について 
            //ここで'q2'は、フォームからのパラメタ指定変数 
            ->add('q2', 'Search.Callback', [
                'callback' => function ($query, $args, $filter) {
                    // Modify $query as required
                }
            ]);
    }

initialize()メソッド内に、上記のプラグイン設定を長々と記載したくない場合は、代わりにテーブルクラスにsearchConfiguration()メソッドを作成し、検索プラグインの設定を独立して記述できます。このメソッドは、検索マネージャーインスタンスを返す必要があります。

なお、メソッドの名前を変更する必要がある場合、または複数のメソッドを持ち、それらを切り替える場合は、動作オプションのsearchConfigMethodを目的のメソッドの名前に設定することで、メソッドの名前を構成できます。

use Search\Manager;

class ExampleTable extends Table {

    public function searchConfiguration()
    {
        $search = new Manager($this);

        $search->like('title');

        return $search;
    }
}

コントローラーの設定

検索プラグインを使用するためには、URLで渡されるクエリパラメータを処理する必要があります。一般的には検索一覧画面となるindex()画面で、これに対応するようにインデックスメソッドを編集していく必要があります。

public function index()
{
    $query = $this->Articles
        // 第1引数、カスタムファインダーで'search'プラグインを使用する設定記述。
        // 第2引数、検索クエリの配列
        ->find('search', ['search' => $this->request->query])

        // 一般的なcakeのカスタムファインダーと同じく、containやwhere句も使用ok
        ->contain(['Comments'])
        ->where(['title IS NOT' => null]);

    //Viewに取得結果を渡す時も、cakeのカスタムファインダーと同じ。
    $this->set('articles', $this->paginate($query));
}

Searchプラグインのビヘイビアにより、CakePHPの finderは動的に検索条件を生成します。

もし、Friendsofcake/Crudプラグインを使用している場合は、CrudアクションでListenerを有効にする必要があります。詳しくはCrudプラグインの説明を参照してください。
https://github.com/FriendsOfCake/crud

initializeクラスの設定

コントローラクラスのイニシャライズには、サーチプラグインを使用したいメソッドをSearch Prgコンポーネントを追加ておきます。

public function initialize()
{
    parent::initialize();
    $this->loadComponent('Search.Prg', [
        // 下記の場合は、indexメソッドとlookupメソッドでプラグインが使用可となる。
        // 必要に応じて、addやeditなど、使用したいメソッドを追記する
        'actions' => ['index', 'lookup']
    ]);
}

Search.Prgコンポーネントを使用すると、クエリパラメータのデータを使用してフィルタリングフォームにデータを入力できます。Get、Post、Redirectにより、渡されたデータがフィルタリングに利用できます。

フィルタリングの方法

Once you have completed all the setup you can now filter your data by passing query params in your index method. Using the Article example given above, you could filter your articles using the following.

example.com/articles?q=cakephp

Would filter your list of articles to any article with “cakephp” in the title or content field. You might choose to make a get form which posts the filter directly to the URL, but if you’re using the Search.Prg component, you’ll want to use POST.

Creating your form

In most cases you’ll want to add a form to your index view which will search your data.

    echo $this->Form->create();
    // You'll need to populate $authors in the template from your controller
    echo $this->Form->input('author_id');
    // Match the search param in your table configuration
    echo $this->Form->input('q');
    echo $this->Form->button('Filter', ['type' => 'submit']);
    echo $this->Html->link('Reset', ['action' => 'index']);
    echo $this->Form->end();

If you are using the Search.Prg component the forms current values will be populated from the query params.

検索のリセット

If you pass down the information on whether the query was modified by your search query strings, you can also include a reset button only if necessary:

// in your controller action
$this->set('isSearch', $this->Articles->isSearch());

Then one can switch based on that in the template:

// in your form
if ($isSearch) {
	echo $this->Html->link('Reset', ['action' => 'index']);
}

検索抽出フィルターの色々

検索フィルターのセットが付属しています

  • Value 完全一致するものを抽出( idや区分値等に利用)
  • Like 部分一致を抽出、前方一致や後方一致等をオプション指定可能
  • Boolean to limit results by truthy (by default: 1, true, ‘1’, ‘true’, ‘yes’, ‘on’) and falsy (by default: 0, false, ‘0’, ‘false’, ‘no’, ‘off’) values which are passed down to the ORM as true/1 or false/0 or ignored when being neither truthy or falsy.
  • Finder to produce results using a (custom) finder
  • Compare to produce results requiring operator comparison ( ><>= and <=)
  • Callback to produce results using your own custom callable function

Options

All filters

The following options are supported by all filters.

  • field (string, defaults to the name passed to the first argument of the add filter method) The name of the field to use for searching. Use this option if you need to use a name in your forms that doesn’t match the actual field name.
  • name (string, defaults to the name passed to the first argument of the add filter method) The name of the field to look up in the request data. Use this option if you need to configure the name of the filter differently than the name of the field, in cases where you can’t use the field option, for example when it is being used to define multiple fields, which is supported by the Like filter.
  • alwaysRun (bool, defaults to false) Defines whether the filter should always run, irrespectively of whether the corresponding field exists in the request data.
  • filterEmpty (bool, defaults to false) Defines whether the filter should not run in case the corresponding field in the request is empty. Refer to the Optional fields section for additional details.

The following options are supported by all filters except Callback and Finder.

  • aliasField (bool, defaults to true) Defines whether the field name should be aliased with respect to the alias used by the table class to which the behavior is attached to.
  • defaultValue (mixed, defaults to null) The default value that is being used in case the value passed for the corresponding field is invalid or missing.

Compare

  • operator (string, defaults to >=) The operator to use for comparison. Valid values are >=<=> and <.

Like

  • multiValue (bool, defaults to false) Defines whether the filter accepts multiple values. If disabled, and multiple values are being passed, the filter will fall back to using the default value defined by the defaultValue option.
  • ※ver4.5.0から、multiValueSeparator という機能が追加され、「りんご、ばなな」のような複数の検索語を扱うことができるようになっています。できればアップデートしたいですが、ver4.5.0はCakePHP3.5以降の対応の様で、本体アップデートのコストとのトレードオフが発生します。現状の仕様で複数の検索語を扱うには、CallBackやFinderで自前処理が必要です。
  • field (string|array, defaults to ) The name of the field to use for searching. Works like the base field option but also accepts multiple field names as an array. When defining multiple fields, the search term is going to be looked up in all the given fields, using the conditional operator defined by the fieldMode option.
  • before (bool, defaults to false) Whether to automatically add a wildcard before the search term.
  • after (bool, defaults to false) Whether to automatically add a wildcard after the search term.
  • mode (string, default to orThis options is deprecated, please use fieldMode instead.
  • fieldMode (string, defaults to or) The conditional mode to use when matching against multiple fields.
  • valueMode (string, defaults to or) The conditional mode to use when searching for multiple values.
  • comparison (string, defaults to LIKE) The comparison operator to use.
  • wildcardAny (string, defaults to *) Defines the string that should be treated as a any wildcard in case it is being encountered in the search term. The behavior will internally replace this with the appropriate LIKE compatible wildcard. This is useful if you want to pass wildcards inside of the search term, while still being able to use the actual wildcard character inside of the search term so that it is being treated as a part of the term. For example a search term of * has reached 100% would be converted to % has reached 100\%.
  • wildcardOne (string, defaults to ?) Defines the string that should be treated as a one wildcard in case it is being encountered in the search term. Behaves similar to wildcardAny, that is, the actual LIKE compatible wildcard (_) is being escaped in case used the search term.

Value

  • multiValue (bool, defaults to false) Defines whether the filter accepts multiple values. If disabled, and multiple values are being passed, the filter will fall back to using the default value defined by the defaultValue option.
  • mode (string, possible values are or and and, defaults to or) The conditional mode to use when searching for multiple values.

Optional fields

Sometimes you might want to search your data based on two of three inputs in your form. You can use the filterEmpty search option to ignore any empty fields.

// ExampleTable::initialize()
    $searchManager->value('author_id', [
        'filterEmpty' => true
    ]);

Be sure to allow empty in your search form, if you’re using one.

echo $this->Form->input('author_id', ['empty' => 'Pick an author']);

Persisting the Query String

Persisting the query string can be done with the queryStringWhitelist option. The CakePHP’s Paginator params sort and direction when filtering are kept by default. Simply add all query strings that should be whitelisted.