Commit 8848d769 by Tomoki Morita

Add docs/guide-ja/caching-*.md [ci skip]

parent 8376f446
データキャッシュ
============
データキャッシュは PHP の変数をキャッシュに格納し、あとでキャッシュからそれらを読み込みます。
[クエリキャッシュ](#query-caching)[ページキャッシュ](caching-page.md) などのより高度なキャッシュ機能の基礎でもあります。
以下はデータキャッシュの典型的な利用パターンを示したコードです。`$cache`[キャッシュコンポーネント](#cache-components) を指します:
```php
// キャッシュから $data を取得しようと試みる
$data = $cache->get($key);
if ($data === false) {
// キャッシュの中に $data が見つからない場合は一から作る
// 次回はそれを取得できるように $data をキャッシュに格納する
$cache->set($key, $data);
}
// $data はここで利用できる
```
## キャッシュコンポーネント <a name="cache-components"></a>
データキャッシュはメモリ、ファイル、データベースなどさまざまなキャッシュストレージを表す、いわゆるキャッシュコンポーネントに依存しています。
キャッシュコンポーネントは通常グローバルに設定しアクセスできるように [アプリケーションコンポーネント](structure-application-components.md) として登録されています。以下のコードは [Memcached](http://memcached.org/) を使い 2 つのキャッシュサーバを用いて、`cache` コンポーネントをどのように設定するかを示したものです:
```php
'components' => [
'cache' => [
'class' => 'yii\caching\MemCache',
'servers' => [
[
'host' => 'server1',
'port' => 11211,
'weight' => 100,
],
[
'host' => 'server2',
'port' => 11211,
'weight' => 50,
],
],
],
],
```
上記のキャッシュコンポーネントには `Yii::$app->cache` でアクセスできます。
すべてのキャッシュコンポーネントは同じ API がセットされているので、アプリケーションのコンフィグレーション側で設定しなおせば、キャッシュを使っているコードに変更を加えなくても、異なるキャッシュコンポーネントに入れ替えることができます。例えば上記の設定を [[yii\caching\ApcCache|APC キャッシュ]] に変更する場合は以下のようにします:
```php
'components' => [
'cache' => [
'class' => 'yii\caching\ApcCache',
],
],
```
> ヒント: キャッシュコンポーネントは複数登録することができます。`cache` という名前のコンポーネントはキャッシュに依存したクラスによってデフォルトで使用されています (例えば [[yii\web\UrlManager]] など) 。
### サポートされているキャッシュストレージ <a name="supported-cache-storage"></a>
Yii はさまざまなキャッシュストレージをサポートしています。以下は概要です:
* [[yii\caching\ApcCache]]: PHP の [APC](http://php.net/manual/ja/book.apc.php) 拡張モジュールを使用します。集中型の分厚いアプリケーションのキャッシュを扱うときには最速の一つとして考えることができます (例えば、サーバが 1 台であったり、専用のロードバランサを持っていない、など) 。
* [[yii\caching\DbCache]]: キャッシュされたデータを格納するためにデータベースのテーブルを使用します。このキャッシュを使用するには [[yii\caching\DbCache::cacheTable]] で指定したテーブルを作成する必要があります。
* [[yii\caching\DummyCache]]: 実際にはキャッシュを行わない、キャッシュの代替を提供します。このコンポーネントの目的は、キャッシュが利用できることをチェックするためのコードを簡略化することです。たとえば、開発中やサーバに実際のキャッシュサポートがない場合に、このキャッシュコンポーネントを使用することができます。そして、実際のキャッシュサポートが有効になったときに、対応するキャッシュコンポーネントに切替えて使用します。 どちらの場合も、`Yii::$app->cache` が null かも知れないと心配せずに、データを取得するために同じコード `Yii::$app->cache->get($key)` を使用できます。
* [[yii\caching\FileCache]]: キャッシュされたデータを保存するために標準ファイルを使用します。これはページコンテンツなど大きなかたまりのデータに特に適しています。
* [[yii\caching\MemCache]]: PHP の [Memcache](http://php.net/manual/ja/book.memcache.php)[Memcached](http://php.net/manual/ja/book.memcached.php) 拡張モジュールを使用します。分散型のアプリケーションでキャッシュを扱うときには最速の一つとして考えることができます (例えば、複数台のサーバ構成であったり、ロードバランサなど) 。
* [[yii\redis\Cache]]: [Redis](http://redis.io/) の key-value ストアに基づいてキャッシュコンポーネントを実装しています。(Redis の バージョン 2.6.12 以降が必要です) 。
* [[yii\caching\WinCache]]: PHP の [WinCache](http://iis.net/downloads/microsoft/wincache-extension) ([関連リンク](http://php.net/manual/ja/book.wincache.php)) 拡張モジュールを使用します。
* [[yii\caching\XCache]]: PHP の [XCache](http://xcache.lighttpd.net/) 拡張モジュールを使用します。
* [[yii\caching\ZendDataCache]]: キャッシュメディアして [Zend Data Cache](http://files.zend.com/help/Zend-Server-6/zend-server.htm#data_cache_component.htm) を使用します。
> ヒント: 同じアプリケーション内で異なるキャッシュを使用することもできます。一般的なやり方として、小さくとも常に使用されるデータ (例えば、統計データなど) を格納する場合はメモリベースのキャッシュストレージを使用し、大きくて使用頻度の低いデータを格納する場合はファイルベース、またはデータベースのキャッシュストレージを使用します (例えば、ページコンテンツなど) 。
## キャッシュ API <a name="cache-apis"></a>
すべてのキャッシュコンポーネントが同じ基底クラス [[yii\caching\Cache]] を持っているので、以下の API をサポートしています。
* [[yii\caching\Cache::get()|get()]]: 指定されたキーを用いてキャッシュからデータを取得します。キャッシュが見つからないか、もしくは有効期限が切れていたり無効になっている場合は false を返します。
* [[yii\caching\Cache::set()|set()]]: キーによって識別されたデータをキャッシュに格納します。
* [[yii\caching\Cache::add()|add()]]: キーがキャッシュ内で見つからない場合に、キーによって識別されたデータをキャッシュに格納します。
* [[yii\caching\Cache::mget()|mget()]]: 指定されたキーを用いてキャッシュから複数のデータを取得します。
* [[yii\caching\Cache::mset()|mset()]]: キャッシュに複数のデータを格納します。各データはキーによって識別されます。
* [[yii\caching\Cache::madd()|madd()]]: キャッシュに複数のデータを格納します。各データはキーによって識別されます。もしキャッシュ内にキーがすでに存在する場合はスキップされます。
* [[yii\caching\Cache::exists()|exists()]]: 指定されたキーがキャッシュ内で見つかったかどうかを示す値を返します。
* [[yii\caching\Cache::delete()|delete()]]: キャッシュからキーによって識別されるデータを削除します。
* [[yii\caching\Cache::flush()|flush()]]: キャッシュからすべてのデータを削除します。
> 注意: [[yii\caching\Cache::get()|get()]] メソッドは、データがキャッシュ内に見つからないことを示すために戻り値として false を使用しているので、直接 boolean 型の `false` をキャッシュしないでください。代わり、配列内に `false` を置いてキャッシュすることによって、この問題を回避できます。
キャッシュされたデータを取得する際に発生するオーバーヘッドを減すために、MemCache, APC などのいくつかのキャッシュストレージはバッチモードで複数のキャッシュされた値の取得をサポートしています。[[yii\caching\Cache::mget()|mget()]] や [[yii\caching\Cache::madd()|madd()]] などの API はこの機能を十分に引き出すために提供されています。基礎となるキャッシュストレージがこの機能をサポートしていない場合には、シミュレートされます。
[[yii\caching\Cache]] は `ArrayAccess` インターフェイスを継承しているので、キャッシュコンポーネントは配列のように扱うことができます。以下はいくつかの例です:
```php
$cache['var1'] = $value1; // $cache->set('var1', $value1); と同等
$value2 = $cache['var2']; // $value2 = $cache->get('var2'); と同等
```
### キャッシュのキーについて <a name="cache-keys"></a>
キャッシュに格納される各データは、一意のキーによって識別されるため、キャッシュ内にデータを格納するときはキーを指定する必要があります。あとでキャッシュからデータを取得するときは、それに対応するキーを用意する、といった感じです。
文字列またはキャッシュのキーとして、任意の値を使用することができます。キーが文字列でない場合は、自動的に文字列にシリアライズされます。
キャッシュのキーを定義する一般的なやり方として、配列に決定要素を単位としてすべて含めることです。
例えば [[yii\db\Schema]] はデータベースのテーブルに関するキャッシュスキーマ情報に以下のキーを使用しています:
```php
[
__CLASS__, // クラス名
$this->db->dsn, // データベース接続のデータソース名
$this->db->username, // データベース接続のログインユーザ
$name, // テーブル名
];
```
見ての通り、キーは一意にデータベースのテーブルを指定するために必要なすべての情報が含まれています。
同じキャッシュストレージが異なるアプリケーションによって使用されているときは、キャッシュのキーの競合を避けるために、各アプリケーションではユニークなキーの接頭辞を指定する必要があります。これは [[yii\caching\Cache::keyPrefix]] プロパティを設定することでできます。例えば、アプリケーションのコンフィギュレーションで以下のように書くことができます:
```php
'components' => [
'cache' => [
'class' => 'yii\caching\ApcCache',
'keyPrefix' => 'myapp', // ユニークなキャッシュのキーの接頭辞
],
],
```
相互運用性を確保するために、英数字のみを使用する必要があります。
### キャッシュの有効期限 <a name="cache-expiration"></a>
キャッシュに格納されたデータは、いくつかのキャッシュポリシー (例えば、キャッシュスペースがいっぱいになったときは最も古いデータが削除される、など) の実施で除去されない限り、永遠に残り続けます。この動作を変えるために [[yii\caching\Cache::set()|set()]] で有効期限パラメータを指定することができます。パラメータはキャッシュ内に何秒間有効であるかを示します。[[yii\caching\Cache::get()|get()]] でデータを取得する際に有効期限が切れていた場合は、キャッシュ内にデータが見つからなかったことを示す false が返されます。例えば、
```php
// 最大で 45 秒間キャッシュ内にデータを保持する
$cache->set($key, $data, 45);
sleep(50);
$data = $cache->get($key);
if ($data === false) {
// $data は有効期限が切れているか、またはキャッシュ内に見つからない
}
```
### キャッシュの依存関係 <a name="cache-dependencies"></a>
有効期限の設定に加えて、キャッシュされたデータにはいわゆる *キャッシュの依存関係* の変化によって無効にすることもできます。例えば [[yii\caching\FileDependency]] はファイルの更新時刻の依存関係を表しています。依存関係が変更されたときに、対応するファイルが更新されることを意味しています。その結果、キャッシュ内で見つかった古いファイルのコンテンツは、無効とされるべきであり [[yii\caching\Cache::get()|get()]] は false を返します。
キャッシュの依存関係は [[yii\caching\Dependency]] 子孫クラスのオブジェクトとして表現されます。[[yii\caching\Cache::set()|set()]] でキャッシュにデータを格納する際に、関連するキャッシュの依存関係を知らせることができます。例えば、
```php
// example.txt ファイルの変更時間への依存関係を作成
$dependency = new \yii\caching\FileDependency(['fileName' => 'example.txt']);
// データは 30 秒で期限切れになります
// さらに、依存関係にあるファイルが変更された場合、有効期限内でも無効になります
$cache->set($key, $data, 30, $dependency);
// データが有効期限切れの場合はキャッシュがチェックされます
// 関連する依存関係が変更された場合にもチェックします
// これらの条件のいずれかが満たされている場合は false を返します
$data = $cache->get($key);
```
以下は利用可能なキャッシュの依存関係の概要です:
- [[yii\caching\ChainedDependency]]: チェーン上のいずれかの依存関係が変更された場合、依存関係が変更されます。
- [[yii\caching\DbDependency]]: 指定された SQL 文のクエリ結果が変更された場合、依存関係が変更されます。
- [[yii\caching\ExpressionDependency]]: 指定されたPHPの式の結果が変更された場合、依存関係が変更されます。
- [[yii\caching\FileDependency]]: ファイルの最終更新時刻が変更された場合、依存関係が変更されます。
- [[yii\caching\TagDependency]]: 一つまたは複数のタグを持つキャッシュされたデータを関連付けます。[[yii\caching\TagDependency::invalidate()]] を呼び出すことによって指定されたタグ(複数可)と、キャッシュされたデータを無効にすることができます。
## クエリキャッシュ <a name="query-caching"></a>
クエリキャッシュは、データキャッシュ上に構築された特別なキャッシュ機能で、データベースのクエリ結果をキャッシュするために提供されています。
クエリキャッシュは [[yii\db\Connection|データベース接続]] と有効な `cache` コンポーネントを必要とします。
`$db`[[yii\db\Connection]] のインスタンスと仮定した場合、クエリキャッシュの基本的な使い方は以下のようになります:
```php
$result = $db->cache(function ($db) {
// クエリキャッシュが有効で、かつクエリ結果がキャッシュ内にある場合、
// SQL クエリ結果がキャッシュから提供されます
return $db->createCommand('SELECT * FROM customer WHERE id=1')->queryOne();
});
```
クエリキャッシュは [DAO](db-dao.md) だけではなく [アクティブレコード](db-active-record.md) でも使用することができます。
> 情報: いくつかの DBMS (例えば [MySQL](http://dev.mysql.com/doc/refman/5.1/ja/query-cache.html)) でもデータベースのサーバサイドのクエリキャッシュをサポートしています。どちらのクエリキャッシュメカニズムも選べますが、前述した Yii のクエリキャッシュを使用することによって、キャッシュの依存関係を柔軟に指定できたり、潜在的にもより効率的でしょう。
### 設定 <a name="query-caching-configs"></a>
クエリキャッシュは [[yii\db\Connection]] を通して 3 つのグローバルな設定可能オプションがあります:
* [[yii\db\Connection::enableQueryCache|enableQueryCache]]: クエリキャッシュを可能にするかどうか。デフォルトは true。実効的にクエリキャッシュをオンにするには [[yii\db\Connection::queryCache|queryCache]] によって指定し、さらに有効なキャッシュを持っている必要があることに注意してください。
* [[yii\db\Connection::queryCacheDuration|queryCacheDuration]]: これはクエリ結果がキャッシュ内に有効な状態として維持できる秒数を表します。クエリキャッシュを永遠にキャッシュに残したい場合は 0 を指定することができます。このプロパティは [[yii\db\Connection::cache()]] の持続時間を指定せず呼び出されたときに使用されるデフォルト値です。
* [[yii\db\Connection::queryCache|queryCache]]: これはキャッシュコンポーネントの ID を表します。デフォルトは `'cache'`。有効なキャッシュコンポーネントが存在する場合にのみ、クエリキャッシュが使用可能になります。
### 使い方 <a name="query-caching-usages"></a>
クエリキャッシュを使用する必要がある複数の SQL クエリを持っている場合は [[yii\db\Connection::cache()]] を使用することができます。使い方としては以下のように、
```php
$duration = 60; // クエリ結果を 60 秒間 キャッシュ
$dependency = ...; // 依存関係のオプション
$result = $db->cache(function ($db) {
// ... ここで SQL クエリを実行します ...
return $result;
}, $duration, $dependency);
```
無名関数内の任意の SQL クエリは、指定した依存関係とともに指定された期間キャッシュされます。もしキャッシュ内に有効なクエリ結果が見つかった場合、クエリはスキップされ、その結果、代わりにキャッシュから提供されます。`$duration` の指定がない場合 [[yii\db\Connection::queryCacheDuration|queryCacheDuration]] で指定されている値が使用されます。
また、`cache()` 内でいくつかの特定のクエリに対してクエリキャッシュを無効にすることもできます。この場合 [[yii\db\Connection::noCache()]] を使用します。
```php
$result = $db->cache(function ($db) {
// クエリキャッシュを使用する SQL クエリ
$db->noCache(function ($db) {
// クエリキャッシュを使用しない SQL クエリ
});
// ...
return $result;
});
```
単一のクエリのためにクエリキャッシュを使用する場合は、コマンドを構築するときに [[yii\db\Command::cache()]] を呼び出すことができます。例えば、
```php
// クエリキャッシュを使い、期間を 60 秒にセットする
$customer = $db->createCommand('SELECT * FROM customer WHERE id=1')->cache(60)->queryOne();
```
また、ひとつのコマンドでクエリキャッシュを無効にするために [[yii\db\Command::noCache()]] を使用することもできます。例えば、
```php
$result = $db->cache(function ($db) {
// クエリキャッシュを使用する SQL クエリ
// このコマンドはクエリキャッシュを使用しない
$customer = $db->createCommand('SELECT * FROM customer WHERE id=1')->noCache()->queryOne();
// ...
return $result;
});
```
### 制約 <a name="query-caching-limitations"></a>
リソースハンドルを返すようなクエリにはクエリキャッシュは働きません。例えばいくつかの DBMS において BLOB 型のカラムを用いる場合、クエリ結果はカラムデータについてリソースハンドルを返します。
いくつかのキャッシュストレージはサイズに制約があります。例えば Memcache では、各エントリのサイズは 1MB が上限値です。そのためクエリ結果のサイズがこの制約を越える場合、キャッシュは失敗します。
フラグメントキャッシュ
================
フラグメントキャッシュは、ウェブページの断片をキャッシュすることを言います。例えば、ページ内の表に年間販売の概要が表示されている場合、リクエスト毎にこの表を生成するのにかかる時間を削減するために、キャッシュにこの表を格納することができます。フラグメントキャッシュは [データキャッシュ](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` が必要になります。
## キャッシュのオプション <a name="caching-options"></a>
[[yii\base\View::beginCache()|beginCache()]] メソッドの 2 番目のパラメータを配列にすることで、フラグメントキャッシュに関する追加のオプションを指定することもできます。裏で、この配列のオプションは実際にフラグメントキャッシュ機能を実装している [[yii\widgets\FragmentCache]] ウィジェットを構成するために使用されます。
### 持続時間 <a name="duration"></a>
おそらくフラグメントキャッシュで通常よく使われるであろうオプションは [[yii\widgets\FragmentCache::duration|duration]] でしょう。このオプションにはコンテンツがどれだけの時間キャッシュ内において有効であるかを指定します。以下のコードは最大で 1 時間コンテンツの断片をキャッシュします:
```php
if ($this->beginCache($id, ['duration' => 3600])) {
// ... ここに生成するコンテンツを書く ...
$this->endCache();
}
```
オプションがセットされていない場合は、デフォルトである 60 が使われ、つまり有効期限が 60 秒間のキャッシュされたコンテンツを意味します。
### 依存関係 <a name="dependencies"></a>
[データキャッシュ](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();
}
```
### バリエーション <a name="variations"></a>
キャッシュされたコンテンツはいくつかのパラメータによって変化させることもできます。例えば、複数の言語をサポートしているウェブアプリケーションに対して、ビューコードの同じ部分を、異なる言語で生成することができます。現在のアプリケーションの言語に応じて、キャッシュされたコンテンツに変更を加えるといったことが可能になります。
キャッシュのバリエーションを指定するには [[yii\widgets\FragmentCache::variations|variations]] オプションに配列で、それぞれが特定のバリエーションの要素を表すスカラー値をセットします。例えば、言語によってキャッシュされたコンテンツを変化させるには、以下のコードを使うことができます:
```php
if ($this->beginCache($id, ['variations' => [Yii::$app->language]])) {
// ... ここに生成するコンテンツを書く ...
$this->endCache();
}
```
### トグルキャッシュ <a name="toggling-caching"></a>
また、ある条件が満たされた場合にのみフラグメントキャッシュを有効にすることもできます。たとえば、フォームが表示されているページに対して、最初の (GET リクエストによる) リクエストの場合だけはキャッシュしたいと思いますが、その後の (POST リクエストによる) フォームの表示では、フォームにユーザ入力が含まれている可能性があるため、キャッシュをすべきではありません。これを行うには、以下のように [[yii\widgets\FragmentCache::enabled|enabled]] オプションをセットします:
```php
if ($this->beginCache($id, ['enabled' => Yii::$app->request->isGet])) {
// ... ここに生成するコンテンツを書く ...
$this->endCache();
}
```
## キャッシュのネスト <a name="nested-caching"></a>
フラグメントキャッシュはネストすることができます。つまり、キャッシュされる断片を、より大きなキャッシュされる断片で囲むことができます。例えば、コメントが内側のフラグメントキャッシュ内にキャッシュされ、それらが外側のフラグメントキャッシュに記事内容と一緒にキャッシュされます。以下のコードは 2 つのフラグメントキャッシュをどのようにネストできるかを示したものです:
```php
if ($this->beginCache($id1)) {
// ...コンテンツ生成ロジック...
if ($this->beginCache($id2, $options2)) {
// ...コンテンツ生成ロジック...
$this->endCache();
}
// ...コンテンツ生成ロジック...
$this->endCache();
}
```
ネストされたキャッシュには、異なるキャッシュオプションを設定することができます。 たとえば、上記の例における内側のキャッシュと外側のキャッシュに対して、異なる持続期間の値を設定する事が可能です。 これによって、外側のキャッシュでキャッシュされたデータが無効になった場合でも、内側のキャッシュが有効な内側の断片を提供することが可能になります。 しかし、その逆は真ではありません。 外側のキャッシュが有効であると判断された場合には、内側のキャッシュが無効になった後でも、外側のキャッシュが古くなったコンテンツのコピーを提供し続けます。 ネストされたキャッシュの持続時間や依存関係の設定を間違うと、無効になった内側のキャッシュデータが外側のキャッシュに残り続けることになるので、注意が必要です。
## ダイナミックコンテンツ <a name="dynamic-content"></a>
フラグメントキャッシュを使用する際、出力全体が比較的静的で、一ヶ所ないし数ヶ所だけが例外的に動的であるというような状況に遭遇します。例えば、ページ上部にはメインメニューバーと現在のユーザの名前とが一緒に表示される場合があります。他には、リクエスト毎に実行しなければいけない 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 コードはすべてのリクエストに対して実行されますが、囲まれている断片がキャッシュから提供されているか否かは問いません。
HTTP キャッシュ
============
前の節で説明したサーバーサイドのキャッシュに加えて、ウェブアプリケーションは、同じページコンテンツを生成し送信する時間を節約するために、クライアントサイドでもキャッシュを利用することができます。
クライアントサイドのキャッシュを使用するには、レンダリング結果をキャッシュできるように、コントローラアクションのフィルタとして [[yii\filters\HttpCache]] を設定します。[[yii\filters\HttpCache]] は `GET``HEAD` リクエストに対してのみ動作し、また、それらのリクエストは 3 種類のキャッシュ関連の HTTP ヘッダを扱うことができます:
* [[yii\filters\HttpCache::lastModified|Last-Modified]]
* [[yii\filters\HttpCache::etagSeed|Etag]]
* [[yii\filters\HttpCache::cacheControlHeader|Cache-Control]]
## `Last-Modified` ヘッダ <a name="last-modified"></a>
`Last-Modified` ヘッダは、クライアントがそれをキャッシュする時から、ページが変更されたかどうかを示すために、タイムスタンプを使用しています。
`Last-Modified` ヘッダの送信を有効にするには [[yii\filters\HttpCache::lastModified]] プロパティを、ページの変更時間に関する UNIX タイムスタンプを返す PHP の callable 型で、以下のようなシグネチャで構成していきます。
```php
/**
* @param Action $action 現在扱っているアクションオブジェクト
* @param array $params "params" プロパティの値
* @return integer ページの更新時刻を表す UNIX タイムスタンプ
*/
function ($action, $params)
```
以下は `Last-Modified` ヘッダを使用する例です:
```php
public function behaviors()
{
return [
[
'class' => 'yii\filters\HttpCache',
'only' => ['index'],
'lastModified' => function ($action, $params) {
$q = new \yii\db\Query();
return $q->from('post')->max('updated_at');
},
],
];
}
```
上記のコードは `index` アクションでのみ HTTP キャッシュを有効にしている状態です。投稿の最終更新時刻に基づいて `Last-Modified` を生成する必要があります。ブラウザが初めて `index` ページにアクセスすると、ページはサーバ上で生成されブラウザに送信されます。もしブラウザが再度同じページにアクセスし、その期間中に投稿に変更がない場合は、ブラウザはクライアントサイドにキャッシュしたものを使用するので、サーバはページを再生成することはありません。その結果、サーバサイドのレンダリング処理とページコンテンツの送信は両方ともスキップされます。
## `ETag` ヘッダ <a name="etag"></a>
"Entity Tag" (略して `ETag`) ヘッダはページコンテンツを表すためにハッシュを使用します。ページが変更された場合ハッシュも同様に変更されます。サーバサイドで生成されたハッシュとクライアントサイドで保持しているハッシュを比較することによって、ページが変更されたかどうか、また再送信するべきかどうかを決定します。
`ETag` ヘッダの送信を有効にするには [[yii\filters\HttpCache::etagSeed]] プロパティを設定します。プロパティは ETag のハッシュを生成するためのシードを返す PHP の callable 型で、以下のようなシグネチャで構成していきます。
```php
/**
* @param Action $action 現在扱っているアクションオブジェクト
* @param array $params "params" プロパティの値
* @return string ETag のハッシュを生成するためのシードとして使用する文字列
*/
function ($action, $params)
```
以下は `ETag` ヘッダを使用している例です:
```php
public function behaviors()
{
return [
[
'class' => 'yii\filters\HttpCache',
'only' => ['view'],
'etagSeed' => function ($action, $params) {
$post = $this->findModel(\Yii::$app->request->get('id'));
return serialize([$post->title, $post->content]);
},
],
];
}
```
上記のコードは `view` アクションでのみ HTTP キャッシュを有効にしている状態です。リクエストされた投稿のタイトルとコンテンツに基づいて HTTP の `Etag` ヘッダを生成しています。ブラウザが初めて `view` ページにアクセスするときに、ページがサーバ上で生成されブラウザに送信されます。ブラウザが再度同じページにアクセスし、投稿のタイトルやコンテンツに変更がない場合には、サーバはページを再生成せず、ブラウザはクライアントサイトにキャッシュしたものを使用します。その結果、サーバサイドのレンダリング処理とページコンテンツ送信の両方ともスキップされます。
ETag は `Last-Modified` ヘッダよりも複雑かつ、より正確なキャッシング方式を可能にします。例えば、サイトが別のテーマに切り替わった場合には ETag を無効化する、といったことができます。
ETag はリクエスト毎に再評価する必要があるため、負荷の高いもの生成すると `HttpCache` の本来の目的を損なって不必要なオーバーヘッドが生じる場合があるので、ページのコンテンツが変更されたときにキャッシュを無効化するための式は単純なものを指定するようにして下さい。
> 注意: [RFC 7232](http://tools.ietf.org/html/rfc7232#section-2.4) に準拠して `Etag` と `Last-Modified` ヘッダの両方を設定した場合、`HttpCache` はその両方とも送信します。また、もし `If-None-Match` ヘッダと `If-Modified-Since` ヘッダの両方を送信した場合は前者のみが尊重されます。
## `Cache-Control` ヘッダ <a name="cache-control"></a>
`Cache-Control` ヘッダはページのための一般的なキャッシュポリシーを指定します。ヘッダ値に [[yii\filters\HttpCache::cacheControlHeader]] プロパティを設定することで、それを送ることができます。デフォルトでは、以下のヘッダーが送信されます:
```
Cache-Control: public, max-age=3600
```
## セッションキャッシュリミッタ<a name="session-cache-limiter"></a>
ページでセッションを使用している場合、PHP はいくつかのキャッシュ関連の HTTP ヘッダ(PHP の設定ファイル内で指定されている session.cache_limiter など)を自動的に送信します。これらのヘッダは `HttpCache` で妨害したり、必要なキャッシュを無効にしたりできます。この動作を変更したい場合は [[yii\filters\HttpCache::sessionCacheLimiter]] プロパティを設定します。プロパティには `public``private``private_no_expire`、そして `nocache` などの文字列の値を使用することができます。これらの値についての説明は [session_cache_limiter()](http://www.php.net/manual/ja/function.session-cache-limiter.php) を参照してください。
## SEO への影響 <a name="seo-implications"></a>
検索エンジンのボットはキャッシュヘッダを尊重する傾向があります。 クローラの中には、一定期間内に処理するドメインごとのページ数に制限を持っているものもあるため、キャッシュヘッダを導入して、処理の必要があるページ数を減らしてやると、サイトのインデックスの作成を促進できるかも知れません。
キャッシュ
=======
ウェブアプリケーションのパフォーマンスを向上させるための簡単で効果的な方法としてキャッシュというものがあります。比較的静的なデータをキャッシュに格納し、必要に応じてキャッシュからそれらを取得することによって、アプリケーションは一からデータを生成するのに必要な時間を節約することができます。
キャッシュはさまざまなレベルのものを、アプリケーション内のさまざまな場所で使用することができます。例えばサーバサイドでの低いレベルでは、データベースから取得した最新の記事情報リストのような基本的なデータを格納するために使用したり、高いレベルでは、レンダリング結果の一部分、最新の記事であったり、またウェブページ全体を格納するためなどにも使用できます。クライアントサイドでは、ブラウザのキャッシュに最近訪れたことのあるページの内容を格納するために HTTP キャッシュを使用することもできます。
Yii では以下のリストに挙げられているキャッシュ機構をサポートしています:
* [データキャッシュ](caching-data.md)
* [フラグメントキャッシュ](caching-fragment.md)
* [ページキャッシュ](caching-page.md)
* [HTTP キャッシュ](caching-http.md)
ページキャッシュ
============
ページキャッシュはサーバサイドでページ全体のコンテンツをキャッシュすることを言います。あとで、同じページに再度リクエストがあった場合、その内容を一から再び生成させるのではなく、キャッシュから提供するようにします。
ページキャッシュは [[yii\filters\PageCache]]、 [アクションフィルタ](structure-filters.md) によってサポートされています。これは、コントローラクラスで以下のように使用することができます:
```php
public function behaviors()
{
return [
[
'class' => 'yii\filters\PageCache',
'only' => ['index'],
'duration' => 60,
'variations' => [
\Yii::$app->language,
],
'dependency' => [
'class' => 'yii\caching\DbDependency',
'sql' => 'SELECT COUNT(*) FROM post',
],
],
];
}
```
上記のコードは、ページキャッシュが `index` アクションのみで使用され、そのページのコンテンツは最大 60 秒間キャッシュし、現在のアプリケーションの言語によって変化し、投稿の総数に変化があった場合キャッシュされたページが無効になる、ということを示しています。
見てわかるように、ページキャッシュは [フラグメントキャッシュ](caching-fragment.md) ととてもよく似ています。それらは両方とも `duration``dependencies``variations`、そして `enabled` などのオプションをサポートしています。主な違いとしては、ページキャッシュは [アクションフィルタ](structure-filters.md) として、フラグメントキャッシュは [ウィジェット](structure-widgets.md) として実装されているということです。
また、ページキャッシュと一緒に [ダイナミックコンテンツ](caching-fragment.md#dynamic-content) だけでなく [フラグメントキャッシュ](caching-fragment.md) も使用することができます。
......@@ -39,6 +39,7 @@ Japanese
-------
- Nobuo Kihara 木原伸夫, [@softark](https://github.com/softark), softark@gmail.com
- Tomoki Morita, [@jamband](https://github.com/jamband), tmsongbooks215@gmail.com
Russian
-------
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment