web-dev-qa-db-ja.com

すべてのレンダーキャッシュを構成オーバーライドで更新するにはどうすればよいですか?

ショートバージョン:

構成オーバーライドを使用してサイト名をオーバーライドしています。変更はHTMLタイトルに反映されますが、システムブランドブロックには反映されません。 Drupalは、レンダーキャッシュからこのブロックを提供し続けます。

ロングバージョン:

オンデマンドで構成をオーバーライドするConfigFactoryOverrideInterfaceを実装する構成オーバーライドサービスを使用しています。少し単純化すると、次のようになります。

_class MyConfigOverride implements ConfigFactoryOverrideInterface {

  /**
   * {@inheritdoc}
   */
  public function loadOverrides($names) {
    $overrides = [];

    if ($override_required) {
      if (in_array('system.site', $names)) {
        $overrides['system.site']['name'] = 'My name';
      }
    }
    return $overrides;
  }

  /**
   * {@inheritdoc}
   */
  public function getCacheSuffix() {
    return 'MyConfigOverride';
  }

  /**
   * {@inheritdoc}
   */
  public function getCacheableMetadata($name) {
    $metadata = new CacheableMetadata();

    if ($name === 'system.site') {
      $my_entity = MyEntity::Load(1);
      if ($override_required && !empty($my_entity)) {
        // Append entity cache metadata (cache tags and context).
        $metadata->addCacheableDependency($my_entity);
      }
    }
    return $metadata;
  }

  /**
   * {@inheritdoc}
   */
  public function createConfigObject($name, $collection = StorageInterface::DEFAULT_COLLECTION) {
    return NULL;
  }

}
_

ただし、このオーバーライドが有効になるとすぐに、システムブランドブロックのレンダーキャッシュは新しいサイト名で更新されません。 SystemBrandingBlock クラスは、system.siteキャッシュタグをマージするgetCacheTags()を実装しますが(以下を参照)、getCacheContexts()を実装しないためです(私はページのバリエーションを提供するので、モジュールが使用します)。

_/**
 * {@inheritdoc}
 */
public function getCacheTags() {
  return Cache::mergeTags(
    parent::getCacheTags(),
    $this->configFactory->get('system.site')->getCacheTags()
  );

}
_

オーバーライドが適用されない場合のために、追加の「空の」キャッシュメタデータをクラスに追加することで、これを克服しようとしました。

_  /**
   * {@inheritdoc}
   */
  public function getCacheableMetadata($name) {
    $metadata = new CacheableMetadata();

    if ($name === 'system.site') {
      $my_entity = MyEntity::Load(1);
      if ($override_required && !empty($my_entity)) {
        // Append entity cache metadata.
        $metadata->addCacheableDependency($my_entity);
      }
      else {
        // Append 'empty' cache metadata.
        $metadata->addCacheContexts(['mycachecontext']);
        $metadata->addCacheTags(['myentity', 'myentity:0']);
      }
    }
    return $metadata;
  }
_

ブロックは_system.site_のキャッシュコンテキストを継承せず、提供されたキャッシュタグ( 'myentity'、 'myentity:0')のいずれも更新または無効化しないため、レンダーキャッシュは引き続き保持されます。 _hook_block_build_BASE_BLOCK_ID_alter_ 実装でシステムブランドブロックにキャッシュコンテキストを追加できますが、すべての状況をカバーすることはないため、このような特定の例外は実装しないことをお勧めします。

すべてのレンダリング可能な要素(ブロック?)を更新し、_system.site_によって提供されるキャッシュタグを継承するものにキャッシュコンテキストを追加するフックを期待しています。しかし、私は他の解決策も受け入れます。

レンダーキャッシュ内のブロックまたはその他のエンティティをどのように作成できますか。これは、構成のオーバーライドを認識している_system.site_構成に依存していますか?

5
Neograph734

その間、私はこのアプローチを考え出しましたが、私は他の解決策にまだオープンです。

キャッシュ可能なメタデータを分解してsystem.siteタグを検索し、独自のコンテキストとタグ(必要な場合)を追加することで、ブロックのpre_renderコールバックに解決策を見つけました。

/**
 * Implements hook_block_view_alter().
 */
functionmymodule_block_view_alter(array &$build, \Drupal\Core\Block\BlockPluginInterface $block) {
  $build['#pre_render'][] = 'mymodule_block_view_pre_render';
}

/**
 * #pre_render callback: Sets my module cache tags.
 */
function mymodule_block_view_pre_render(array $build) {
  $cacheable_metadata = CacheableMetadata::createFromRenderArray($build);
  $tags = $cacheable_metadata->getCacheTags();

  if (in_array('config:system.site', $tags)) {
    // Always add a cache context, so we have a variant without overrides as well.
    $cacheable_metadata->addCacheContexts(['mycontext']);

    if ($entity = MyEntity::Load(1)) {
      $cacheable_metadata->addCacheableDependency($entity );
    }
  }

  $cacheable_metadata->applyTo($build);

  return $build;
}
2
Neograph734