【问题标题】:Drupal 8 - Add custom cache contextDrupal 8 - 添加自定义缓存上下文
【发布时间】:2019-06-15 05:13:14
【问题描述】:

我有以下情况:我想根据当前用户的某个字段隐藏或显示一些本地任务(选项卡)。因此我实现了hook_menu_local_tasks_alter() in my_module/my_module.module

function my_module_menu_local_tasks_alter(&$data, $route_name, \Drupal\Core\Cache\RefinableCacheableDependencyInterface &$cacheability) {
  ... some logic ...

  if ($user->get('field_my_field')->getValue() === 'some value')
    unset($data['tabs'][0]['unwanted_tab_0']);
    unset($data['tabs'][0]['unwanted_tab_1']);

  ... some logic ...
}

这很好,但如果field_my_field 的值发生变化,我需要清除缓存。

所以我发现我需要在我的my_module_menu_local_tasks_alter 中实现这样的缓存上下文:

$cacheability
  ->addCacheTags([
    'user.available_regions',
  ]);

我已经这样定义了我的缓存上下文:

my_module/my_module.services.yml:

services:
  cache_context.user.available_regions:
    class: Drupal\my_module\CacheContext\AvailableRegions
    arguments: ['@current_user']
    tags:
      - { name: cache.context }

my_module/src/CacheCotext/AvailableRegions.php:

<?php

namespace Drupal\content_sharing\CacheContext;

use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Cache\Context\CacheContextInterface;
use Drupal\Core\Session\AccountProxyInterface;

/**
* Class AvailableRegions.
*/
class AvailableRegions implements CacheContextInterface {

  protected $currentUser;

  /**
   * Constructs a new DefaultCacheContext object.
   */
  public function __construct(AccountProxyInterface $current_user) {
    $this->currentUser = $current_user;
  }

  /**
  * {@inheritdoc}
  */
  public static function getLabel() {
    return t('Available sub pages.');
  }

  /**
  * {@inheritdoc}
  */
  public function getContext() {
    // Actual logic of context variation will lie here.
    $field_published_sites = $this->get('field_published_sites')->getValue();

    $sites = [];
    foreach ($field_published_sites as $site) {
      $sites[] = $site['target_id'];
    }

    return implode('|', $sites);
  }

  /**
  * {@inheritdoc}
  */
  public function getCacheableMetadata() {
    return new CacheableMetadata();
  }

}

但是每次我更改我的字段field_my_field 的值时,我仍然需要清除缓存,因此上下文不起作用。谁能指出我正确的方向如何解决这个问题或如何调试这种事情?

【问题讨论】:

    标签: caching drupal drupal-8


    【解决方案1】:

    您应该能够使用核心提供的默认缓存能力,而不是提供自定义缓存上下文。我认为问题不在于可缓存元数据的创建,您的hook_menu_local_tasks_alter 似乎正在更改不知道它现在依赖于用户的内容。所以我相信你需要两件事:

    1. 表示“此菜单内容现在依赖于用户”的常规缓存上下文,例如。 user 缓存上下文。
    2. 额外使用缓存标签让特定用户说:'一旦缓存,当这个用户实体改变时,去为这个用户重新生成本地任务'。

    请注意,HOOK_menu_local_tasks_alter 提供了一个可缓存性助手,即$cacheability 的第三个参数。 Drupal 核心在这里还提供了一种机制,允许我们说“这条缓存数据依赖于另一条缓存数据”。

    因此,您应该能够执行以下操作:

    function my_module_menu_local_tasks_alter(&$data, $route_name, RefinableCacheableDependencyInterface &$cacheability) {
      ... some logic ...
    
      // We are going to alter content by user.
      $cacheability->addCacheableDependency($user);
    
      // Note if you still really need your custom context, you could add it.
      // Also note that any user.* contexts should already be covered above.
      $cacheability->addCacheContexts(['some_custom_contexts']);
    
      if ($user->get('field_my_field')->getValue() === 'some value')
        unset($data['tabs'][0]['unwanted_tab_0']);
        unset($data['tabs'][0]['unwanted_tab_1']);
    
      ... some logic ...
    }
    

    【讨论】:

    • 这行得通!我还在我的自定义缓存上下文中更改了这一点(类似于您建议的默认缓存性)$this-&gt;currentUser = User::load($current_user-&gt;id());(在my_module/src/CacheCotext/AvailableRegions.php 的构造函数中)
    猜你喜欢
    • 2016-10-05
    • 2018-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-02
    • 2017-05-28
    • 1970-01-01
    • 2018-07-24
    相关资源
    最近更新 更多