Drupal 8 - 添加自定义缓存上下文
Drupal 8 - Add custom cache context
我遇到以下情况:我想根据当前用户的字段隐藏或显示一些本地任务(选项卡)。因此我实现了 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
我仍然需要清除缓存,因此上下文无法正常工作。谁能指出正确的方向如何解决这个问题或如何调试此类问题?
您应该能够使用 core 提供的默认缓存能力,而不是提供自定义缓存上下文。我认为问题不在于可缓存元数据的创建,似乎您的 hook_menu_local_tasks_alter
正在更改不知道它现在依赖于用户的内容。所以我相信你需要两件事:
- 表示 'this menu content now relies on the user' 的一般缓存上下文,例如。
user
缓存上下文。
- 为特定用户添加缓存标记的附加说明:'once this is cached, when this user entity changes, go regenerate the local tasks for this user'。
请注意,HOOK_menu_local_tasks_alter
为可缓存性提供了一个助手,即 $cacheability
的第三个参数。 Drupal 核心在这里也提供了一种机制,允许我们说 'this piece of cache data relies on this other piece of cache data'。
因此您应该能够执行以下操作:
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 ...
}
我遇到以下情况:我想根据当前用户的字段隐藏或显示一些本地任务(选项卡)。因此我实现了 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
我仍然需要清除缓存,因此上下文无法正常工作。谁能指出正确的方向如何解决这个问题或如何调试此类问题?
您应该能够使用 core 提供的默认缓存能力,而不是提供自定义缓存上下文。我认为问题不在于可缓存元数据的创建,似乎您的 hook_menu_local_tasks_alter
正在更改不知道它现在依赖于用户的内容。所以我相信你需要两件事:
- 表示 'this menu content now relies on the user' 的一般缓存上下文,例如。
user
缓存上下文。 - 为特定用户添加缓存标记的附加说明:'once this is cached, when this user entity changes, go regenerate the local tasks for this user'。
请注意,HOOK_menu_local_tasks_alter
为可缓存性提供了一个助手,即 $cacheability
的第三个参数。 Drupal 核心在这里也提供了一种机制,允许我们说 'this piece of cache data relies on this other piece of cache data'。
因此您应该能够执行以下操作:
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 ...
}