Issue #2976103 by amateescu, catch, tstoeckler, alexpott: Make it possible to retrieve all the last installed entity type definitions at once from the update manager

merge-requests/1654/head
Nathaniel Catchpole 2018-06-29 15:13:38 +01:00
parent 7410ab4ab0
commit 5e908886e9
6 changed files with 109 additions and 9 deletions

View File

@ -575,7 +575,7 @@ services:
- { name: event_subscriber }
entity.definition_update_manager:
class: Drupal\Core\Entity\EntityDefinitionUpdateManager
arguments: ['@entity.manager']
arguments: ['@entity.manager', '@entity.last_installed_schema.repository']
entity.last_installed_schema.repository:
class: Drupal\Core\Entity\EntityLastInstalledSchemaRepository
arguments: ['@keyvalue']

View File

@ -21,14 +21,29 @@ class EntityDefinitionUpdateManager implements EntityDefinitionUpdateManagerInte
*/
protected $entityManager;
/**
* The last installed schema repository.
*
* @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface
*/
protected $entityLastInstalledSchemaRepository;
/**
* Constructs a new EntityDefinitionUpdateManager.
*
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager.
* @param \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface $entity_last_installed_schema_repository
* The last installed schema repository service.
*/
public function __construct(EntityManagerInterface $entity_manager) {
public function __construct(EntityManagerInterface $entity_manager, EntityLastInstalledSchemaRepositoryInterface $entity_last_installed_schema_repository = NULL) {
$this->entityManager = $entity_manager;
if (!isset($entity_last_installed_schema_repository)) {
@trigger_error('The $entity_last_installed_schema_repository parameter was added in Drupal 8.6.x and will be required in 9.0.0. See https://www.drupal.org/node/2973262.', E_USER_DEPRECATED);
$entity_last_installed_schema_repository = \Drupal::service('entity.last_installed_schema.repository');
}
$this->entityLastInstalledSchemaRepository = $entity_last_installed_schema_repository;
}
/**
@ -63,7 +78,7 @@ class EntityDefinitionUpdateManager implements EntityDefinitionUpdateManagerInte
// 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);
$original_storage_definitions = $this->entityLastInstalledSchemaRepository->getLastInstalledFieldStorageDefinitions($entity_type_id);
foreach ($change_list['field_storage_definitions'] as $field_name => $change) {
switch ($change) {
@ -108,7 +123,7 @@ class EntityDefinitionUpdateManager implements EntityDefinitionUpdateManagerInte
// 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);
$original_storage_definitions = $this->entityLastInstalledSchemaRepository->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;
@ -123,10 +138,17 @@ class EntityDefinitionUpdateManager implements EntityDefinitionUpdateManagerInte
* {@inheritdoc}
*/
public function getEntityType($entity_type_id) {
$entity_type = $this->entityManager->getLastInstalledDefinition($entity_type_id);
$entity_type = $this->entityLastInstalledSchemaRepository->getLastInstalledDefinition($entity_type_id);
return $entity_type ? clone $entity_type : NULL;
}
/**
* {@inheritdoc}
*/
public function getEntityTypes() {
return $this->entityLastInstalledSchemaRepository->getLastInstalledDefinitions();
}
/**
* {@inheritdoc}
*/
@ -173,7 +195,7 @@ class EntityDefinitionUpdateManager implements EntityDefinitionUpdateManagerInte
* {@inheritdoc}
*/
public function getFieldStorageDefinition($name, $entity_type_id) {
$storage_definitions = $this->entityManager->getLastInstalledFieldStorageDefinitions($entity_type_id);
$storage_definitions = $this->entityLastInstalledSchemaRepository->getLastInstalledFieldStorageDefinitions($entity_type_id);
return isset($storage_definitions[$name]) ? clone $storage_definitions[$name] : NULL;
}
@ -211,7 +233,7 @@ class EntityDefinitionUpdateManager implements EntityDefinitionUpdateManagerInte
break;
case static::DEFINITION_UPDATED:
$original = $this->entityManager->getLastInstalledDefinition($entity_type_id);
$original = $this->entityLastInstalledSchemaRepository->getLastInstalledDefinition($entity_type_id);
$this->entityManager->onEntityTypeUpdate($entity_type, $original);
break;
}
@ -262,7 +284,7 @@ class EntityDefinitionUpdateManager implements EntityDefinitionUpdateManagerInte
$change_list = [];
foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) {
$original = $this->entityManager->getLastInstalledDefinition($entity_type_id);
$original = $this->entityLastInstalledSchemaRepository->getLastInstalledDefinition($entity_type_id);
// @todo Support non-storage-schema-changing definition updates too:
// https://www.drupal.org/node/2336895.
@ -277,7 +299,7 @@ class EntityDefinitionUpdateManager implements EntityDefinitionUpdateManagerInte
if ($this->entityManager->getStorage($entity_type_id) instanceof DynamicallyFieldableEntityStorageInterface) {
$field_changes = [];
$storage_definitions = $this->entityManager->getFieldStorageDefinitions($entity_type_id);
$original_storage_definitions = $this->entityManager->getLastInstalledFieldStorageDefinitions($entity_type_id);
$original_storage_definitions = $this->entityLastInstalledSchemaRepository->getLastInstalledFieldStorageDefinitions($entity_type_id);
// Detect created field storage definitions.
foreach (array_diff_key($storage_definitions, $original_storage_definitions) as $field_name => $storage_definition) {

View File

@ -108,6 +108,18 @@ interface EntityDefinitionUpdateManagerInterface {
*/
public function getEntityType($entity_type_id);
/**
* Returns all the entity type definitions, ready to be manipulated.
*
* When needing to apply updates to existing entity type definitions, this
* method should always be used to retrieve all the definitions ready to be
* manipulated.
*
* @return \Drupal\Core\Entity\EntityTypeInterface[]
* The last installed entity type definitions, keyed by the entity type ID.
*/
public function getEntityTypes();
/**
* Installs a new entity type definition.
*

View File

@ -34,6 +34,28 @@ class EntityLastInstalledSchemaRepository implements EntityLastInstalledSchemaRe
return $this->keyValueFactory->get('entity.definitions.installed')->get($entity_type_id . '.entity_type');
}
/**
* {@inheritdoc}
*/
public function getLastInstalledDefinitions() {
$all_definitions = $this->keyValueFactory->get('entity.definitions.installed')->getAll();
// Filter out field storage definitions.
$filtered_keys = array_filter(array_keys($all_definitions), function ($key) {
return substr($key, -12) === '.entity_type';
});
$entity_type_definitions = array_intersect_key($all_definitions, array_flip($filtered_keys));
// Ensure that the returned array is keyed by the entity type ID.
$keys = array_keys($entity_type_definitions);
$keys = array_map(function ($key) {
$parts = explode('.', $key);
return $parts[0];
}, $keys);
return array_combine($keys, $entity_type_definitions);
}
/**
* {@inheritdoc}
*/

View File

@ -41,6 +41,34 @@ interface EntityLastInstalledSchemaRepositoryInterface {
*/
public function getLastInstalledDefinition($entity_type_id);
/**
* Gets the entity type definitions in their most recently installed state.
*
* During the application lifetime, entity type definitions can change. For
* example, updated code can be deployed. The
* \Drupal\Core\Entity\EntityTypeManagerInterface::getDefinitions() method
* will always return the definitions as determined by the current codebase.
* This method returns the definitions from the last time that a
* \Drupal\Core\Entity\EntityTypeListener event was completed. In other words,
* the definitions that the entity type's handlers have incorporated into the
* application state. For example, if the entity type's storage handler is
* SQL-based, the definition for which database tables were created.
*
* Application management code can check if
* \Drupal\Core\Entity\EntityTypeManagerInterface::getDefinitions() differs
* from getLastInstalledDefinitions() and decide whether to:
* - Invoke the appropriate \Drupal\Core\Entity\EntityTypeListenerInterface
* event so that handlers react to the new definitions.
* - Raise a warning that the application state is incompatible with the
* codebase.
* - Perform some other action.
*
* @return \Drupal\Core\Entity\EntityTypeInterface[]
* An array containing the installed definition for all entity types, keyed
* by the entity type ID.
*/
public function getLastInstalledDefinitions();
/**
* Stores the entity type definition in the application state.
*

View File

@ -20,6 +20,8 @@ use Drupal\Tests\system\Functional\Entity\Traits\EntityDefinitionTestTrait;
/**
* Tests EntityDefinitionUpdateManager functionality.
*
* @coversDefaultClass \Drupal\Core\Entity\EntityDefinitionUpdateManager
*
* @group Entity
*/
class EntityDefinitionUpdateTest extends EntityKernelTestBase {
@ -1180,4 +1182,18 @@ class EntityDefinitionUpdateTest extends EntityKernelTestBase {
}
}
/**
* @covers ::getEntityTypes
*/
public function testGetEntityTypes() {
$entity_type_definitions = $this->entityDefinitionUpdateManager->getEntityTypes();
// Ensure that we have at least one entity type to check below.
$this->assertGreaterThanOrEqual(1, count($entity_type_definitions));
foreach ($entity_type_definitions as $entity_type_id => $entity_type) {
$this->assertEquals($this->entityDefinitionUpdateManager->getEntityType($entity_type_id), $entity_type);
}
}
}