class ConfigEntityStorage in Drupal 8
Same name and namespace in other branches
- 9 core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php \Drupal\Core\Config\Entity\ConfigEntityStorage
Defines the storage class for configuration entities.
Configuration object names of configuration entities are comprised of two parts, separated by a dot:
- config_prefix: A string denoting the owner (module/extension) of the configuration object, followed by arbitrary other namespace identifiers that are declared by the owning extension; e.g., 'node.type'. The config_prefix does NOT contain a trailing dot. It is defined by the entity type's annotation.
- ID: A string denoting the entity ID within the entity type namespace; e.g., 'article'. Entity IDs may contain dots/periods. The entire remaining string after the config_prefix in a config name forms the entity ID. Additional or custom suffixes are not possible.
Hierarchy
- class \Drupal\Core\Entity\EntityHandlerBase uses DependencySerializationTrait, StringTranslationTrait
- class \Drupal\Core\Entity\EntityStorageBase implements EntityHandlerInterface, EntityStorageInterface
- class \Drupal\Core\Config\Entity\ConfigEntityStorage implements ConfigEntityStorageInterface, ImportableEntityStorageInterface
- class \Drupal\Core\Entity\EntityStorageBase implements EntityHandlerInterface, EntityStorageInterface
Expanded class hierarchy of ConfigEntityStorage
Related topics
16 files declare their use of ConfigEntityStorage
- BlockStorageUnitTest.php in core/
modules/ block/ tests/ src/ Kernel/ BlockStorageUnitTest.php - BundleConfigImportValidate.php in core/
lib/ Drupal/ Core/ Entity/ Event/ BundleConfigImportValidate.php - ConfigDependencyWebTest.php in core/
modules/ config/ tests/ src/ Functional/ ConfigDependencyWebTest.php - ConfigEntityStorageTest.php in core/
tests/ Drupal/ Tests/ Core/ Config/ Entity/ ConfigEntityStorageTest.php - ConfigEntityTest.php in core/
modules/ config/ tests/ src/ Functional/ ConfigEntityTest.php
File
- core/
lib/ Drupal/ Core/ Config/ Entity/ ConfigEntityStorage.php, line 36
Namespace
Drupal\Core\Config\EntityView source
class ConfigEntityStorage extends EntityStorageBase implements ConfigEntityStorageInterface, ImportableEntityStorageInterface {
/**
* Length limit of the configuration entity ID.
*
* Most file systems limit a file name's length to 255 characters, so
* ConfigBase::MAX_NAME_LENGTH restricts the full configuration object name
* to 250 characters (leaving 5 for the file extension). The config prefix
* is limited by ConfigEntityType::PREFIX_LENGTH to 83 characters, so this
* leaves 166 remaining characters for the configuration entity ID, with 1
* additional character needed for the joining dot.
*
* @see \Drupal\Core\Config\ConfigBase::MAX_NAME_LENGTH
* @see \Drupal\Core\Config\Entity\ConfigEntityType::PREFIX_LENGTH
*/
const MAX_ID_LENGTH = 166;
/**
* {@inheritdoc}
*/
protected $uuidKey = 'uuid';
/**
* The config factory service.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* The config storage service.
*
* @var \Drupal\Core\Config\StorageInterface
*/
protected $configStorage;
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
/**
* Static cache of entities, keyed first by entity ID, then by an extra key.
*
* The additional cache key is to maintain separate caches for different
* states of config overrides.
*
* @var array
* @see \Drupal\Core\Config\ConfigFactoryInterface::getCacheKeys().
*/
protected $entities = [];
/**
* Determines if the underlying configuration is retrieved override free.
*
* @var bool
*/
protected $overrideFree = FALSE;
/**
* Constructs a ConfigEntityStorage object.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The entity type definition.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory service.
* @param \Drupal\Component\Uuid\UuidInterface $uuid_service
* The UUID service.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
* @param \Drupal\Core\Cache\MemoryCache\MemoryCacheInterface|null $memory_cache
* The memory cache backend.
*/
public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, UuidInterface $uuid_service, LanguageManagerInterface $language_manager, MemoryCacheInterface $memory_cache = NULL) {
parent::__construct($entity_type, $memory_cache);
$this->configFactory = $config_factory;
$this->uuidService = $uuid_service;
$this->languageManager = $language_manager;
}
/**
* {@inheritdoc}
*/
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
return new static($entity_type, $container
->get('config.factory'), $container
->get('uuid'), $container
->get('language_manager'), $container
->get('entity.memory_cache'));
}
/**
* {@inheritdoc}
*/
public function loadRevision($revision_id) {
return NULL;
}
/**
* {@inheritdoc}
*/
public function deleteRevision($revision_id) {
return NULL;
}
/**
* Returns the prefix used to create the configuration name.
*
* The prefix consists of the config prefix from the entity type plus a dot
* for separating from the ID.
*
* @return string
* The full configuration prefix, for example 'views.view.'.
*/
protected function getPrefix() {
return $this->entityType
->getConfigPrefix() . '.';
}
/**
* {@inheritdoc}
*/
public static function getIDFromConfigName($config_name, $config_prefix) {
return substr($config_name, strlen($config_prefix . '.'));
}
/**
* {@inheritdoc}
*/
protected function doLoadMultiple(array $ids = NULL) {
$prefix = $this
->getPrefix();
// Get the names of the configuration entities we are going to load.
if ($ids === NULL) {
$names = $this->configFactory
->listAll($prefix);
}
else {
$names = [];
foreach ($ids as $id) {
// Add the prefix to the ID to serve as the configuration object name.
$names[] = $prefix . $id;
}
}
// Load all of the configuration entities.
/** @var \Drupal\Core\Config\Config[] $configs */
$configs = [];
$records = [];
foreach ($this->configFactory
->loadMultiple($names) as $config) {
$id = $config
->get($this->idKey);
$records[$id] = $this->overrideFree ? $config
->getOriginal(NULL, FALSE) : $config
->get();
$configs[$id] = $config;
}
$entities = $this
->mapFromStorageRecords($records, $configs);
// Config entities wrap config objects, and therefore they need to inherit
// the cacheability metadata of config objects (to ensure e.g. additional
// cacheability metadata added by config overrides is not lost).
foreach ($entities as $id => $entity) {
// But rather than simply inheriting all cacheability metadata of config
// objects, we need to make sure the self-referring cache tag that is
// present on Config objects is not added to the Config entity. It must be
// removed for 3 reasons:
// 1. When renaming/duplicating a Config entity, the cache tag of the
// original config object would remain present, which would be wrong.
// 2. Some Config entities choose to not use the cache tag that the under-
// lying Config object provides by default (For performance and
// cacheability reasons it may not make sense to have a unique cache
// tag for every Config entity. The DateFormat Config entity specifies
// the 'rendered' cache tag for example, because A) date formats are
// changed extremely rarely, so invalidating all render cache items is
// fine, B) it means fewer cache tags per page.).
// 3. Fewer cache tags is better for performance.
$self_referring_cache_tag = [
'config:' . $configs[$id]
->getName(),
];
$config_cacheability = CacheableMetadata::createFromObject($configs[$id]);
$config_cacheability
->setCacheTags(array_diff($config_cacheability
->getCacheTags(), $self_referring_cache_tag));
$entity
->addCacheableDependency($config_cacheability);
}
return $entities;
}
/**
* {@inheritdoc}
*/
protected function doCreate(array $values) {
// Set default language to current language if not provided.
$values += [
$this->langcodeKey => $this->languageManager
->getCurrentLanguage()
->getId(),
];
$entity = new $this->entityClass($values, $this->entityTypeId);
return $entity;
}
/**
* {@inheritdoc}
*/
protected function doDelete($entities) {
foreach ($entities as $entity) {
$this->configFactory
->getEditable($this
->getPrefix() . $entity
->id())
->delete();
}
}
/**
* Implements Drupal\Core\Entity\EntityStorageInterface::save().
*
* @throws \Drupal\Core\Entity\EntityMalformedException
* When attempting to save a configuration entity that has no ID.
*/
public function save(EntityInterface $entity) {
// Configuration entity IDs are strings, and '0' is a valid ID.
$id = $entity
->id();
if ($id === NULL || $id === '') {
throw new EntityMalformedException('The entity does not have an ID.');
}
// Check the configuration entity ID length.
// @see \Drupal\Core\Config\Entity\ConfigEntityStorage::MAX_ID_LENGTH
// @todo Consider moving this to a protected method on the parent class, and
// abstracting it for all entity types.
if (strlen($entity
->get($this->idKey)) > static::MAX_ID_LENGTH) {
throw new ConfigEntityIdLengthException("Configuration entity ID {$entity->get($this->idKey)} exceeds maximum allowed length of " . static::MAX_ID_LENGTH . " characters.");
}
return parent::save($entity);
}
/**
* {@inheritdoc}
*/
protected function doSave($id, EntityInterface $entity) {
$is_new = $entity
->isNew();
$prefix = $this
->getPrefix();
$config_name = $prefix . $entity
->id();
if ($id !== $entity
->id()) {
// Renaming a config object needs to cater for:
// - Storage needs to access the original object.
// - The object needs to be renamed/copied in ConfigFactory and reloaded.
// - All instances of the object need to be renamed.
$this->configFactory
->rename($prefix . $id, $config_name);
}
$config = $this->configFactory
->getEditable($config_name);
// Retrieve the desired properties and set them in config.
$config
->setData($this
->mapToStorageRecord($entity));
$config
->save($entity
->hasTrustedData());
// Update the entity with the values stored in configuration. It is possible
// that configuration schema has casted some of the values.
if (!$entity
->hasTrustedData()) {
$data = $this
->mapFromStorageRecords([
$config
->get(),
]);
$updated_entity = current($data);
foreach (array_keys($config
->get()) as $property) {
$value = $updated_entity
->get($property);
$entity
->set($property, $value);
}
}
return $is_new ? SAVED_NEW : SAVED_UPDATED;
}
/**
* Maps from an entity object to the storage record.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity object.
*
* @return array
* The record to store.
*/
protected function mapToStorageRecord(EntityInterface $entity) {
return $entity
->toArray();
}
/**
* {@inheritdoc}
*/
protected function has($id, EntityInterface $entity) {
$prefix = $this
->getPrefix();
$config = $this->configFactory
->get($prefix . $id);
return !$config
->isNew();
}
/**
* {@inheritdoc}
*/
public function hasData() {
return (bool) $this->configFactory
->listAll($this
->getPrefix());
}
/**
* {@inheritdoc}
*/
protected function buildCacheId($id) {
return parent::buildCacheId($id) . ':' . ($this->overrideFree ? '' : implode(':', $this->configFactory
->getCacheKeys()));
}
/**
* Invokes a hook on behalf of the entity.
*
* @param $hook
* One of 'presave', 'insert', 'update', 'predelete', or 'delete'.
* @param $entity
* The entity object.
*/
protected function invokeHook($hook, EntityInterface $entity) {
// Invoke the hook.
$this->moduleHandler
->invokeAll($this->entityTypeId . '_' . $hook, [
$entity,
]);
// Invoke the respective entity-level hook.
$this->moduleHandler
->invokeAll('entity_' . $hook, [
$entity,
$this->entityTypeId,
]);
}
/**
* {@inheritdoc}
*/
protected function getQueryServiceName() {
return 'entity.query.config';
}
/**
* {@inheritdoc}
*/
public function importCreate($name, Config $new_config, Config $old_config) {
$entity = $this
->_doCreateFromStorageRecord($new_config
->get(), TRUE);
$entity
->save();
return TRUE;
}
/**
* {@inheritdoc}
*/
public function importUpdate($name, Config $new_config, Config $old_config) {
$id = static::getIDFromConfigName($name, $this->entityType
->getConfigPrefix());
$entity = $this
->load($id);
if (!$entity) {
throw new ConfigImporterException("Attempt to update non-existing entity '{$id}'.");
}
$entity
->setSyncing(TRUE);
$entity = $this
->updateFromStorageRecord($entity, $new_config
->get());
$entity
->save();
return TRUE;
}
/**
* {@inheritdoc}
*/
public function importDelete($name, Config $new_config, Config $old_config) {
$id = static::getIDFromConfigName($name, $this->entityType
->getConfigPrefix());
$entity = $this
->load($id);
$entity
->setSyncing(TRUE);
$entity
->delete();
return TRUE;
}
/**
* {@inheritdoc}
*/
public function importRename($old_name, Config $new_config, Config $old_config) {
return $this
->importUpdate($old_name, $new_config, $old_config);
}
/**
* {@inheritdoc}
*/
public function createFromStorageRecord(array $values) {
return $this
->_doCreateFromStorageRecord($values);
}
/**
* Helps create a configuration entity from storage values.
*
* Allows the configuration entity storage to massage storage values before
* creating an entity.
*
* @param array $values
* The array of values from the configuration storage.
* @param bool $is_syncing
* Is the configuration entity being created as part of a config sync.
*
* @return \Drupal\Core\Config\ConfigEntityInterface
* The configuration entity.
*
* @see \Drupal\Core\Config\Entity\ConfigEntityStorageInterface::createFromStorageRecord()
* @see \Drupal\Core\Config\Entity\ImportableEntityStorageInterface::importCreate()
*/
protected function _doCreateFromStorageRecord(array $values, $is_syncing = FALSE) {
// Assign a new UUID if there is none yet.
if ($this->uuidKey && $this->uuidService && !isset($values[$this->uuidKey])) {
$values[$this->uuidKey] = $this->uuidService
->generate();
}
$data = $this
->mapFromStorageRecords([
$values,
]);
$entity = current($data);
$entity->original = clone $entity;
$entity
->setSyncing($is_syncing);
$entity
->enforceIsNew();
$entity
->postCreate($this);
// Modules might need to add or change the data initially held by the new
// entity object, for instance to fill-in default values.
$this
->invokeHook('create', $entity);
return $entity;
}
/**
* {@inheritdoc}
*/
public function updateFromStorageRecord(ConfigEntityInterface $entity, array $values) {
$entity->original = clone $entity;
$data = $this
->mapFromStorageRecords([
$values,
]);
$updated_entity = current($data);
/** @var \Drupal\Core\Config\Entity\ConfigEntityTypeInterface $entity_type */
$entity_type = $this
->getEntityType();
$id_key = $entity_type
->getKey('id');
$properties = $entity_type
->getPropertiesToExport($updated_entity
->get($id_key));
if (empty($properties)) {
// Fallback to using the provided values. If the properties cannot be
// determined for the config entity type annotation or configuration
// schema.
$properties = array_keys($values);
}
foreach ($properties as $property) {
if ($property === $this->uuidKey) {
// During an update the UUID field should not be copied. Under regular
// circumstances the values will be equal. If configuration is written
// twice during configuration install the updated entity will not have a
// UUID.
// @see \Drupal\Core\Config\ConfigInstaller::createConfiguration()
continue;
}
$entity
->set($property, $updated_entity
->get($property));
}
return $entity;
}
/**
* {@inheritdoc}
*/
public function loadOverrideFree($id) {
$entities = $this
->loadMultipleOverrideFree([
$id,
]);
return isset($entities[$id]) ? $entities[$id] : NULL;
}
/**
* {@inheritdoc}
*/
public function loadMultipleOverrideFree(array $ids = NULL) {
$this->overrideFree = TRUE;
$entities = $this
->loadMultiple($ids);
$this->overrideFree = FALSE;
return $entities;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
ConfigEntityStorage:: |
protected | property | The config factory service. | |
ConfigEntityStorage:: |
protected | property | The config storage service. | |
ConfigEntityStorage:: |
protected | property | Static cache of entities, keyed first by entity ID, then by an extra key. | |
ConfigEntityStorage:: |
protected | property | The language manager. | |
ConfigEntityStorage:: |
protected | property | Determines if the underlying configuration is retrieved override free. | |
ConfigEntityStorage:: |
protected | property |
Name of entity's UUID database table field, if it supports UUIDs. Overrides EntityStorageBase:: |
|
ConfigEntityStorage:: |
protected | function |
Builds the cache ID for the passed in entity ID. Overrides EntityStorageBase:: |
|
ConfigEntityStorage:: |
public | function |
Creates a configuration entity from storage values. Overrides ConfigEntityStorageInterface:: |
|
ConfigEntityStorage:: |
public static | function |
Instantiates a new instance of this entity handler. Overrides EntityHandlerInterface:: |
4 |
ConfigEntityStorage:: |
public | function |
Delete a specific entity revision. Overrides EntityStorageInterface:: |
|
ConfigEntityStorage:: |
protected | function |
Performs storage-specific creation of entities. Overrides EntityStorageBase:: |
|
ConfigEntityStorage:: |
protected | function |
Performs storage-specific entity deletion. Overrides EntityStorageBase:: |
|
ConfigEntityStorage:: |
protected | function |
Performs storage-specific loading of entities. Overrides EntityStorageBase:: |
|
ConfigEntityStorage:: |
protected | function |
Performs storage-specific saving of the entity. Overrides EntityStorageBase:: |
|
ConfigEntityStorage:: |
public static | function |
Extracts the configuration entity ID from the full configuration name. Overrides ConfigEntityStorageInterface:: |
|
ConfigEntityStorage:: |
protected | function | Returns the prefix used to create the configuration name. | |
ConfigEntityStorage:: |
protected | function |
Gets the name of the service for the query for this entity storage. Overrides EntityStorageBase:: |
|
ConfigEntityStorage:: |
protected | function |
Determines if this entity already exists in storage. Overrides EntityStorageBase:: |
|
ConfigEntityStorage:: |
public | function |
Determines if the storage contains any data. Overrides EntityStorageBase:: |
|
ConfigEntityStorage:: |
public | function |
Creates entities upon synchronizing configuration changes. Overrides ImportableEntityStorageInterface:: |
1 |
ConfigEntityStorage:: |
public | function |
Delete entities upon synchronizing configuration changes. Overrides ImportableEntityStorageInterface:: |
2 |
ConfigEntityStorage:: |
public | function |
Renames entities upon synchronizing configuration changes. Overrides ImportableEntityStorageInterface:: |
|
ConfigEntityStorage:: |
public | function |
Updates entities upon synchronizing configuration changes. Overrides ImportableEntityStorageInterface:: |
1 |
ConfigEntityStorage:: |
protected | function |
Invokes a hook on behalf of the entity. Overrides EntityStorageBase:: |
|
ConfigEntityStorage:: |
public | function |
Loads one or more entities in their original form without overrides. Overrides ConfigEntityStorageInterface:: |
|
ConfigEntityStorage:: |
public | function |
Loads one entity in their original form without overrides. Overrides ConfigEntityStorageInterface:: |
|
ConfigEntityStorage:: |
public | function |
Load a specific entity revision. Overrides EntityStorageInterface:: |
|
ConfigEntityStorage:: |
protected | function | Maps from an entity object to the storage record. | 3 |
ConfigEntityStorage:: |
constant | Length limit of the configuration entity ID. | 1 | |
ConfigEntityStorage:: |
public | function |
Implements Drupal\Core\Entity\EntityStorageInterface::save(). Overrides EntityStorageBase:: |
|
ConfigEntityStorage:: |
public | function |
Updates a configuration entity from storage values. Overrides ConfigEntityStorageInterface:: |
|
ConfigEntityStorage:: |
protected | function | Helps create a configuration entity from storage values. | |
ConfigEntityStorage:: |
public | function |
Constructs a ConfigEntityStorage object. Overrides EntityStorageBase:: |
4 |
DependencySerializationTrait:: |
protected | property | An array of entity type IDs keyed by the property name of their storages. | |
DependencySerializationTrait:: |
protected | property | An array of service IDs keyed by property name used for serialization. | |
DependencySerializationTrait:: |
public | function | 1 | |
DependencySerializationTrait:: |
public | function | 2 | |
EntityHandlerBase:: |
protected | property | The module handler to invoke hooks on. | 2 |
EntityHandlerBase:: |
protected | function | Gets the module handler. | 2 |
EntityHandlerBase:: |
public | function | Sets the module handler for this handler. | |
EntityStorageBase:: |
protected | property | Name of the entity class. | |
EntityStorageBase:: |
protected | property | Information about the entity type. | |
EntityStorageBase:: |
protected | property | Entity type ID for this storage. | |
EntityStorageBase:: |
protected | property | Name of the entity's ID field in the entity database table. | |
EntityStorageBase:: |
protected | property | The name of the entity langcode property. | 1 |
EntityStorageBase:: |
protected | property | The memory cache. | |
EntityStorageBase:: |
protected | property | The memory cache cache tag. | |
EntityStorageBase:: |
protected | property | The UUID service. | 1 |
EntityStorageBase:: |
protected | function | Builds an entity query. | 1 |
EntityStorageBase:: |
public | function |
Constructs a new entity object, without permanently saving it. Overrides EntityStorageInterface:: |
1 |
EntityStorageBase:: |
public | function |
Deletes permanently saved entities. Overrides EntityStorageInterface:: |
2 |
EntityStorageBase:: |
protected | function | Performs post save entity processing. | 1 |
EntityStorageBase:: |
protected | function | Performs presave entity processing. | 1 |
EntityStorageBase:: |
public | function |
Gets an aggregated query instance. Overrides EntityStorageInterface:: |
|
EntityStorageBase:: |
public | function |
Gets the entity type definition. Overrides EntityStorageInterface:: |
|
EntityStorageBase:: |
public | function |
Gets the entity type ID. Overrides EntityStorageInterface:: |
|
EntityStorageBase:: |
protected | function | Gets entities from the static cache. | |
EntityStorageBase:: |
public | function |
Gets an entity query instance. Overrides EntityStorageInterface:: |
|
EntityStorageBase:: |
public | function |
Loads one entity. Overrides EntityStorageInterface:: |
2 |
EntityStorageBase:: |
public | function |
Load entities by their property values. Overrides EntityStorageInterface:: |
3 |
EntityStorageBase:: |
public | function |
Loads one or more entities. Overrides EntityStorageInterface:: |
1 |
EntityStorageBase:: |
public | function |
Loads an unchanged entity from the database. Overrides EntityStorageInterface:: |
1 |
EntityStorageBase:: |
protected | function | Maps from storage records to entity objects. | 4 |
EntityStorageBase:: |
protected | function | Attaches data to entities upon loading. | |
EntityStorageBase:: |
protected | function | Gathers entities from a 'preload' step. | 1 |
EntityStorageBase:: |
public | function |
Resets the internal, static entity cache. Overrides EntityStorageInterface:: |
2 |
EntityStorageBase:: |
public | function |
Restores a previously saved entity. Overrides EntityStorageInterface:: |
1 |
EntityStorageBase:: |
protected | function | Stores entities in the static entity cache. | |
EntityStorageInterface:: |
constant | Load the most recent version of an entity's field data. | ||
EntityStorageInterface:: |
constant | Load the version of an entity's field data specified in the entity. | ||
StringTranslationTrait:: |
protected | property | The string translation service. | 1 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. |