管理画面で記事をデータベースに保存して、フロントサイドで記事を閲覧できるサイトを構築していました。
フロントサイドでwebサイトにアクセスした時に、記事の一覧を表示するために必要なデータをキャッシュに保存して、ページ遷移時にそのデータを使用して表示させておりました。
(一覧を表示するために必要なデータが、仕様の関係で少し重いクエリを発行しなければならないため、最新の情報をキャッシュに保存しておくという手法を取りました。)
(CakePHP v3.4.4)
目次
afterSave/afterDeleteイベントでキャッシュを削除させたい
やりたかったことは、管理画面で記事の登録、更新、削除をした時に、それまでのキャッシュを一旦クリアして、フロントサイドで再度データを生成し、キャッシュに保存し直すように実装することです。
今回は、afterDeleteとafterSaveを組み込んだBehaviorを作成し、AtriclesTableでBehaviorを読み込んでいます。
実装したコードはこちら
【CacheDeleteBehavior.php】
use Cake\ORM\Behavior;
use Cake\ORM\Table;
use Cake\Event\Event;
use Cake\ORM\Query;
use Cake\Cache\Cache;
class CacheDeleteBehavior extends Behavior
{
public function afterDelete(Event $event)
{
Cache::delete('data’,’articledata');
Cache::delete('data_admin’,’articledata');
}
public function afterSave(Event $event)
{
Cache::delete('data’,’articledata');
Cache::delete('data_admin’,’articledata');
}
}
【ArticlesTable.php】
public function initialize(array $config)
{
・・・
・・・
・・・
$this->addBehavior('CacheDelete');
・・・
・・・
・・・
}
上記の設定をしておけば、ArticlesTable内で何らかの更新をかけた際に、指定のキャッシュが削除されるはず。
なぜかキャッシュがクリアされない
しかし、管理画面で記事の更新をかけているにも関わらず、キャッシュが古いまま更新されないことがありました。
afterDeleteの書き方が悪かったのか、
初めて使ったBehaviorの書き方が悪かったのか、
キャッシュ削除の書き方が悪かったのか、
再現させるために色々と試してみました、、、。
deleteAllはafterDeleteイベントを呼ばない
データ削除時にafterDeleteが呼ばれていない模様、、、。
さらにdeleteAll実行時にafterDeleteが呼ばれていない模様、、、。
、、、、CakePHP 3.X Cookbookを確認してみました。
しっかりと記載がありました。
「deleteAll は、beforeDelete/afterDelete イベントを 呼び出しません 。 それらのイベントを呼び出したい場合、それぞれのレコードを読み込んで削除する必要があります。」
出典:CakePHP 3.X Cookbook データの削除
やっと原因にたどり着きました。
今回はdeleteAll実行時に、個別にキャッシュを削除する処理を加えることで対応しました。
afterDeleteを呼べるようにできるか
余談ですが、この件について色々調べてみたところ
CakePHPのv.3.X以降からdeleteAllに渡せる引数が変更されていることに気づきました。
CakePHP 2.X Cookbookによると
「deleteAll(mixed $conditions,$cascade = true, $callbacks = false)」
CakePHP 3.X Cookbookによると
「deleteAll($conditions)」
念のためCakePHP3でdeleteAllを定義しているファイルを参照してみると
【/vender/cakephp/cakephp/src/ORM/Table.php】
/**
* {@inheritDoc}
*/
public function deleteAll($conditions)
{
$query = $this->query()
->delete()
->where($conditions);
$statement = $query->execute();
$statement->closeCursor();
return $statement->rowCount();
}
確かにそのようです。
この件を調査している途中で、deleteAllの引数の$callbacksをtrueにして渡してあげるとafterDeleteを呼ぶことができるという記事をいくつか見たことがあったので、上記を確認するまでは少し迷走しました。
どのみち今回はそれができなそうなので、deleteAll時に個別に処理を実行させるしかなさそうです。
まとめ
deleteAll時にafterSave/afterDeleteは呼ばれない
バージョン等、自分の環境に沿って調べていかないと、いろんな情報が混在して迷走してしまうことを再認識しました。
参考文献
CakePHP 3.X Cookbook データの削除
CakePHP 2.X Cookbook データを削除する
飲食業界からIT業界に転身してきて現在2年目です。PHPの経験がメインとなります。これまで自分がPHPを扱ってきた上で、モヤモヤしてきたことをメインに記事にしていきますのでよろしくお願いいたします。