Umi Blog
ウミブログ

全国のDrupalistのみなさん、こんにちは!
今回はQiitaのアドベントカレンダーに参加するということで気合を入れてオリジナル記事を書く・・・はずが時間がなかったので翻訳にさせていただきました。
テーマは「キャッシュ」です。先日のミートアップでキャッシュの話がちらっと出たので、勉強がてら翻訳してみました。
「Cache APIについて 日本語訳」という記事でも触れましたが、Drupalは「アクセス結果からエンティティ、URLまで、直接レンダリング可能なデータや、何をレンダリングすべきかと決めるデータのすべて」のキャッシュを残すことが出来ます。そして、それぞれデータのキャッシュが「どのような条件下で、どれくらいの長さ保存されるか」を「キャッシャビリティ(Cacheability)」と呼び、「キャッシャビリティ・メタデータ」という形式のデータを書くことでそれらの設定を行うことができます。 この文章では特にHTMLレンダリングに使われる 「レンダリング配列」のキャッシャビリティの設定方法について説明されています。 なお、レンダリング配列について詳しく知りたい方は「レンダリング配列について 日本語訳」を御覧ください。
それではみなさんよいクリスマス&お正月を!
(翻訳開始)
原文: Cacheability of render arrays(翻訳時の最終更新日:2018年9月28日)
レンダリング配列は何をユーザーに見せるかを決めます。 そのため、レンダリング配列はレスポンスのキャッシャビリティも決めます。
とてもダイナミックなレンダリング配列を生成するコード(一般的にはたくさんのif文を使っているコード)をレンダリングするということは、Drupalは単純にレンダリング配列によって作られたHTMLをキャッシュできないことを意味します。Drupalは時と場合に応じて(if文を含む)コードを呼び出さなくてはいけません。
別の言葉で言うなら、Drupalはコードがどれだけダイナミックであるのかを知らなくてはいけません。そうでないと、キャッシュされたHTMLを間違ったユーザーに送ってしまうことになります!(筆者注: 例えば、ユーザーAのみが見れるページをキャッシュしたものをユーザーB用に使うことは出来ません。Drupalが現在のユーザーを読み取って個別にキャッシュする必要があります。)
(サイトの表示を適切に効率化する上で)一番重要なことは、レンダリングAPIにレンダリング配列のキャッシャビリティを知らせることです。
レンダリング配列を生成するときはいつでも、以下の5つのステップを使いましょう。:
varyヘッダーと完全な相似になっています。Cache::PERMANENT)となっています。表示が決まった期間のみ有効の場合、キャッシュ寿命を秒単位で指定ましょう。キャッシュの寿命が0の場合、それはキャッシュ不可能であるということです。キャッシュ・コンテクスト、キャッシュ・タグ、キャッシュ寿命は常に設定されてないといけません。 なぜなら、それらはレスポンス全体のキャッシャビリティに影響するからです。それらのパラメーターは「バブル(伝達)」します。つまり、レンダリングされた部分の親(レスポンス・オブジェクト)は自動的にそれらのパラメーターを受け取るのです。 キャッシュ・キーはそのレンダリング配列がキャッシュされる場合のみ設定される必要があります。
上記の考えを抽象的な例に当てはめてみましょう。
['node', 5, 'teaser']のようになります。['timezone']のようになります。['node:5', 'user:3', 'file:4', 'config:filter.format.basic_html']のようになります。Cache::PERMANENT)のままにしておいて問題ないでしょう。(注意: (ティーザーの場合)Drupalは自動的に上記のキャッシャビリティ・メタデータを設定してくれます。エンティティ・ビュー・ビルダー(Entity View Builder)とフィールドフォーマッター(Field Formatter)がそれを担当します。この例は誰でもDrupalのキャッシュを理解できるようにとあえて作ったものです。)
注意してほしいのは、すべてのエンティティとコンフィグがCacheableDependencyInterfaceを実装しているということです。そのインターフェースはエンティティ/コンフィグオブジェクトが編集されたらいつでもレンダリング配列のキャッシュが無効化するようなキャッシャビリティ・メタデータを提供しています。
詳しくはCacheableDependencyInterface & friendsをご覧ください。
$renderer = \Drupal::service('renderer');
$config = \Drupal::config('system.site');
$current_user = \Drupal::currentUser();
$build = [
'#markup' => t('Hi, %name, welcome back to @site!', [
'%name' => $current_user->getUsername(),
'@site' => $config->get('name'),
]),
'#cache' => [
'contexts' => [
// "current user"は上で定義されているように、リクエストによって変わります.
// そのため、Drupal に 'user' ごとにキャッシュのバリエーションを変えるように教えます.
'user',
],
],
];
// 上記のキャッシャビリティ・メタデータに、コンフィグ・オブジェクトのキャッシャビリティ・メタデータと、
// ユーザーエンティティのキャッシャビリティ・メタデータを合成します.
$renderer->addCacheableDependency($build, $config);
$renderer->addCacheableDependency($build, \Drupal\user\Entity\User::load($current_user->id()));
ここではユーザー名とサイト名を含むマークアップを生成しています。ユーザー名はユーザーエンティティに紐づけられているので、キャッシュ・タグを関連付けます。そしてそのアウトプットが閲覧するユーザーごと異なるようにしたいので、キャッシュ・コンテクストにuserを設定する必要があります。サイト名はコンフィグに格納されているので、Configオブジェクトのキャッシュ・タグも関連付けます。
ちょっとした長さのコードにはなりましたが、このレンダリング配列とマークアップのキャッシャビリティをDrupalに的確に知らせることが出来ました!
閲覧者によって内容を変えずに、すべての人に対して同じ表示メッセージを表示するパターンも見てみましょう。
$renderer = \Drupal::service('renderer');
$config = \Drupal::config('system.site');
$build = [
'#markup' => t('Hi, welcome back to @site!', [
'@site' => $config->get('name'),
])
];
$renderer->addCacheableDependency($build, $config);
画面に生成されるマークアップは少ししか違いませんが、コードはかなりシンプルになりました。すべてのユーザーに対して同じマークアップを適用できるので、必要とされる キャッシャビリティ・メタデータが少ないのです。特筆すべき点はキャッシュ・コンテクストが存在していないことでしょう。
あるページがどのキャッシュ・コンテキストのバリエーションを表示しているのか、どんなキャッシュ・タグによって期限切れにされているのかを知るのはとても簡単です。HTMLの X-Drupal-Cache-Contexts とX-Drupal-Cache-Tags ヘッダーを見ればいいのです。
それらのヘッダーを見れるようにするには、こちらをご覧ください。
(翻訳終わり)
小さなご意見も、私たちにとっては大きなヒントです!
ぜひ率直なご感想をお寄せください
この

Masters of Drupal Engineering.
人に、