Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
20.00% |
5 / 25 |
CRAP | |
37.50% |
45 / 120 |
| ConfigEntityStorage | |
0.00% |
0 / 1 |
|
20.00% |
5 / 25 |
738.79 | |
37.50% |
45 / 120 |
| __construct | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 5 |
|||
| createInstance | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 4 |
|||
| loadRevision | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| deleteRevision | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| getPrefix | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
| getIDFromConfigName | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
| doLoadMultiple | |
100.00% |
1 / 1 |
6 | |
100.00% |
19 / 19 |
|||
| doCreate | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
| doDelete | |
100.00% |
1 / 1 |
2 | |
100.00% |
3 / 3 |
|||
| save | |
0.00% |
0 / 1 |
4.07 | |
83.33% |
5 / 6 |
|||
| doSave | |
0.00% |
0 / 1 |
5.06 | |
86.67% |
13 / 15 |
|||
| mapToStorageRecord | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
| has | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 3 |
|||
| getFromStaticCache | |
0.00% |
0 / 1 |
56 | |
0.00% |
0 / 8 |
|||
| setStaticCache | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 5 |
|||
| invokeHook | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 3 |
|||
| getQueryServiceName | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
| importCreate | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 4 |
|||
| importUpdate | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 8 |
|||
| importDelete | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 5 |
|||
| importRename | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
| createFromStorageRecord | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 9 |
|||
| updateFromStorageRecord | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 7 |
|||
| loadOverrideFree | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 2 |
|||
| loadMultipleOverrideFree | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 4 |
|||
| <?php | |
| /** | |
| * @file | |
| * Contains \Drupal\Core\Config\Entity\ConfigEntityStorage. | |
| */ | |
| namespace Drupal\Core\Config\Entity; | |
| use Drupal\Core\Cache\CacheableMetadata; | |
| use Drupal\Core\Config\ConfigFactoryInterface; | |
| use Drupal\Core\Config\ConfigImporterException; | |
| use Drupal\Core\Entity\EntityInterface; | |
| use Drupal\Core\Entity\EntityMalformedException; | |
| use Drupal\Core\Entity\EntityStorageBase; | |
| use Drupal\Core\Config\Config; | |
| use Drupal\Core\Config\Entity\Exception\ConfigEntityIdLengthException; | |
| use Drupal\Core\Entity\EntityTypeInterface; | |
| use Drupal\Component\Uuid\UuidInterface; | |
| use Drupal\Core\Language\LanguageManagerInterface; | |
| use Symfony\Component\DependencyInjection\ContainerInterface; | |
| /** | |
| * 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. | |
| * | |
| * @ingroup entity_api | |
| */ | |
| 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 = array(); | |
| /** | |
| * 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. | |
| */ | |
| public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, UuidInterface $uuid_service, LanguageManagerInterface $language_manager) { | |
| parent::__construct($entity_type); | |
| $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') | |
| ); | |
| } | |
| /** | |
| * {@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 = array(); | |
| 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 += array($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 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)) > self::MAX_ID_LENGTH) { | |
| throw new ConfigEntityIdLengthException("Configuration entity ID {$entity->get($this->idKey)} exceeds maximum allowed length of " . self::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(array($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(); | |
| } | |
| /** | |
| * Gets entities from the static cache. | |
| * | |
| * @param array $ids | |
| * If not empty, return entities that match these IDs. | |
| * | |
| * @return \Drupal\Core\Entity\EntityInterface[] | |
| * Array of entities from the entity cache. | |
| */ | |
| protected function getFromStaticCache(array $ids) { | |
| $entities = array(); | |
| // Load any available entities from the internal cache. | |
| if ($this->entityType->isStaticallyCacheable() && !empty($this->entities)) { | |
| $config_overrides_key = $this->overrideFree ? '' : implode(':', $this->configFactory->getCacheKeys()); | |
| foreach ($ids as $id) { | |
| if (!empty($this->entities[$id])) { | |
| if (isset($this->entities[$id][$config_overrides_key])) { | |
| $entities[$id] = $this->entities[$id][$config_overrides_key]; | |
| } | |
| } | |
| } | |
| } | |
| return $entities; | |
| } | |
| /** | |
| * Stores entities in the static entity cache. | |
| * | |
| * @param \Drupal\Core\Entity\EntityInterface[] $entities | |
| * Entities to store in the cache. | |
| */ | |
| protected function setStaticCache(array $entities) { | |
| if ($this->entityType->isStaticallyCacheable()) { | |
| $config_overrides_key = $this->overrideFree ? '' : implode(':', $this->configFactory->getCacheKeys()); | |
| foreach ($entities as $id => $entity) { | |
| $this->entities[$id][$config_overrides_key] = $entity; | |
| } | |
| } | |
| } | |
| /** | |
| * 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, array($entity)); | |
| // Invoke the respective entity-level hook. | |
| $this->moduleHandler->invokeAll('entity_' . $hook, array($entity, $this->entityTypeId)); | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| protected function getQueryServiceName() { | |
| return 'entity.query.config'; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function importCreate($name, Config $new_config, Config $old_config) { | |
| $entity = $this->createFromStorageRecord($new_config->get()); | |
| $entity->setSyncing(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) { | |
| // 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(array($values)); | |
| $entity = current($data); | |
| $entity->original = clone $entity; | |
| $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(array($values)); | |
| $updated_entity = current($data); | |
| foreach (array_keys($values) as $property) { | |
| $value = $updated_entity->get($property); | |
| $entity->set($property, $value); | |
| } | |
| 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; | |
| } | |
| } |