フラグメントキャッシュ ================ フラグメントキャッシュは、ウェブページの断片をキャッシュすることを言います。例えば、ページ内の表に年間販売の概要が表示されている場合、リクエスト毎にこの表を生成するのにかかる時間を削減するために、キャッシュにこの表を格納することができます。フラグメントキャッシュは [データキャッシュ](caching-data.md) 上に構築されています。 フラグメントキャッシュを使用するには [ビュー](structure-views.md) で以下の構文を使用します: ```php if ($this->beginCache($id)) { // ... ここに生成するコンテントを書く ... $this->endCache(); } ``` つまり、コンテント生成ロジックを [[yii\base\View::beginCache()|beginCache()]] と [[yii\base\View::endCache()|endCache()]] の呼び出しのペアで囲みます。 コンテントがキャッシュ内で見つかった場合、[[yii\base\View::beginCache()|beginCache()]] はキャッシュされたコンテントをレンダリングして false を返し、結果として、コンテント生成ロジックがスキップされます。 それ以外の場合はコンテント生成ロジックが呼ばれ、そして [[yii\base\View::endCache()|endCache()]] が呼ばれたときに、生成されたコンテントがキャプチャされ、キャッシュに格納されます。 [データキャッシュ](caching-data.md) と同様に、キャッシュされるコンテントを識別するためにユニークな `$id` が必要になります。 ## キャッシュのオプション [[yii\base\View::beginCache()|beginCache()]] メソッドの 2 番目のパラメータとしてオプションの配列を渡すことによって、フラグメントキャッシュに関する追加のオプションを指定することができます。 裏で、このオプションの配列は、実際にフラグメントキャッシュ機能を実装している [[yii\widgets\FragmentCache]] ウィジェットを構成するために使用されます。 ### 持続時間 おそらくフラグメントキャッシュで通常よく使われるであろうオプションは [[yii\widgets\FragmentCache::duration|duration]] でしょう。 このオプションはコンテントがどれだけの時間キャッシュ内において有効であるかを指定します。以下のコードは最大で 1 時間コンテントの断片をキャッシュします: ```php if ($this->beginCache($id, ['duration' => 3600])) { // ... ここに生成するコンテントを書く ... $this->endCache(); } ``` このオプションがセットされていない場合は、デフォルトである 60 が使われます。 すなわち、キャッシュされたコンテントの有効期限は 60 秒後に切れることになります。 ### 依存 [データキャッシュ](caching-data.md#cache-dependencies) と同様に、キャッシュされたコンテントの断片は依存を持つことができます。 例えば、表示されている投稿の内容は、投稿が変更されたか否かに依存します。 依存を指定するには [[yii\widgets\FragmentCache::dependency|dependency]] オプションに [[yii\caching\Dependency]] オブジェクトを指定するか、または依存オブジェクトを作成するための構成情報配列を指定します。 以下のコードはコンテントの断片が `updated_at` カラムの値の変化に依存していることを指定しています: ```php $dependency = [ 'class' => 'yii\caching\DbDependency', 'sql' => 'SELECT MAX(updated_at) FROM post', ]; if ($this->beginCache($id, ['dependency' => $dependency])) { // ... ここに生成するコンテントを書く ... $this->endCache(); } ``` ### バリエーション キャッシュされるコンテントには、何らかのパラメータによってバリエーションを持たせることが出来ます。 例えば、複数の言語をサポートしているウェブアプリケーションでは、ビューコードの同じ部分が言語によってさまざまに異なるコンテントを生成することが可能です。 従って、現在のアプリケーションの言語に応じて、キャッシュされるコンテントのバリエーションを持つ必要があります。 キャッシュのバリエーションを指定するには [[yii\widgets\FragmentCache::variations|variations]] オプションに配列で、それぞれが特定のバリエーションの要素を表すスカラー値をセットします。 例えば、言語によってキャッシュされるコンテントのバリエーションを持つためには、以下のコードを使うことができます: ```php if ($this->beginCache($id, ['variations' => [Yii::$app->language]])) { // ... ここに生成するコンテントを書く ... $this->endCache(); } ``` ### キャッシュを ON/OFF する 時として、ある条件が満たされた場合にのみフラグメントキャッシュを有効にしたい場合があるでしょう。 たとえば、フォームが表示されているページでは、フォームをキャッシュしたいのは最初の (GET リクエストによる) リクエストの場合だけです。 その後の (POST リクエストによる) フォームの表示では、フォームにユーザ入力が含まれている可能性があるため、キャッシュをすべきではありません。 これを行うには、以下のように [[yii\widgets\FragmentCache::enabled|enabled]] オプションをセットします: ```php if ($this->beginCache($id, ['enabled' => Yii::$app->request->isGet])) { // ... ここに生成するコンテントを書く ... $this->endCache(); } ``` ## キャッシュのネスト フラグメントキャッシュはネストすることができます。 つまり、キャッシュされる断片を、それ自体もキャッシュされる別の断片に入れることができます。 例えば、内側のフラグメントキャッシュにはコメントがキャッシュされており、外側のフラグメントキャッシュには記事内容と一緒にコメントもキャッシュされている、という形です。 以下のコードは 2 つのフラグメントキャッシュをネストする方法を示すものです。 ```php if ($this->beginCache($id1)) { // ...コンテント生成ロジック... if ($this->beginCache($id2, $options2)) { // ...コンテント生成ロジック... $this->endCache(); } // ...コンテント生成ロジック... $this->endCache(); } ``` ネストされたキャッシュには、異なるキャッシュオプションを設定することができます。 たとえば、上記の例における内側のキャッシュと外側のキャッシュに対して、異なる持続期間の値を設定する事が可能です。 これによって、外側のキャッシュでキャッシュされたデータが無効になった場合でも、内側のキャッシュが有効な内側の断片を提供することが可能になります。 しかし、その逆は真ではありません。 外側のキャッシュが有効であると判断された場合には、内側のキャッシュが無効になった後でも、外側のキャッシュが古くなったコンテントのコピーを提供し続けます。 従って、ネストされたキャッシュの持続時間や依存の設定を間違うと、無効になった内側のキャッシュデータが外側のキャッシュに残り続けることになるので、注意が必要です。 ## ダイナミックコンテント フラグメントキャッシュを使用する際、出力全体が比較的静的で、一ヶ所ないし数ヶ所だけが例外的に動的であるというような状況に遭遇するでしょう。 例えば、ページのヘッダがメインメニューバーと現在のユーザ名を一緒に表示している場合です。 もう一つの問題は、キャッシュされるコンテントに、リクエスト毎に実行しなければいけない PHP のコード (例えば、アセットバンドルを登録するためのコード) が含まれている場合です。 この両方の問題は、いわゆる *ダイナミックコンテント* 機能によって解決することができます。 ダイナミックコンテントは、それがフラグメントキャッシュの中に含まれていても、キャッシュすべきではない出力の部分を意味します。 このコンテントを常に動的にするためには、外側のコンテントがキャッシュから提供されている場合でも、すべてのリクエストに対して、何らかの PHP コードを実行することにより生成しなければいけません。 ダイナミックコンテントを目的の場所に挿入するには、以下のように、キャッシュされる断片内で [[yii\base\View::renderDynamic()]] を呼び出します。 ```php if ($this->beginCache($id1)) { // ...コンテント生成ロジック... echo $this->renderDynamic('return Yii::$app->user->identity->name;'); // ...コンテント生成ロジック... $this->endCache(); } ``` [[yii\base\View::renderDynamic()|renderDynamic()]] メソッドはパラメータとして PHP コードを取ります。 この PHP コードの戻り値が、ダイナミックコンテントとして扱われます。 囲んでいる断片がキャッシュから提供されるか否かにかかわらず、同じ PHP コードがすべてのリクエストに対して実行されます。