以前、Cakephp4のカスタムファインダーを定義の記事を上げましたが、今回は更に踏み込んで【実用編】として、師匠(おにいちゃん)にご教授いただきましたので(毎度ありがとうございますm(_ _)m)、それを記事にしておければと思います。
ちなみに、カスタムファインダー定義の話についてはこちらです。
-
Cakephp4でカスタムファインダーを定義する!
続きを見る
では、Cakephpのカスタムファンダーの実用編、見ていきましょう。
カスタムファインダー実用例: 口コミに対するコメントをイメージ
カスタムファインダーを使用する際のイメージとして、「1つの口コミに複数のコメントが付けられるモデル」を考えます。コメントは論理削除を可能としておきます。
※論理削除とは、フラグ(False,Trueなど)によって削除管理をする方法。今回は削除されていない場合はnull、削除された場合は削除日が入ることにします。
CommentsTable:
以下、削除していないコメントを取得するカスタムファインダーメソッドがあるとします。
// 削除していないコメントを取得する public function findNotDeleted(Query $query, array $options) { return $query->where(['deleted IS NULL'); }
定義したカスタムファインダーメソッドをコントローラーで使用する場合、以下のようになります。
// 削除されていないコメントを取得する(カスタムファインダー経由) // このファインダーは Commentsモデルで独立しているので普通に使える。 $this->Comments->find('notDeleted')->all();
ReviewsTable: 例 - カスタムファインダーを利用しない
口コミとコメントをアソシエーションします。
public function initialize(array $config) { // 口コミは複数のコメントを持っている $this->hasMany('Comments'); }
hasManyを使ってReviewsモデルにCommentsモデルを紐づけました。(一つのレビューは複数のコメントを所持している)
論理削除したコメントは表示させたくないので、口コミ+コメントを取得する場合、カスタムファインダーを使って論理削除されたコメントを取り除きます。
// 削除されていないコメント付きで口コミを取得する (1) // https://book.cakephp.org/3/ja/orm/query-builder.html#contain $this->Reviews->find() ->contain(['Comments' => function (Query $q) { return $q->find('notDeleted'); }]) ->all();
でも、こんなことを毎度やるのは面倒くさいですよね。なので、アソシエーションの段階でカスタムファインダーを使っておけば、毎度やらなくて済みます。
ReviewsTable: アソシエーションの段階でカスタムファインダーを定義
アソシエーションの箇所で予めカスタムファインダーを定義しておきます。
public function initialize(array $config) { // 削除していないコメントのみ containさせる $this->hasMany('Comments', [ 'finder' => 'notDeleted' ]); }
次に、コントローラーでデータを取得する例です。
// 削除されていないコメント付きで口コミを取得する (2) // 論理削除を意識せずに拾ってこれる $this->Reviews->find()->contain(['Comments'])->all();
これで毎度、notDeleted を指定する必要がなくなります。
大事なのは「不要なコメントを出したくない」ファインダーの定義はCommentsモデルであって、それを使いたいモデルはそのファインダーを借りたいだけ、という点です。
カスタムファインダーを応用: ユーザーの口コミを拾ってくる
定義したコメントのカスタムファインダーメソッドを応用するとユーザーの口コミを拾ってくるという際に「論理削除された口コミ、論理削除されたコメントを拾わずにかんたんに全部拾う」ってことも出来ます。
UsersTable: ユーザー
先にReviewsモデルをアソシエートし、カスタムファインダーの「notDeleted」を指定
public function initialize(array $config) { $this->hasMany('Reviews', [ 'finder' => 'notDeleted', ]); }
ReviewsTable: カスタムファインダーメソッドを定義
口コミの論理削除されているものは取得しない条件のカスタムファインダーメソッド定義
public function findNotDeleted(Query $query, array $options) { return $query->where(['deleted IS NULL'); }
論理削除された口コミ、論理削除されたコメントは拾わない
$this->Users->find()->contain(['Reviews', 'Reviews.Comments'])->all();
もちろん、そのまま口コミを拾う際にも利用できます。
$this->Reviews->find('notDeleted')->all();
アソシエーションでカスタムファインダーを指定しない場合
アソシエーションでカスタムファインダーを指定しない場合、以下のようにコードが冗長になります。
$this->Users->find() ->contain([ 'Reviews' => function ($q) { return $q->find('notDeleted'); }, 'Reviews.Comments' => function ($q) { return $q->find('notDeleted'); }, ]) ->all();
毎度毎度、これらを書いていくことで、ある程度の規模になると、メンテナンス的にも厳しい状況になりやすいことが容易に想像できるかと思います。
最後に
フレームワークも一つの機能を使いこなすだけで、かなり便利にコードの見通しもよくなることがわかりますね。
Cakephpのカスタムファインダーメソッド、是非使いこなしましょうー!