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) finderCompare
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 thefield
option, for example when it is being used to define multiple fields, which is supported by theLike
filter.alwaysRun
(bool
, defaults tofalse
) Defines whether the filter should always run, irrespectively of whether the corresponding field exists in the request data.filterEmpty
(bool
, defaults tofalse
) 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 totrue
) 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 tonull
) 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 tofalse
) 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 thedefaultValue
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 basefield
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 thefieldMode
option.before
(bool
, defaults tofalse
) Whether to automatically add a wildcard before the search term.after
(bool
, defaults tofalse
) Whether to automatically add a wildcard after the search term.mode
(string
, default toor
) This options is deprecated, please usefieldMode
instead.fieldMode
(string
, defaults toor
) The conditional mode to use when matching against multiple fields.valueMode
(string
, defaults toor
) The conditional mode to use when searching for multiple values.comparison
(string
, defaults toLIKE
) 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 appropriateLIKE
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 towildcardAny
, that is, the actualLIKE
compatible wildcard (_
) is being escaped in case used the search term.
Value
multiValue
(bool
, defaults tofalse
) 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 thedefaultValue
option.mode
(string
, possible values areor
andand
, defaults toor
) 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.