CakePHP3の検索プラグイン「friendsofcake/search」の設置方法・CakePHP3.6対応
2019/09/28
CakePHP3の検索プラグイン「friendsofcake/search」の設置方法
CakePHP3の検索プラグイン「friendsofcake/search」とは
 
CakePHP3で検索処理を実装するにあたってプラグインの利用を検討しました。
結果、CakePHP3の検索プラグインでは「friendsofcake/search」がメジャーなようでした。
 
 
CakePHP2の頃は「CakeDC/search」というプラグインを使っていまして、下記の記事などを書いていました。
CakePHP 2.3 Search Pluginで検索処理 その1設置方法
 
「CakeDC/search」同じ「CakeDC」のグループが作ったプラグインとしては、CakePHP3でも使っている「CakeDC/Users」というユーザ認証に関するプラグインがあります。
CakePHP3のユーザ管理・ログイン認証プラグインCakeDC/Usersのインストール解説・3.6以降対応
 
ですが、検索プラグインでは CakePHP3になってからは「friendsofcake/search」が主流となったようです。
 
「friendsofcake」というグループは「CakeDC」と同様、CakePHPを開発している方々が在籍しているグループのようです。
また、「friendsofcake」が作ったプラグインとしては、Bootstrapを組み込むためのプラグイン「friendsofcake/bootstrap-ui」などがあります。
CakePHP3にデザインテンプレートBootstrapを導入する方法・friendsofcake/bootstrap-ui使用
 
 
実際に「friendsofcake/search」を使ってみた感じでは、「CakeDC/search」よりも簡単に導入することができ、各条件に合わせたカスタマイズも簡単にできる感じがします。
検索処理のような汎用的な処理は、オリジナルの処理を作るよりプラグインを使うほうが効率的に開発を進めることができるでしょう。
 
 
ちなみに、CakePHP3.6になったときに「friendsofcake/search」の設置方法も変わったと思われ、CakePHP3.6がリリースされた 2018年4月14日以前に書かれた記事のソースコードでは動作しないものが多々ありました。
参考にする際は記事が書かれた日付を確認したほうが良さそうです。
 
この記事は、CakePHP3.7で動作確認しながら書いています。
 
 
CakePHP3の検索プラグイン「friendsofcake/search」の導入手順
 
この章では、「friendsofcake/search」を導入する基本的な手順を解説します。
 
次の章で、記述方法のバリエーションや不具合が発生した場合の対応方法について解説します。
 
 
1.Composerを使って「friendsofcake/search」をインストール
 
まずはじめに、下記のコマンドを実行し、「friendsofcake/search」をインストールします。
コマンドを実行する場所は、アプリケーションのルートフォルダです。
 
| 
					 1  | 
						$ composer require friendsofcake/search  | 
					
 
CakePHP3でプラグインやライブラリをインストールする際には Composerを使うと便利ですが、これまでに Composerがよくわからない方は下記を参照してください。
CakePHP3でcomposerを利用してライブラリ・プラグインをインストールする方法
 
 
2.「friendsofcake/search」をロード
 
次に、インストールした「friendsofcake/search」をプログラム内で使用するためにロードする設定を記述します。
 
/src/Application.php
に下記の処理を追加します。
 
