Issue #2443409 by Berdir: Add a way to entity manager to get fresh entity and field definitions without invalidating all caches
parent
71838159fe
commit
2bf5dc11da
|
@ -21,4 +21,17 @@ interface CachedDiscoveryInterface extends DiscoveryInterface {
|
|||
*/
|
||||
public function clearCachedDefinitions();
|
||||
|
||||
/**
|
||||
* Disable the use of caches.
|
||||
*
|
||||
* Can be used to ensure that uncached plugin definitions are returned,
|
||||
* without invalidating all cached information.
|
||||
*
|
||||
* This will also remove all local/static caches.
|
||||
*
|
||||
* @param bool $use_caches
|
||||
* FALSE to not use any caches.
|
||||
*/
|
||||
public function useCaches($use_caches = FALSE);
|
||||
|
||||
}
|
||||
|
|
|
@ -95,7 +95,13 @@ class EntityDefinitionUpdateManager implements EntityDefinitionUpdateManagerInte
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function applyUpdates() {
|
||||
foreach ($this->getChangeList() as $entity_type_id => $change_list) {
|
||||
$change_list = $this->getChangeList();
|
||||
if ($change_list) {
|
||||
// getChangeList() only disables the cache and does not invalidate.
|
||||
// In case there are changes, explictly invalidate caches.
|
||||
$this->entityManager->clearCachedDefinitions();
|
||||
}
|
||||
foreach ($change_list as $entity_type_id => $change_list) {
|
||||
// Process entity type definition changes before storage definitions ones
|
||||
// this is necessary when you change an entity type from non-revisionable
|
||||
// to revisionable and at the same time add revisionable fields to the
|
||||
|
@ -153,7 +159,7 @@ class EntityDefinitionUpdateManager implements EntityDefinitionUpdateManagerInte
|
|||
* - DEFINITION_DELETED
|
||||
*/
|
||||
protected function getChangeList() {
|
||||
$this->entityManager->clearCachedDefinitions();
|
||||
$this->entityManager->useCaches(FALSE);
|
||||
$change_list = array();
|
||||
|
||||
foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) {
|
||||
|
@ -208,6 +214,8 @@ class EntityDefinitionUpdateManager implements EntityDefinitionUpdateManagerInte
|
|||
// @todo Support deleting entity definitions when we support base field
|
||||
// purging. See https://www.drupal.org/node/2282119.
|
||||
|
||||
$this->entityManager->useCaches(TRUE);
|
||||
|
||||
return array_filter($change_list);
|
||||
}
|
||||
|
||||
|
|
|
@ -372,13 +372,13 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
|
|||
if (!isset($this->baseFieldDefinitions[$entity_type_id])) {
|
||||
// Not prepared, try to load from cache.
|
||||
$cid = 'entity_base_field_definitions:' . $entity_type_id . ':' . $this->languageManager->getCurrentLanguage()->getId();
|
||||
if ($cache = $this->cacheBackend->get($cid)) {
|
||||
if ($cache = $this->cacheGet($cid)) {
|
||||
$this->baseFieldDefinitions[$entity_type_id] = $cache->data;
|
||||
}
|
||||
else {
|
||||
// Rebuild the definitions and put it into the cache.
|
||||
$this->baseFieldDefinitions[$entity_type_id] = $this->buildBaseFieldDefinitions($entity_type_id);
|
||||
$this->cacheBackend->set($cid, $this->baseFieldDefinitions[$entity_type_id], Cache::PERMANENT, array('entity_types', 'entity_field_info'));
|
||||
$this->cacheSet($cid, $this->baseFieldDefinitions[$entity_type_id], Cache::PERMANENT, array('entity_types', 'entity_field_info'));
|
||||
}
|
||||
}
|
||||
return $this->baseFieldDefinitions[$entity_type_id];
|
||||
|
@ -470,13 +470,13 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
|
|||
$base_field_definitions = $this->getBaseFieldDefinitions($entity_type_id);
|
||||
// Not prepared, try to load from cache.
|
||||
$cid = 'entity_bundle_field_definitions:' . $entity_type_id . ':' . $bundle . ':' . $this->languageManager->getCurrentLanguage()->getId();
|
||||
if ($cache = $this->cacheBackend->get($cid)) {
|
||||
if ($cache = $this->cacheGet($cid)) {
|
||||
$bundle_field_definitions = $cache->data;
|
||||
}
|
||||
else {
|
||||
// Rebuild the definitions and put it into the cache.
|
||||
$bundle_field_definitions = $this->buildBundleFieldDefinitions($entity_type_id, $bundle, $base_field_definitions);
|
||||
$this->cacheBackend->set($cid, $bundle_field_definitions, Cache::PERMANENT, array('entity_types', 'entity_field_info'));
|
||||
$this->cacheSet($cid, $bundle_field_definitions, Cache::PERMANENT, array('entity_types', 'entity_field_info'));
|
||||
}
|
||||
// Field definitions consist of the bundle specific overrides and the
|
||||
// base fields, merge them together. Use array_replace() to replace base
|
||||
|
@ -578,13 +578,13 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
|
|||
}
|
||||
// Not prepared, try to load from cache.
|
||||
$cid = 'entity_field_storage_definitions:' . $entity_type_id . ':' . $this->languageManager->getCurrentLanguage()->getId();
|
||||
if ($cache = $this->cacheBackend->get($cid)) {
|
||||
if ($cache = $this->cacheGet($cid)) {
|
||||
$field_storage_definitions = $cache->data;
|
||||
}
|
||||
else {
|
||||
// Rebuild the definitions and put it into the cache.
|
||||
$field_storage_definitions = $this->buildFieldStorageDefinitions($entity_type_id);
|
||||
$this->cacheBackend->set($cid, $field_storage_definitions, Cache::PERMANENT, array('entity_types', 'entity_field_info'));
|
||||
$this->cacheSet($cid, $field_storage_definitions, Cache::PERMANENT, array('entity_types', 'entity_field_info'));
|
||||
}
|
||||
$this->fieldStorageDefinitions[$entity_type_id] += $field_storage_definitions;
|
||||
}
|
||||
|
@ -598,7 +598,7 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
|
|||
if (!$this->fieldMap) {
|
||||
// Not prepared, try to load from cache.
|
||||
$cid = 'entity_field_map';
|
||||
if ($cache = $this->cacheBackend->get($cid)) {
|
||||
if ($cache = $this->cacheGet($cid)) {
|
||||
$this->fieldMap = $cache->data;
|
||||
}
|
||||
else {
|
||||
|
@ -614,7 +614,7 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
|
|||
}
|
||||
}
|
||||
|
||||
$this->cacheBackend->set($cid, $this->fieldMap, Cache::PERMANENT, array('entity_types', 'entity_field_info'));
|
||||
$this->cacheSet($cid, $this->fieldMap, Cache::PERMANENT, array('entity_types', 'entity_field_info'));
|
||||
}
|
||||
}
|
||||
return $this->fieldMap;
|
||||
|
@ -717,7 +717,7 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
|
|||
public function getAllBundleInfo() {
|
||||
if (empty($this->bundleInfo)) {
|
||||
$langcode = $this->languageManager->getCurrentLanguage()->getId();
|
||||
if ($cache = $this->cacheBackend->get("entity_bundle_info:$langcode")) {
|
||||
if ($cache = $this->cacheGet("entity_bundle_info:$langcode")) {
|
||||
$this->bundleInfo = $cache->data;
|
||||
}
|
||||
else {
|
||||
|
@ -738,7 +738,7 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
|
|||
}
|
||||
}
|
||||
$this->moduleHandler->alter('entity_bundle_info', $this->bundleInfo);
|
||||
$this->cacheBackend->set("entity_bundle_info:$langcode", $this->bundleInfo, Cache::PERMANENT, array('entity_types', 'entity_bundles'));
|
||||
$this->cacheSet("entity_bundle_info:$langcode", $this->bundleInfo, Cache::PERMANENT, array('entity_types', 'entity_bundles'));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -758,7 +758,7 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
|
|||
// hook_entity_extra_field_info_alter() might contain t() calls, we cache
|
||||
// per language.
|
||||
$cache_id = 'entity_bundle_extra_fields:' . $entity_type_id . ':' . $bundle . ':' . $this->languageManager->getCurrentLanguage()->getId();
|
||||
$cached = $this->cacheBackend->get($cache_id);
|
||||
$cached = $this->cacheGet($cache_id);
|
||||
if ($cached) {
|
||||
$this->extraFields[$entity_type_id][$bundle] = $cached->data;
|
||||
return $this->extraFields[$entity_type_id][$bundle];
|
||||
|
@ -774,7 +774,7 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
|
|||
|
||||
// Store in the 'static' and persistent caches.
|
||||
$this->extraFields[$entity_type_id][$bundle] = $info;
|
||||
$this->cacheBackend->set($cache_id, $info, Cache::PERMANENT, array(
|
||||
$this->cacheSet($cache_id, $info, Cache::PERMANENT, array(
|
||||
'entity_field_info',
|
||||
));
|
||||
|
||||
|
@ -886,7 +886,7 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
|
|||
$key = 'entity_' . $display_type . '_info';
|
||||
$entity_type_id = 'entity_' . $display_type;
|
||||
$langcode = $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_INTERFACE)->getId();
|
||||
if ($cache = $this->cacheBackend->get("$key:$langcode")) {
|
||||
if ($cache = $this->cacheGet("$key:$langcode")) {
|
||||
$this->displayModeInfo[$display_type] = $cache->data;
|
||||
}
|
||||
else {
|
||||
|
@ -896,7 +896,7 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
|
|||
$this->displayModeInfo[$display_type][$display_mode_entity_type][$display_mode_name] = $display_mode->toArray();
|
||||
}
|
||||
$this->moduleHandler->alter($key, $this->displayModeInfo[$display_type]);
|
||||
$this->cacheBackend->set("$key:$langcode", $this->displayModeInfo[$display_type], CacheBackendInterface::CACHE_PERMANENT, array('entity_types', 'entity_field_info'));
|
||||
$this->cacheSet("$key:$langcode", $this->displayModeInfo[$display_type], CacheBackendInterface::CACHE_PERMANENT, array('entity_types', 'entity_field_info'));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1206,6 +1206,19 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
|
|||
return $this->installedDefinitions->get($entity_type_id . '.entity_type');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function useCaches($use_caches = FALSE) {
|
||||
parent::useCaches($use_caches);
|
||||
if (!$use_caches) {
|
||||
$this->handlers = [];
|
||||
$this->fieldDefinitions = [];
|
||||
$this->baseFieldDefinitions = [];
|
||||
$this->fieldStorageDefinitions = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the entity type definition in the application state.
|
||||
*
|
||||
|
|
|
@ -7,13 +7,14 @@
|
|||
|
||||
namespace Drupal\Core\Entity;
|
||||
|
||||
use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface;
|
||||
use Drupal\Component\Plugin\PluginManagerInterface;
|
||||
use Drupal\Core\Field\FieldStorageDefinitionListenerInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface for entity type managers.
|
||||
*/
|
||||
interface EntityManagerInterface extends PluginManagerInterface, EntityTypeListenerInterface, EntityBundleListenerInterface, FieldStorageDefinitionListenerInterface {
|
||||
interface EntityManagerInterface extends PluginManagerInterface, EntityTypeListenerInterface, EntityBundleListenerInterface, FieldStorageDefinitionListenerInterface, CachedDiscoveryInterface {
|
||||
|
||||
/**
|
||||
* Builds a list of entity type labels suitable for a Form API options list.
|
||||
|
|
|
@ -80,6 +80,13 @@ class DefaultPluginManager extends PluginManagerBase implements PluginManagerInt
|
|||
*/
|
||||
protected $defaults = array();
|
||||
|
||||
/**
|
||||
* Flag whether persistent caches should be used.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $useCaches = TRUE;
|
||||
|
||||
/**
|
||||
* Creates the discovery object.
|
||||
*
|
||||
|
@ -180,7 +187,7 @@ class DefaultPluginManager extends PluginManagerBase implements PluginManagerInt
|
|||
* and would actually be returned by the getDefinitions() method.
|
||||
*/
|
||||
protected function getCachedDefinitions() {
|
||||
if (!isset($this->definitions) && $this->cacheBackend && $cache = $this->cacheBackend->get($this->cacheKey)) {
|
||||
if (!isset($this->definitions) && $cache = $this->cacheGet($this->cacheKey)) {
|
||||
$this->definitions = $cache->data;
|
||||
}
|
||||
return $this->definitions;
|
||||
|
@ -193,12 +200,43 @@ class DefaultPluginManager extends PluginManagerBase implements PluginManagerInt
|
|||
* List of definitions to store in cache.
|
||||
*/
|
||||
protected function setCachedDefinitions($definitions) {
|
||||
if ($this->cacheBackend) {
|
||||
$this->cacheBackend->set($this->cacheKey, $definitions, Cache::PERMANENT, $this->cacheTags);
|
||||
}
|
||||
$this->cacheSet($this->cacheKey, $definitions, Cache::PERMANENT, $this->cacheTags);
|
||||
$this->definitions = $definitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function useCaches($use_caches = FALSE) {
|
||||
$this->useCaches = $use_caches;
|
||||
if (!$use_caches) {
|
||||
$this->definitions = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches from the cache backend, respecting the use caches flag.
|
||||
*
|
||||
* @see \Drupal\Core\Cache\CacheBackendInterface::get()
|
||||
*/
|
||||
protected function cacheGet($cid) {
|
||||
if ($this->useCaches && $this->cacheBackend) {
|
||||
return $this->cacheBackend->get($cid);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores data in the persistent cache, respecting the use caches flag.
|
||||
*
|
||||
* @see \Drupal\Core\Cache\CacheBackendInterface::set()
|
||||
*/
|
||||
protected function cacheSet($cid, $data, $expire = Cache::PERMANENT, array $tags = array()) {
|
||||
if ($this->cacheBackend && $this->useCaches) {
|
||||
$this->cacheBackend->set($cid, $data, $expire, $tags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Performs extra processing on plugin definitions.
|
||||
|
|
|
@ -44,7 +44,6 @@ trait EntityDefinitionTestTrait {
|
|||
$entity_type->set('entity_keys', $keys);
|
||||
|
||||
$this->state->set('entity_test_update.entity_type', $entity_type);
|
||||
$this->entityManager->clearCachedDefinitions();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,7 +57,6 @@ trait EntityDefinitionTestTrait {
|
|||
$entity_type->set('entity_keys', $keys);
|
||||
|
||||
$this->state->set('entity_test_update.entity_type', $entity_type);
|
||||
$this->entityManager->clearCachedDefinitions();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -75,7 +73,6 @@ trait EntityDefinitionTestTrait {
|
|||
}
|
||||
|
||||
$this->state->set('entity_test_update.entity_type', $entity_type);
|
||||
$this->entityManager->clearCachedDefinitions();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -92,7 +89,6 @@ trait EntityDefinitionTestTrait {
|
|||
}
|
||||
|
||||
$this->state->set('entity_test_update.entity_type', $entity_type);
|
||||
$this->entityManager->clearCachedDefinitions();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -106,7 +102,6 @@ trait EntityDefinitionTestTrait {
|
|||
->setName('new_base_field')
|
||||
->setLabel(t('A new base field'));
|
||||
$this->state->set('entity_test_update.additional_base_field_definitions', $definitions);
|
||||
$this->entityManager->clearCachedDefinitions();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -121,7 +116,6 @@ trait EntityDefinitionTestTrait {
|
|||
->setLabel(t('A new revisionable base field'))
|
||||
->setRevisionable(TRUE);
|
||||
$this->state->set('entity_test_update.additional_base_field_definitions', $definitions);
|
||||
$this->entityManager->clearCachedDefinitions();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -136,7 +130,6 @@ trait EntityDefinitionTestTrait {
|
|||
*/
|
||||
protected function removeBaseField() {
|
||||
$this->state->delete('entity_test_update.additional_base_field_definitions');
|
||||
$this->entityManager->clearCachedDefinitions();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -144,7 +137,6 @@ trait EntityDefinitionTestTrait {
|
|||
*/
|
||||
protected function addBaseFieldIndex() {
|
||||
$this->state->set('entity_test_update.additional_field_index.entity_test_update.new_base_field', TRUE);
|
||||
$this->entityManager->clearCachedDefinitions();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -152,7 +144,6 @@ trait EntityDefinitionTestTrait {
|
|||
*/
|
||||
protected function removeBaseFieldIndex() {
|
||||
$this->state->delete('entity_test_update.additional_field_index.entity_test_update.new_base_field');
|
||||
$this->entityManager->clearCachedDefinitions();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -168,7 +159,6 @@ trait EntityDefinitionTestTrait {
|
|||
->setTargetEntityTypeId('entity_test_update');
|
||||
$this->state->set('entity_test_update.additional_field_storage_definitions', $definitions);
|
||||
$this->state->set('entity_test_update.additional_bundle_field_definitions.test_bundle', $definitions);
|
||||
$this->entityManager->clearCachedDefinitions();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -184,7 +174,6 @@ trait EntityDefinitionTestTrait {
|
|||
protected function removeBundleField() {
|
||||
$this->state->delete('entity_test_update.additional_field_storage_definitions');
|
||||
$this->state->delete('entity_test_update.additional_bundle_field_definitions.test_bundle');
|
||||
$this->entityManager->clearCachedDefinitions();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -215,7 +204,6 @@ trait EntityDefinitionTestTrait {
|
|||
$entity_type->set('base_table', 'entity_test_update_new');
|
||||
|
||||
$this->state->set('entity_test_update.entity_type', $entity_type);
|
||||
$this->entityManager->clearCachedDefinitions();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -227,7 +215,6 @@ trait EntityDefinitionTestTrait {
|
|||
$entity_type->set('data_table', 'entity_test_update_data_new');
|
||||
|
||||
$this->state->set('entity_test_update.entity_type', $entity_type);
|
||||
$this->entityManager->clearCachedDefinitions();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -239,7 +226,6 @@ trait EntityDefinitionTestTrait {
|
|||
$entity_type->set('revision_table', 'entity_test_update_revision_new');
|
||||
|
||||
$this->state->set('entity_test_update.entity_type', $entity_type);
|
||||
$this->entityManager->clearCachedDefinitions();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -251,7 +237,6 @@ trait EntityDefinitionTestTrait {
|
|||
$entity_type->set('revision_data_table', 'entity_test_update_revision_data_new');
|
||||
|
||||
$this->state->set('entity_test_update.entity_type', $entity_type);
|
||||
$this->entityManager->clearCachedDefinitions();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -259,7 +244,6 @@ trait EntityDefinitionTestTrait {
|
|||
*/
|
||||
protected function deleteEntityType() {
|
||||
$this->state->set('entity_test_update.entity_type', 'null');
|
||||
$this->entityManager->clearCachedDefinitions();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -208,6 +208,9 @@ class ViewsEntitySchemaSubscriberIntegrationTest extends ViewUnitTestBase {
|
|||
*/
|
||||
public function testRevisionDataTableRename() {
|
||||
$this->updateEntityTypeToRevisionable();
|
||||
// Multiple changes, so we have to invalidate the caches, otherwise
|
||||
// the second update will revert the first.
|
||||
$this->entityManager->clearCachedDefinitions();
|
||||
$this->updateEntityTypeToTranslatable();
|
||||
$this->entityDefinitionUpdateManager->applyUpdates();
|
||||
|
||||
|
@ -414,6 +417,10 @@ class ViewsEntitySchemaSubscriberIntegrationTest extends ViewUnitTestBase {
|
|||
public function testVariousTableUpdatesForRevisionView() {
|
||||
// base + revision <-> base + translation + revision
|
||||
$this->updateEntityTypeToRevisionable();
|
||||
// Multiple changes, so we have to invalidate the caches, otherwise
|
||||
// the second update will revert the first.
|
||||
$this->entityManager->clearCachedDefinitions();
|
||||
|
||||
list($view, $display) = $this->getUpdatedViewAndDisplay(TRUE);
|
||||
|
||||
$this->assertEqual('entity_test_update_revision', $view->get('base_table'));
|
||||
|
|
|
@ -185,6 +185,30 @@ class DefaultPluginManagerTest extends UnitTestCase {
|
|||
$this->assertEquals($this->expectedDefinitions, $plugin_manager->getDefinitions());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the plugin manager with caching disabled.
|
||||
*/
|
||||
public function testDefaultPluginManagerNoCache() {
|
||||
$plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions, NULL, NULL, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
|
||||
|
||||
$cid = $this->randomMachineName();
|
||||
$cache_backend = $this->getMockBuilder('Drupal\Core\Cache\MemoryBackend')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$cache_backend
|
||||
->expects($this->never())
|
||||
->method('get');
|
||||
$cache_backend
|
||||
->expects($this->never())
|
||||
->method('set');
|
||||
$plugin_manager->setCacheBackend($cache_backend, $cid);
|
||||
|
||||
$plugin_manager->useCaches(FALSE);
|
||||
|
||||
$this->assertEquals($this->expectedDefinitions, $plugin_manager->getDefinitions());
|
||||
$this->assertEquals($this->expectedDefinitions['banana'], $plugin_manager->getDefinition('banana'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the plugin manager cache clear with tags.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue