Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
0.00% |
0 / 17 |
CRAP | |
0.00% |
0 / 154 |
EntityDefinitionUpdateManager | |
0.00% |
0 / 1 |
|
0.00% |
0 / 17 |
2862 | |
0.00% |
0 / 154 |
__construct | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
needsUpdates | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
getChangeSummary | |
0.00% |
0 / 1 |
110 | |
0.00% |
0 / 34 |
|||
applyUpdates | |
0.00% |
0 / 1 |
72 | |
0.00% |
0 / 19 |
|||
getEntityType | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 3 |
|||
installEntityType | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 3 |
|||
updateEntityType | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 4 |
|||
uninstallEntityType | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 3 |
|||
installFieldStorageDefinition | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 10 |
|||
getFieldStorageDefinition | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 3 |
|||
updateFieldStorageDefinition | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 4 |
|||
uninstallFieldStorageDefinition | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 3 |
|||
doEntityUpdate | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 11 |
|||
doFieldUpdate | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 12 |
|||
getChangeList | |
0.00% |
0 / 1 |
132 | |
0.00% |
0 / 35 |
|||
requiresEntityStorageSchemaChanges | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 3 |
|||
requiresFieldStorageSchemaChanges | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 3 |
<?php | |
/** | |
* @file | |
* Contains \Drupal\Core\Entity\EntityDefinitionUpdateManager. | |
*/ | |
namespace Drupal\Core\Entity; | |
use Drupal\Core\Entity\Schema\DynamicallyFieldableEntityStorageSchemaInterface; | |
use Drupal\Core\Entity\Schema\EntityStorageSchemaInterface; | |
use Drupal\Core\Field\BaseFieldDefinition; | |
use Drupal\Core\Field\FieldStorageDefinitionInterface; | |
use Drupal\Core\StringTranslation\StringTranslationTrait; | |
/** | |
* Manages entity definition updates. | |
*/ | |
class EntityDefinitionUpdateManager implements EntityDefinitionUpdateManagerInterface { | |
use StringTranslationTrait; | |
/** | |
* The entity manager service. | |
* | |
* @var \Drupal\Core\Entity\EntityManagerInterface | |
*/ | |
protected $entityManager; | |
/** | |
* Constructs a new EntityDefinitionUpdateManager. | |
* | |
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager | |
* The entity manager. | |
*/ | |
public function __construct(EntityManagerInterface $entity_manager) { | |
$this->entityManager = $entity_manager; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function needsUpdates() { | |
return (bool) $this->getChangeList(); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getChangeSummary() { | |
$summary = array(); | |
foreach ($this->getChangeList() as $entity_type_id => $change_list) { | |
// Process entity type definition changes. | |
if (!empty($change_list['entity_type'])) { | |
$entity_type = $this->entityManager->getDefinition($entity_type_id); | |
$t_args = array('%entity_type' => $entity_type->getLabel()); | |
switch ($change_list['entity_type']) { | |
case static::DEFINITION_CREATED: | |
$summary[$entity_type_id][] = $this->t('Create the %entity_type entity type.', $t_args); | |
break; | |
case static::DEFINITION_UPDATED: | |
$summary[$entity_type_id][] = $this->t('Update the %entity_type entity type.', $t_args); | |
break; | |
} | |
} | |
// Process field storage definition changes. | |
if (!empty($change_list['field_storage_definitions'])) { | |
$storage_definitions = $this->entityManager->getFieldStorageDefinitions($entity_type_id); | |
$original_storage_definitions = $this->entityManager->getLastInstalledFieldStorageDefinitions($entity_type_id); | |
foreach ($change_list['field_storage_definitions'] as $field_name => $change) { | |
switch ($change) { | |
case static::DEFINITION_CREATED: | |
$summary[$entity_type_id][] = $this->t('Create the %field_name field.', array('%field_name' => $storage_definitions[$field_name]->getLabel())); | |
break; | |
case static::DEFINITION_UPDATED: | |
$summary[$entity_type_id][] = $this->t('Update the %field_name field.', array('%field_name' => $storage_definitions[$field_name]->getLabel())); | |
break; | |
case static::DEFINITION_DELETED: | |
$summary[$entity_type_id][] = $this->t('Delete the %field_name field.', array('%field_name' => $original_storage_definitions[$field_name]->getLabel())); | |
break; | |
} | |
} | |
} | |
} | |
return $summary; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function applyUpdates() { | |
$complete_change_list = $this->getChangeList(); | |
if ($complete_change_list) { | |
// self::getChangeList() only disables the cache and does not invalidate. | |
// In case there are changes, explicitly invalidate caches. | |
$this->entityManager->clearCachedDefinitions(); | |
} | |
foreach ($complete_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 | |
// entity type. | |
if (!empty($change_list['entity_type'])) { | |
$this->doEntityUpdate($change_list['entity_type'], $entity_type_id); | |
} | |
// Process field storage definition changes. | |
if (!empty($change_list['field_storage_definitions'])) { | |
$storage_definitions = $this->entityManager->getFieldStorageDefinitions($entity_type_id); | |
$original_storage_definitions = $this->entityManager->getLastInstalledFieldStorageDefinitions($entity_type_id); | |
foreach ($change_list['field_storage_definitions'] as $field_name => $change) { | |
$storage_definition = isset($storage_definitions[$field_name]) ? $storage_definitions[$field_name] : NULL; | |
$original_storage_definition = isset($original_storage_definitions[$field_name]) ? $original_storage_definitions[$field_name] : NULL; | |
$this->doFieldUpdate($change, $storage_definition, $original_storage_definition); | |
} | |
} | |
} | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getEntityType($entity_type_id) { | |
$entity_type = $this->entityManager->getLastInstalledDefinition($entity_type_id); | |
return $entity_type ? clone $entity_type : NULL; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function installEntityType(EntityTypeInterface $entity_type) { | |
$this->entityManager->clearCachedDefinitions(); | |
$this->entityManager->onEntityTypeCreate($entity_type); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function updateEntityType(EntityTypeInterface $entity_type) { | |
$original = $this->getEntityType($entity_type->id()); | |
$this->entityManager->clearCachedDefinitions(); | |
$this->entityManager->onEntityTypeUpdate($entity_type, $original); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function uninstallEntityType(EntityTypeInterface $entity_type) { | |
$this->entityManager->clearCachedDefinitions(); | |
$this->entityManager->onEntityTypeDelete($entity_type); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function installFieldStorageDefinition($name, $entity_type_id, $provider, FieldStorageDefinitionInterface $storage_definition) { | |
// @todo Pass a mutable field definition interface when we have one. See | |
// https://www.drupal.org/node/2346329. | |
if ($storage_definition instanceof BaseFieldDefinition) { | |
$storage_definition | |
->setName($name) | |
->setTargetEntityTypeId($entity_type_id) | |
->setProvider($provider) | |
->setTargetBundle(NULL); | |
} | |
$this->entityManager->clearCachedDefinitions(); | |
$this->entityManager->onFieldStorageDefinitionCreate($storage_definition); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getFieldStorageDefinition($name, $entity_type_id) { | |
$storage_definitions = $this->entityManager->getLastInstalledFieldStorageDefinitions($entity_type_id); | |
return isset($storage_definitions[$name]) ? clone $storage_definitions[$name] : NULL; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function updateFieldStorageDefinition(FieldStorageDefinitionInterface $storage_definition) { | |
$original = $this->getFieldStorageDefinition($storage_definition->getName(), $storage_definition->getTargetEntityTypeId()); | |
$this->entityManager->clearCachedDefinitions(); | |
$this->entityManager->onFieldStorageDefinitionUpdate($storage_definition, $original); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function uninstallFieldStorageDefinition(FieldStorageDefinitionInterface $storage_definition) { | |
$this->entityManager->clearCachedDefinitions(); | |
$this->entityManager->onFieldStorageDefinitionDelete($storage_definition); | |
} | |
/** | |
* Performs an entity type definition update. | |
* | |
* @param string $op | |
* The operation to perform, either static::DEFINITION_CREATED or | |
* static::DEFINITION_UPDATED. | |
* @param string $entity_type_id | |
* The entity type ID. | |
*/ | |
protected function doEntityUpdate($op, $entity_type_id) { | |
$entity_type = $this->entityManager->getDefinition($entity_type_id); | |
switch ($op) { | |
case static::DEFINITION_CREATED: | |
$this->entityManager->onEntityTypeCreate($entity_type); | |
break; | |
case static::DEFINITION_UPDATED: | |
$original = $this->entityManager->getLastInstalledDefinition($entity_type_id); | |
$this->entityManager->onEntityTypeUpdate($entity_type, $original); | |
break; | |
} | |
} | |
/** | |
* Performs a field storage definition update. | |
* | |
* @param string $op | |
* The operation to perform, possible values are static::DEFINITION_CREATED, | |
* static::DEFINITION_UPDATED or static::DEFINITION_DELETED. | |
* @param array|null $storage_definition | |
* The new field storage definition. | |
* @param array|null $original_storage_definition | |
* The original field storage definition. | |
*/ | |
protected function doFieldUpdate($op, $storage_definition = NULL, $original_storage_definition = NULL) { | |
switch ($op) { | |
case static::DEFINITION_CREATED: | |
$this->entityManager->onFieldStorageDefinitionCreate($storage_definition); | |
break; | |
case static::DEFINITION_UPDATED: | |
$this->entityManager->onFieldStorageDefinitionUpdate($storage_definition, $original_storage_definition); | |
break; | |
case static::DEFINITION_DELETED: | |
$this->entityManager->onFieldStorageDefinitionDelete($original_storage_definition); | |
break; | |
} | |
} | |
/** | |
* Gets a list of changes to entity type and field storage definitions. | |
* | |
* @return array | |
* An associative array keyed by entity type id of change descriptors. Every | |
* entry is an associative array with the following optional keys: | |
* - entity_type: a scalar having only the DEFINITION_UPDATED value. | |
* - field_storage_definitions: an associative array keyed by field name of | |
* scalars having one value among: | |
* - DEFINITION_CREATED | |
* - DEFINITION_UPDATED | |
* - DEFINITION_DELETED | |
*/ | |
protected function getChangeList() { | |
$this->entityManager->useCaches(FALSE); | |
$change_list = array(); | |
foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) { | |
$original = $this->entityManager->getLastInstalledDefinition($entity_type_id); | |
// @todo Support non-storage-schema-changing definition updates too: | |
// https://www.drupal.org/node/2336895. | |
if (!$original) { | |
$change_list[$entity_type_id]['entity_type'] = static::DEFINITION_CREATED; | |
} | |
else { | |
if ($this->requiresEntityStorageSchemaChanges($entity_type, $original)) { | |
$change_list[$entity_type_id]['entity_type'] = static::DEFINITION_UPDATED; | |
} | |
if ($this->entityManager->getStorage($entity_type_id) instanceof DynamicallyFieldableEntityStorageInterface) { | |
$field_changes = array(); | |
$storage_definitions = $this->entityManager->getFieldStorageDefinitions($entity_type_id); | |
$original_storage_definitions = $this->entityManager->getLastInstalledFieldStorageDefinitions($entity_type_id); | |
// Detect created field storage definitions. | |
foreach (array_diff_key($storage_definitions, $original_storage_definitions) as $field_name => $storage_definition) { | |
$field_changes[$field_name] = static::DEFINITION_CREATED; | |
} | |
// Detect deleted field storage definitions. | |
foreach (array_diff_key($original_storage_definitions, $storage_definitions) as $field_name => $original_storage_definition) { | |
$field_changes[$field_name] = static::DEFINITION_DELETED; | |
} | |
// Detect updated field storage definitions. | |
foreach (array_intersect_key($storage_definitions, $original_storage_definitions) as $field_name => $storage_definition) { | |
// @todo Support non-storage-schema-changing definition updates too: | |
// https://www.drupal.org/node/2336895. So long as we're checking | |
// based on schema change requirements rather than definition | |
// equality, skip the check if the entity type itself needs to be | |
// updated, since that can affect the schema of all fields, so we | |
// want to process that update first without reporting false | |
// positives here. | |
if (!isset($change_list[$entity_type_id]['entity_type']) && $this->requiresFieldStorageSchemaChanges($storage_definition, $original_storage_definitions[$field_name])) { | |
$field_changes[$field_name] = static::DEFINITION_UPDATED; | |
} | |
} | |
if ($field_changes) { | |
$change_list[$entity_type_id]['field_storage_definitions'] = $field_changes; | |
} | |
} | |
} | |
} | |
// @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); | |
} | |
/** | |
* Checks if the changes to the entity type requires storage schema changes. | |
* | |
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type | |
* The updated entity type definition. | |
* @param \Drupal\Core\Entity\EntityTypeInterface $original | |
* The original entity type definition. | |
* | |
* @return bool | |
* TRUE if storage schema changes are required, FALSE otherwise. | |
*/ | |
protected function requiresEntityStorageSchemaChanges(EntityTypeInterface $entity_type, EntityTypeInterface $original) { | |
$storage = $this->entityManager->getStorage($entity_type->id()); | |
return ($storage instanceof EntityStorageSchemaInterface) && $storage->requiresEntityStorageSchemaChanges($entity_type, $original); | |
} | |
/** | |
* Checks if the changes to the storage definition requires schema changes. | |
* | |
* @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition | |
* The updated field storage definition. | |
* @param \Drupal\Core\Field\FieldStorageDefinitionInterface $original | |
* The original field storage definition. | |
* | |
* @return bool | |
* TRUE if storage schema changes are required, FALSE otherwise. | |
*/ | |
protected function requiresFieldStorageSchemaChanges(FieldStorageDefinitionInterface $storage_definition, FieldStorageDefinitionInterface $original) { | |
$storage = $this->entityManager->getStorage($storage_definition->getTargetEntityTypeId()); | |
return ($storage instanceof DynamicallyFieldableEntityStorageSchemaInterface) && $storage->requiresFieldStorageSchemaChanges($storage_definition, $original); | |
} | |
} |