| 
					 1 2 3 4 5 6 7  | 
						public function bootstrap() {        :     (既存の処理)        :     $this->addPlugin("Search");   // この行を追加する  | 
					
 
 
ここでは「/src/Application.php」ファイルに手作業で記述しましたが、コマンドラインから下記のコマンドを実行しても OKです。結果は同じになります。
 
| 
					 1  | 
						$ bin/cake plugin load Search  | 
					
 
 
3.Model(Table)に検索処理を追加
 
Model(Table)にビヘイビアと検索条件の追加を行います。
 
/src/Model/Table/TestsTable.php
に下記の処理を追加します。
 
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  | 
						    public function initialize(array $config)     {            :         (既存の処理)            :         // ビヘイビア(friendsofcake/search)の追加         $this->addBehavior("Search.Search");         // 検索条件の追加         $this->searchManager()             ->like("title",[                 "before" => true,                 "after" => true             ]);  | 
					
 
「ビヘイビアの追加」と「検索条件の追加」の処理を追加します。
 
「検索条件の追加」の箇所は実際に検索する条件に合わせて設定を変更する箇所です。
ここでは「title」という項目を「like検索」する設定になっています。また、「before」「after」を追加して、対象文字列の中の何処かに一致すればいい「中間一致検索」になる設定になっています。
 
最初の設置の際は、動作確認ができる最低限の項目にしておくことをオススメします。
 
 
また、「検索条件の追加」の部分を「initialize()」メソッドの中に書かずに、function()として独立して記述する方法もあります。
記述するファイルは、変わらず「/src/Model/Table/TestsTable.php」の中です。
 
| 
					 1 2 3 4 5 6 7 8 9 10 11  | 
						    // 検索条件の追加     public function searchManager()     {         $searchManager = $this->behaviors()->Search->searchManager();         $searchManager             ->like("title",[                "before"=>true,                "after"=>true             ]);         return $searchManager;     }  | 
					
 
 
4.Controllerに検索処理を追加
 
Controllerに検索処理を追加します。
 
/src/Controller/TestsController.php
に下記の処理を追加します。
 
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29  | 
						class TestsController extends AppController {     // ページング設定の追加     public $paginate = [         "limit" => 100         ];     public function initialize()     {         parent::initialize();         // 検索処理のロードの追加         $this->loadComponent("Search.Prg", [             "actions" => ["index"]    // ここで検索するアクションを配列で指定         ]);     }     public function index()     {         // Bakeしたときに生成された元の処理 //      $tests = $this->paginate($this->Tests);         // 上記の元の処理を下記に変更         $query = $this->Tests             ->find("search",["search"=>$this->request->getQuery()]);         $tests = $this->paginate($query);         $this->set(compact("tests"));     }  | 
					
 
「ページング設定の追加」は、設定内容の変更をしたい場合に追加します。
なくても動作しますので、最初の動作確認の段階ではなくても問題ありません。
 
「検索処理のロードの追加」では、検索処理を追加するアクションを指定します。
今回は「index」アクション内で検索処理を行いますのでそれを指定しています。
 
また、「index()」アクション内では、レコードを取得するクエリーに検索条件を含む「find()」句を追加します。
 
 
ちなみに、「initialize()」メソッド内の「検索処理のロードの追加」の「"actions" => ["index"]」は、デフォルト設定は「"actions" => ["index","lookup"]」となっています。
 
下記のように「actions」の部分をコメントにしても、「index」「lookup」アクション内であれば検索処理は動作します。(とは言え、明示しておくほうが無難ですが。)
 
| 
					 1 2 3 4  | 
						        // 検索処理のロードの追加         $this->loadComponent("Search.Prg", [ //          "actions" => ["index"]    // ここで検索するアクションを配列で指定         ]);  | 
					
 
ちなみに、「$this->loadComponent();」の処理は記述しないと検索できません。
 
 
5.Templateに検索条件のテキストボックスを追加
 
最後に、Templateに検索条件を入力するテキストボックスを追加します。
 
/src/Template/Tests/index.ctp
に下記の処理を追加します。
 
| 
					 1 2 3 4 5 6 7 8  | 
						<div>   <?php     echo $this->Form->create(null, ["valueSources" => "query"]);     echo $this->Form->input("title");     echo $this->Form->button(__("Search"), ["type" => "submit"]);     echo $this->Form->end();   ?> </div>  | 
					
 
4行目は、検索対象となる項目を指定してください。
 
上記の設定であれば、検索条件のテキストボックスに入力した文字列は、検索結果のページにも表示されます。
古いサイトを参考にすると「$this->Form->create()」と書いてある場合もありますが、その記述だけでは、検索結果ページのテキストボックスに入力した文字列が編集されませんので注意をしてください。
 
| 
					 1 2 3 4 5  | 
						// 間違い echo $this->Form->create(); // 正解! echo $this->Form->create(null, ["valueSources" => "query"]);  | 
					
 
もしくは、下記の設定でも OKです。
 
| 
					 1 2 3 4 5 6  | 
						// 間違い echo $this->Form->create(); // 正解! echo $this->Form->create(); $this->Form->setValueSources("query");   // この行を追加する  | 
					
 
 
テキストボックスなどをカスタマイズしたい場合は、下記に Form Helperの使い方の記事を書いていますので、こちらを参考にしてください。
CakePHP3のForm Helperの使い方のまとめ
 
 
アンカーリンク付きのフォームタグを生成する方法
 
パソコンのブラウザではあまり気になりませんが、スマホで検索をした場合、ページの一番上に戻ってしまい、検索結果の一覧のところまで画面をスクロールさせるのが面倒、という場合がありました。
 
そんなときは、アンカーリンク(ページ内リンク)を設定しようと思いましたが、ちょっと悩んだところでもありましたのでここに追記しておきます。(2019.09.28 追記)
 
アンカーリンクを設定する方法は簡単です。
通常はリンク先を設定する「action」属性(フォームの POSTする先の URLを指定する箇所)に「#search」のようにアンカーリンク先を指定するだけです。
 
| 
					 1  | 
						echo $this->Form->create(null, ["valueSources"=>"query","url"=>"#search"]);  | 
					
 
上記のように設定すると、下記のような HTMLが生成されます。
 
| 
					 1  | 
						<form method="post" accept-charset="utf-8" role="form" action="#search">  | 
					
 
これで検索を実行すると、検索処理が行われ、アンカーリンクを設定しているところに画面がスクロールして表示されます。
 
「"url"=>"#search"」を設定すると、検索クエリーが処理されないのではないか、とも思っていましたが、全くそんな心配はいりませんでした。
 
 
ちなみに、アンカー側の記述は HTMLのタグとして下記のように記述します。
 
| 
					 1  | 
						<a name="search"> </a>  | 
					
 
cakephp3の HTML Helperで記述する方法を調べてみましたが、よく分かりませんでした。
 
 
CakePHP3の検索プラグイン「friendsofcake/search」の導入方法のバリエーション
 
前の章では、検索プラグイン「friendsofcake/search」の基本的な導入方法を解説しました。
ですが、「friendsofcake/search」の導入方法は単一ではなく、いくつものバリエーションが存在しますので、それらの方法を解説します。
 
 
Model(Table)の記述を以前の記述方法で踏襲する
 
以前は、検索条件を「searchConfiguration()」の中に記述する方法がありました。
その方法を踏襲する場合は、下記のように記述することで実現できます。
 
/src/Model/Table/TestsTable.php
に下記の処理を追加します。
 
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18  | 
						    public function initialize(array $config)     {            :         (既存の処理)            :         // ビヘイビアの追加(friendsofcake/search)         $this->addBehavior("Search.Search");         // 検索条件の追加         $this->searchConfiguration();     }     // 検索条件の追加     public function searchConfiguration()     {         $this->searchManager()->like("title",["before"=>true,"after"=>true]);     }  | 
					
 
 
Controllerに追加する検索処理のバリエーション
 
Controllerに記述する検索処理は多様な記述の仕方があります。
各人で好みの記述方法があると思いますので、それに合わせた記述方法を試してみてください。
 
 
Controllerに追加する検索処理ですが、$queryの記述の方法を 2分割すると下記のような記述になります。
 
| 
					 1 2  | 
						        $filter = ["search"=>$this->request->getQuery()];         $query = $this->Tests->find("search", $filter);  | 
					
 
 
また、クエリ文字列(クエリストリング、URLパラメーター)を取得する方法は、CakePHP3.4で新しい方法が追加されていますので、CakePHP3.4以降を使っているのであれば、新しい方をオススメします。
 
| 
					 1 2 3 4 5 6 7 8 9  | 
						// CakePHP3.4 以降 $filter = ["search"=>$this->request->getQuery()]; // もしくは // CakePHP3.4 以降 $filter = ["search"=>$this->request->getQueryParams()]; // CakePHP3.4 より前 $filter = ["search"=>$this->request->query];  | 
					
 
 
また、テーブルの連携先(アソシエーション)の情報も取得したい場合は、「contain()句」を利用しますが、これも連結させるだけで OKです。
 
| 
					 1 2 3  | 
						        $query = $this->Tests             ->find("search",["search"=>$this->request->getQuery()])             ->contain(["Users"]);  | 
					
 
 
検索プラグイン「friendsofcake/search」導入方法時にエラーが発生した!
 
記事の最初に「friendsofcake/search」の導入は簡単でした、と書きましたが、実はエラーが消えなくて延々と悩んでいました。
 
実は、CakePHP3.6以降では少し記述の方法が変更になったのですが、それを分かっておらず、古い記述の方法で書いていたためでした。
 
プラグインの実装の実験などをしている別の環境に、別の記述方法で導入を試してみたらあっさりと動いたため、「この違いはなんなんだ??」と調べていくと、バージョンの違いによって記述の仕方が違う、ということが分かりました。
そんなワケで、CakePHP3に関する記事はなるべく新しい記事を参考にしたほうがいいのかもしれませんね。(そのためには、記事には投稿日時が欠かせませんね。)
 
 
で、そんなこんなで発生したエラーの紹介です。
 
「Custom finder “search” expects search arguments to be nested under key “search” in find() options.」のエラー
 
「friendsofcake/search」を組み込んで動作させると、下記のエラーが発生しました。
Error: [Exception] Custom finder "search" expects search arguments to be nested under key "search" in find() options.
 
私は、TestController.phpの index()アクションの中の処理で下記のように書いていました。
 
| 
					 1 2 3  | 
						        $filter = $this->request->getQuery();         $query = $this->Tests->find("search", $filter)->contain(["Users"]);         $bookmarks = $this->paginate($query);  | 
					
 
先に紹介した「$filter」の設定内容を見比べてもらうと分かるのですが、「$filter」に設定する方法が少し変わったようです。
 
| 
					 1 2 3 4 5  | 
						        // 正解         $filter = ["search"=>$this->request->getQuery()];         // 間違い         $filter = $this->request->getQuery();  | 
					
 
CakePHPのことをより分かってそうな方が書いているサイトだったのでそれを信じてしまっていましたが、分かったときには「バージョンが古かったんかぁーーいっ!!」という感じでした。
 
 
検索プラグイン「friendsofcake/search」のカスタマイズについて
 
この記事では、CakePHP3の検索プラグイン「friendsofcake/search」を設置して動作させるための基本的な解説を行いました。
記事が長くなりすぎるための実用的なカスタマイズに関しては下記の記事で改めて書いていますので、こちらを参考にしてください。
CakePHP3の検索プラグイン「friendsofcake/search」の様々な検索の仕方の実装方法
CakePHP3のfriendsofcake/searchでブックマークチュートリアルのタグ検索を実装
CakePHP3のfriendsofcake/searchでツリーカテゴリーの子階層も含めて検索する方法
 
 
CakePHP3の関連記事
CakePHP4のCSS、JavaScript、画像のブラウザへのキャッシュをコントロールするCakePHP3でレコードを保存(追加、更新、Insert、Update)する複数の方法を紹介
CakePHP3でモデルなしフォームからCSVをアップロードしレコードを更新する方法解説
CakePHP3でPHP Simple HTML DOM Parserを使ってスクレイピングする方法
CakePHP3のInsert On Duplicate Key Update(upsert)構文を解説・バルク処理も
CakePHP3の1対多での連携を中間テーブルを使った多対多の連携に変更するときの手順
CakePHP3でデフォルトのソート条件を設定してユーザの選択肢たソート条件を有効にする方法
CakePHP3で Ajaxを使う方法の解説。3.6以降対応。Successとthenの両方を解説。
CakePHP3でパンくずの指定は HTMLヘルパーを使って指定する方法を解説
CakePHP3にOGPをfetch、asignを利用してテンプレートごとに指定する方法を解説
その他の「CakePHP3」に関する記事一覧
GoogleAdwords
GoogleAdwords
この記事が参考になったと思いましたらソーシャルメディアで共有していただけると嬉しいです!
関連記事
-  
            
 - 
      
CakePHP3のCakeDC/Usersの画面、メール本文テンプレートのカスタマイズ方法解説
CakeDC謹製Usersプラグインの紹介。ユーザ新規登録の流れを紹介しつつテンプレートファイルがどこにあるか、設定情報ファイルがどこにあるか、を説明しつつカスタマイズの方法を解説します。
 
-  
            
 - 
      
Google Analytics APIを CakePHP3で動かしてレポートデータを取得する方法の解説
CakePHP3で Google Analytics APIからレポートデータを取得する処理の解説。PHPのサンプルソースをCakePHP3で動くように改造。加えて、ディメンションやメトリックスを条件に設定する方法なども。
 
-  
            
 - 
      
CakePHP3でQRコードを作成、表示するライブラリ「cakePHP-QR-Code-Helper」
CakePHPでQRコードを生成するライブラリ「cakePHP-QR-Code-Helper」の紹介。GDライブラリのインストールも必要ないHelperとして提供されているため、ファイルを設置すればすぐに使用可能。
 
-  
            
 - 
      
CakePHP3のUpload Plugin 3.0をバリデーションなど実運用向けのカスタマイズ方法解説・その2
CakePHP3でファイル、画像をアップロードするプラグイン、upload plugin 3を導入する手順を解説した記事。3部作のその2でバリデーションなどの実用的なカスタマイズ方法を解説。
 
-  
            
 - 
      
CakePHP 2.3でファイルをアップロード・その2 ファイル名を乱数で設定
CakePHPのアップロードするファイル名を乱数で変更しセキュリティを高める方法を解説。
 
-  
            
 - 
      
CakePHP 2.3 テーブルの項目を演算した結果を条件として抽出する方法
アソシエーション(連携)している先のテーブルの項目で演算をする場合の考え方と注意点をサンプルソースを用いて説明しています。分かってしまえば簡単です。
 
-  
            
 - 
      
CakePHP3のForm Helperの使い方のまとめ
CakePHP3になりフォームヘルパーの使い方も大きく変わりましたので、使い方をまとめました。基本的な使い方からプラスアルファの便利な使い方まで紹介。
 
-  
            
 - 
      
CakePHP3でDocumentRootやwebroot、imgフォルダのURLやドメイン、パスを取得
URLやドメイン、フォルダへのパスの取得は、ビューではUrlHelperを使い、コントローラーではRouterクラスを使います。第2引数の指定でURLを取得することも可能。
 
-  
            
 - 
      
CakePHP3のタイムゾーンを協定世界時UTCから日本標準時間JSTにずれを変更する方法
CakePHP3の標準設定のタイムゾーンは「UTC(協定世界時)」に設定されている。これを日本標準時に変更する方法(app.php、bootstrap.phpの変更方法)の解説。
 
-  
            
 - 
      
CakePHP5でヘルパーから他のヘルパーを読み込む方法・CakePHP4からの変更点
CakePHP5のヘルパーで他のヘルパーを読み込む方法を解説。公式の日本語CookbookはCakePHP4のソースのままで間違っているため注意が必要。CakePHP4からの移行の際も同じ点に注意が必要。