m-shimaoと申します。
この記事はCakePHP3 Advent Calendar 2016の10日目の記事となります。
(Fusic Advent Calendar 2016の記事でもあります。)
本日は稚拙ながら私がついさっき作ったFileCacheを使ったプラグインの紹介をさせて頂きたいと思います。
プラグイン
できること
- 特定のテーブルでaddBehavior()すれば、そのテーブルへのfind()がFileCacheを利用したものになる
- まだテストが書けてないので全パターンを確認できてないけど、複雑なクエリじゃなければ大丈夫なはず…
- そのため、そのテーブルに対してselectクエリをたくさん投げてもパフォーマンス的にはあまり気にしなくてよくなる。
- 作ったばかりでまだサービスでの稼働実績がないので、使われる方はお気をつけください
インストール方法
m-shimao/find-in-file-cacheのREADMEをご参照ください
使い方
いま使いたいテーブルがcategoriesテーブルだとすると、
Model/Table/CategoriesTable.phpにてaddBehavior()を追加すれば使えます。
<?php
class CategoriesTable extends Table
{
public function initialize(array $config)
{
$this->addBehavior('FindInFileCache.FindInFileCache');
}
}
find()を投げると、beforeFind()の中で既にFileCacheにデータがあるかをチェックし、
該当するデータが有ればそのデータを返して以降のイベントを行わないような動きをします。
FileCacheに無ければ、通常通りfindを実行後FileCacheにデータをキャッシュします。
キャッシュの有効期間はデフォルトで15分としています。
その他キャッシュの設定を変更したい場合はapp.phpでfind-in-fileというキーでキャッシュの設定を追加して頂ければ
そちらの設定を見に行くようになります。設定例↓です。
<?php
return [
...
'Cache' => [
...
'find-in-file' => [
'className' => 'File',↲
'className' => 'File',↲
'prefix' => 'myapp_cake_static_record_',↲
'path' => CACHE . 'models/', //pathをmodelsと同じにする↲
'duration' => '+1 hours',↲ // cacheの有効期間を1時間にする
],
...
],
...
];
注意点
- 対象のテーブルは基本的にデータが変わらないもの or データが変更されてもすぐに反映される必要が無いものを想定しています。
例えばbookmarksなど頻繁に更新されるテーブルに対して設定しても使いものにならないと思うので、
お使いの際はテーブルの性質をご考慮ください - join等にも対応しているはずですが、まだテストできていません…。余り複雑なクエリでは使わないほうがよいかもしれません。
開発でハマった点
もともとQueryオブジェクトに
$query->cache($cacheKey);
とするとcacheからデータのfetch・データのstoreをうまいことfindの前・後に挟んでくれるようになるメソッドがあるので
それを使えば簡単に実装できそうだと思っていたのですが、
cacheからのfetchのタイミングがbeforeFindの前だったので、うまく使えませんでした…。
結局上述のようにbeforeFindの中でキャッシュにアクセスして、あったら以降のイベントをStopするような実装にしました。
(2017/1/31追記) コメント頂いた件の改修
- 間が空いてしまいましたが…、@chinpei215さんよりご指摘頂いた下記の2点に対して対応しました
- mapReduce(), formatResults()がセットされているクエリの場合に実行の度にデコレードが実行されてしまい、結果セットが壊れてしまうバグ
- 同じクエリオブジェクトで二回以上クエリが実行される場合に、2回目以降はcacheを無効化する対応
今後の改修予定
- テストコードの追加。合わせてある程度複雑なクエリへの対応
- cacheを使用しないオプションの追加。
- データがsaveされたらキャッシュを削除する処理を追加。
- いまはクエリの内容毎にキャッシュのキーを変えているのですが、クエリはfind()->all()だけに統一して、その結果セットをwhere句やorder句などの内容に応じてゴニョニョして返すようにしたいです。
雑記
- 昨日はymm1x様のCakePHP3のbakeによるコード自動生成のプラクティスでした。
ちょうど業務で「そろそろbakeいじるか〜」と思っていたタイミングだったので、大変参考になりました - 実は元々クエリログを簡単に出すプラグインを作ろうと思っていたのですが、4日目のYKEI_mrn
様のCakePHP3 のログをためすを見てapp.phpの設定だけでできることを恥ずかしながら初めて知りました。 - 何が言いたいかというと、Advent Calendar登録すると内容が被らないようにこれまでの記事を一通りみるので、すごくためになるなぁと思ったのでした