CacheableDependencyInterface
キャッシュメタデータ(キャッシュタグ、キャッシュコンテキスト、max-age)の処理を容易にするために、Drupal 8にはCacheableDependencyInterfaceがあります。
なぜ?
レンダー配列(または他の何らかの計算)で使用する個々のエンティティと設定エンティティのキャッシュタグを手動で作成する必要があると想像してください。そして、多言語サイトでは、必要なキャッシュコンテキストも手動で追加します(翻訳されたエンティティの場合、または設定エンティティの言語オーバーライドの場合)。
エンティティと設定だけでなく、アクセス結果、ブロックプラグイン、メニューリンク、コンテキストプラグイン、条件プラグインなども同様です。それらはすべて、キャッシュしたいレンダリング(具体的なタイプの計算)で終わるためです。
Drupal 8の開発初期には、これが事実でした。当然、これは信頼性が低く、エラーが発生しやすいものでした。
これがCacheableDependencyInterfaceが導入された理由です。名前が示すように:このインターフェースを実装するオブジェクトは、自動的にキャッシュ可能な依存関係になることができます。
たとえば、<p>こんにちは、%userさん、%siteへようこそ!</p>のレンダー配列を作成するとき、現在のユーザーのUserエンティティとsystem.site設定の両方に依存します。このレンダー配列がキャッシュされると、このUserエンティティとこの設定オブジェクトの両方をキャッシュ可能な依存関係として持ちます。
CacheableDependencyInterfaceは、任意の値オブジェクト(つまり、論理的なデータの単位を表すオブジェクト)で実装できます。APIドキュメントを見ると、Drupal 8コアの多くの重要なオブジェクトで実装されていることがわかります。実際、Drupal 8コードを書くときにやり取りするほとんどのオブジェクトで実装されていると言っても過言ではありません!
かなり頻繁に発生する2つの正反対のケースがあり、Drupalには便利なトレイトがあります:不変のオブジェクトであり、したがって永久にキャッシュ可能なケース(UnchangingCacheableDependencyTrait。常にmax-age === permanentを返します)、およびオブジェクトが常に動的に計算され、したがって決してキャッシュされないケース(UncacheableDependencyTrait。常にmax-age === 0を返します)。
RefinableCacheableDependencyInterface
ただし、CacheableDependencyInterfaceは、オブジェクトの「固有の」「正規の」キャッシュ可能性メタデータのみを操作できます。オブジェクトには複数のバリアントが存在する場合があります。
最も顕著な例は、エンティティ翻訳(同じエンティティIDを持つ同じエンティティで、別の翻訳のみ)と設定翻訳(同じ設定名を持つ同じ設定オブジェクトですが、言語オーバーライドがあります)です。
どちらの場合も、元の(翻訳されていない)オブジェクトにすでに存在するキャッシュ可能性メタデータは引き続き適用されます。たとえば、node:5キャッシュタグ。ただし、エンティティの場合、このエンティティが元のエンティティのバリアントであることを示すために、コンテンツ言語キャッシュコンテキスト('languages:' . LanguageInterface::TYPE_CONTENT、キャッシュコンテキストを参照)が必要です。これは、どのコンテンツ言語キャッシュコンテキストがネゴシエートされたかによって異なります。同様に、設定オブジェクトの場合、この設定オブジェクトが元の設定オブジェクトのバリアントであることを伝えるために、インターフェース言語キャッシュコンテキスト('languages:' . LanguageInterface::TYPE_INTERFACE)が必要です。これは、どのインターフェース言語キャッシュコンテキストがネゴシエートされたかによって異なります。
翻訳を超えた例としては、「Pirate day」モジュールがあります。このモジュールには、海賊の日にのみ適用される設定オーバーライドがあり、yar、har、ランダムなオウムを設定に追加します。その場合、設定オブジェクトにはpirate_dayキャッシュコンテキストが含まれます。
上記のすべての例で、読み込まれたバリアントを示すために、オブジェクトのキャッシュ可能性メタデータを調整する必要があります。このため、RefinableCacheableDependencyInterfaceが追加されました。これはまさにそれを可能にします:キャッシュタグとコンテキストを追加し、max-ageを更新する機能があります。
このインターフェースの実装を容易にするために、もう1つの便利なトレイトがあります:RefinableCacheableDependencyTrait。
エンティティと設定オブジェクトについて
Drupal 8のすべてのエンティティ(core、contrib & custom)は、EntityInterfaceを実装しています。これは、CacheableDependencyInterfaceとRefinableCacheableDependencyInterfaceの両方を拡張します。さらに、Drupal 8コアのすべてのエンティティは抽象基本クラスのEntityを拡張しており、contrib/customも同じことを行うことをお勧めします。つまり、Drupal 8で操作する個々のエンティティにはすべて、一貫したキャッシュタグ(<エンティティタイプ>:<エンティティID>。例:node:5やuser:3)と、翻訳を反映するキャッシュコンテキストが自動的に含まれます。
Drupal 8コアのすべての設定オブジェクトは、抽象基本クラスのConfigBaseを拡張します。これは、CacheableDependencyInterfaceとRefinableCacheableDependencyInterfaceの両方を実装します。つまり、Drupal 8で操作する個々の設定オブジェクトにはすべて、一貫したキャッシュタグ(config:<設定名>形式。例:config:system.performance)と、設定オーバーライドを反映するキャッシュコンテキストが自動的に含まれます(翻訳がコアでの唯一の例です)。
最後に、Drupal 8のすべてのエンティティと設定オブジェクトには、EntityManager::getTranslationFromContext()とLanguageConfigFactoryOverride::getCacheableMetadata($name)のおかげで、コンテンツ/インターフェース言語キャッシュコンテキストが自動的に含まれます。
キャッシュ可能な依存関係であるオブジェクトの使用
レンダリングは、キャッシュ可能な依存関係であるオブジェクトへの依存の最も一般的な例です。これを容易にするために、RendererInterface::addCacheableDependency($build, $dependency)があります。ここで、$buildは$dependencyオブジェクトに依存するレンダー配列です。オブジェクトのキャッシュ可能性メタデータは、レンダー配列に自動的に「吸収」されます。つまり、オブジェクトのキャッシュタグが無効になるたびにレンダー配列が無効になり、別の翻訳が使用される場合(つまり、コンテンツ言語キャッシュコンテキストが別の言語に解決される場合)は別のバージョンがキャッシュされ、依存関係に永続的(無限)ではないmax-ageがある場合は自動的に期限切れになります。
完全な例については、レンダー配列のキャッシュ可能性 - 具体例を参照してください。
もう1つの良い例は、AccessResultオブジェクトを返すアクセスチェックです。これらにはAccessResult::addCacheableDependency($dependency)メソッドもあります。ここでは$dependencyパラメーターのみがあることに注意してください。これは、渡された依存関係のキャッシュ可能性メタデータをアクセス結果オブジェクト自体に保存できるためです。(レンダー配列を持つレンダラーは例外です。)
関連するインターフェースとクラス