Skip to content
Snippets Groups Projects
Commit 03ddf8c2 authored by Dries Buytaert's avatar Dries Buytaert
Browse files

Issue #2198377 by alexpott: Enforce UUID key name in configuration entities.

parent 3a5c3b32
No related branches found
No related tags found
2 merge requests!7452Issue #1797438. HTML5 validation is preventing form submit and not fully...,!789Issue #3210310: Adjust Database API to remove deprecated Drupal 9 code in Drupal 10
Showing
with 39 additions and 43 deletions
...@@ -240,7 +240,12 @@ function entity_revision_delete($entity_type, $revision_id) { ...@@ -240,7 +240,12 @@ function entity_revision_delete($entity_type, $revision_id) {
*/ */
function entity_load_by_uuid($entity_type_id, $uuid, $reset = FALSE) { function entity_load_by_uuid($entity_type_id, $uuid, $reset = FALSE) {
$entity_type = \Drupal::entityManager()->getDefinition($entity_type_id); $entity_type = \Drupal::entityManager()->getDefinition($entity_type_id);
if (!$uuid_key = $entity_type->getKey('uuid')) {
// Configuration entities do not use annotations to set the UUID key.
if ($entity_type->isSubclassOf('Drupal\Core\Config\Entity\ConfigEntityInterface')) {
$uuid_key = 'uuid';
}
elseif (!$uuid_key = $entity_type->getKey('uuid')) {
throw new EntityStorageException("Entity type $entity_type_id does not support UUIDs."); throw new EntityStorageException("Entity type $entity_type_id does not support UUIDs.");
} }
......
...@@ -174,7 +174,12 @@ public function isSyncing() { ...@@ -174,7 +174,12 @@ public function isSyncing() {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function createDuplicate() { public function createDuplicate() {
$duplicate = parent::createDuplicate(); $duplicate = clone $this;
$duplicate->set($this->getEntityType()->getKey('id'), NULL);
// @todo Inject the UUID service into the Entity class once possible.
$duplicate->set('uuid', \Drupal::service('uuid')->generate());
// Prevent the new duplicate from being misinterpreted as a rename. // Prevent the new duplicate from being misinterpreted as a rename.
$duplicate->setOriginalId(NULL); $duplicate->setOriginalId(NULL);
return $duplicate; return $duplicate;
......
...@@ -37,13 +37,6 @@ ...@@ -37,13 +37,6 @@
*/ */
class ConfigStorageController extends EntityStorageControllerBase implements ConfigStorageControllerInterface { class ConfigStorageController extends EntityStorageControllerBase implements ConfigStorageControllerInterface {
/**
* Name of the entity's UUID property.
*
* @var string
*/
protected $uuidKey = 'uuid';
/** /**
* The UUID service. * The UUID service.
* *
...@@ -261,8 +254,8 @@ public function create(array $values = array()) { ...@@ -261,8 +254,8 @@ public function create(array $values = array()) {
$entity->enforceIsNew(); $entity->enforceIsNew();
// Assign a new UUID if there is none yet. // Assign a new UUID if there is none yet.
if (!isset($entity->{$this->uuidKey})) { if (!$entity->uuid()) {
$entity->{$this->uuidKey} = $this->uuidService->generate(); $entity->set('uuid', $this->uuidService->generate());
} }
$entity->postCreate($this); $entity->postCreate($this);
......
...@@ -31,8 +31,7 @@ ...@@ -31,8 +31,7 @@
* bundle_of = "custom_block", * bundle_of = "custom_block",
* entity_keys = { * entity_keys = {
* "id" = "id", * "id" = "id",
* "label" = "label", * "label" = "label"
* "uuid" = "uuid"
* }, * },
* links = { * links = {
* "delete-form" = "custom_block.type_delete", * "delete-form" = "custom_block.type_delete",
......
...@@ -31,8 +31,7 @@ ...@@ -31,8 +31,7 @@
* fieldable = FALSE, * fieldable = FALSE,
* entity_keys = { * entity_keys = {
* "id" = "id", * "id" = "id",
* "label" = "label", * "label" = "label"
* "uuid" = "uuid"
* }, * },
* links = { * links = {
* "delete-form" = "block.admin_block_delete", * "delete-form" = "block.admin_block_delete",
......
...@@ -23,8 +23,7 @@ ...@@ -23,8 +23,7 @@
* label = @Translation("Breakpoint"), * label = @Translation("Breakpoint"),
* entity_keys = { * entity_keys = {
* "id" = "id", * "id" = "id",
* "label" = "label", * "label" = "label"
* "uuid" = "uuid"
* } * }
* ) * )
*/ */
......
...@@ -20,8 +20,7 @@ ...@@ -20,8 +20,7 @@
* label = @Translation("Breakpoint group"), * label = @Translation("Breakpoint group"),
* entity_keys = { * entity_keys = {
* "id" = "id", * "id" = "id",
* "label" = "label", * "label" = "label"
* "uuid" = "uuid"
* } * }
* ) * )
*/ */
......
...@@ -75,7 +75,7 @@ public function getFormID() { ...@@ -75,7 +75,7 @@ public function getFormID() {
*/ */
public function buildForm(array $form, array &$form_state, $config_type = NULL, $config_name = NULL) { public function buildForm(array $form, array &$form_state, $config_type = NULL, $config_name = NULL) {
foreach ($this->entityManager->getDefinitions() as $entity_type => $definition) { foreach ($this->entityManager->getDefinitions() as $entity_type => $definition) {
if ($definition->getConfigPrefix() && $definition->hasKey('uuid')) { if ($definition->isSubclassOf('Drupal\Core\Config\Entity\ConfigEntityInterface')) {
$this->definitions[$entity_type] = $definition; $this->definitions[$entity_type] = $definition;
} }
} }
......
...@@ -122,7 +122,7 @@ public function buildForm(array $form, array &$form_state) { ...@@ -122,7 +122,7 @@ public function buildForm(array $form, array &$form_state) {
$entity_types = array(); $entity_types = array();
foreach ($this->entityManager->getDefinitions() as $entity_type => $definition) { foreach ($this->entityManager->getDefinitions() as $entity_type => $definition) {
if ($definition->getConfigPrefix() && $definition->hasKey('uuid')) { if ($definition->isSubclassOf('Drupal\Core\Config\Entity\ConfigEntityInterface')) {
$entity_types[$entity_type] = $definition->getLabel(); $entity_types[$entity_type] = $definition->getLabel();
} }
} }
...@@ -187,21 +187,20 @@ public function validateForm(array &$form, array &$form_state) { ...@@ -187,21 +187,20 @@ public function validateForm(array &$form, array &$form_state) {
$this->setFormError('import', $form_state, $this->t('Missing ID key "@id_key" for this @entity_type import.', array('@id_key' => $id_key, '@entity_type' => $definition->getLabel()))); $this->setFormError('import', $form_state, $this->t('Missing ID key "@id_key" for this @entity_type import.', array('@id_key' => $id_key, '@entity_type' => $definition->getLabel())));
return; return;
} }
$uuid_key = $definition->getKey('uuid');
// If there is an existing entity, ensure matching ID and UUID. // If there is an existing entity, ensure matching ID and UUID.
if ($entity = $entity_storage->load($data[$id_key])) { if ($entity = $entity_storage->load($data[$id_key])) {
$this->configExists = $entity; $this->configExists = $entity;
if (!isset($data[$uuid_key])) { if (!isset($data['uuid'])) {
$this->setFormError('import', $form_state, $this->t('An entity with this machine name already exists but the import did not specify a UUID.')); $this->setFormError('import', $form_state, $this->t('An entity with this machine name already exists but the import did not specify a UUID.'));
return; return;
} }
if ($data[$uuid_key] !== $entity->uuid()) { if ($data['uuid'] !== $entity->uuid()) {
$this->setFormError('import', $form_state, $this->t('An entity with this machine name already exists but the UUID does not match.')); $this->setFormError('import', $form_state, $this->t('An entity with this machine name already exists but the UUID does not match.'));
return; return;
} }
} }
// If there is no entity with a matching ID, check for a UUID match. // If there is no entity with a matching ID, check for a UUID match.
elseif (isset($data[$uuid_key]) && $entity_storage->loadByProperties(array($uuid_key => $data[$uuid_key]))) { elseif (isset($data['uuid']) && $entity_storage->loadByProperties(array('uuid' => $data['uuid']))) {
$this->setFormError('import', $form_state, $this->t('An entity with this UUID already exists but the machine name does not match.')); $this->setFormError('import', $form_state, $this->t('An entity with this UUID already exists but the machine name does not match.'));
} }
} }
......
...@@ -78,6 +78,13 @@ public function testStorageControllerMethods() { ...@@ -78,6 +78,13 @@ public function testStorageControllerMethods() {
)); ));
$entity->save(); $entity->save();
// Ensure that the configuration entity can be loaded by UUID.
$entity_loaded_by_uuid = entity_load_by_uuid($entity_type->id(), $entity->uuid());
// Compare UUIDs as the objects are not identical since
// $entity->enforceIsNew is FALSE and $entity_loaded_by_uuid->enforceIsNew
// is NULL.
$this->assertIdentical($entity->uuid(), $entity_loaded_by_uuid->uuid());
$entities = $this->storage->loadByProperties(); $entities = $this->storage->loadByProperties();
$this->assertEqual(count($entities), 3, 'Three entities are loaded when no properties are specified.'); $this->assertEqual(count($entities), 3, 'Three entities are loaded when no properties are specified.');
......
...@@ -124,7 +124,7 @@ public function testExport() { ...@@ -124,7 +124,7 @@ public function testExport() {
$this->drupalLogin($this->drupalCreateUser(array('export configuration'))); $this->drupalLogin($this->drupalCreateUser(array('export configuration')));
$this->drupalGet('admin/config/development/configuration/single/export/system.simple'); $this->drupalGet('admin/config/development/configuration/single/export/system.simple');
$this->assertFieldByXPath('//select[@name="config_type"]//option', t('Date format'), 'The date format entity type is selected when specified in the URL.'); $this->assertFieldByXPath('//select[@name="config_type"]//option[@selected="selected"]', t('Simple configuration'), 'The simple configuration option is selected when specified in the URL.');
// Spot check several known simple configuration files. // Spot check several known simple configuration files.
$element = $this->xpath('//select[@name="config_name"]'); $element = $this->xpath('//select[@name="config_name"]');
$options = $this->getAllOptions($element[0]); $options = $this->getAllOptions($element[0]);
...@@ -138,10 +138,10 @@ public function testExport() { ...@@ -138,10 +138,10 @@ public function testExport() {
$this->assertFieldByXPath('//textarea[@name="export"]', "toolkit: gd\n", 'The expected system configuration is displayed.'); $this->assertFieldByXPath('//textarea[@name="export"]', "toolkit: gd\n", 'The expected system configuration is displayed.');
$this->drupalGet('admin/config/development/configuration/single/export/date_format'); $this->drupalGet('admin/config/development/configuration/single/export/date_format');
$this->assertFieldByXPath('//select[@name="config_type"]//option', t('Date format'), 'The date format entity type is selected when specified in the URL.'); $this->assertFieldByXPath('//select[@name="config_type"]//option[@selected="selected"]', t('Date format'), 'The date format entity type is selected when specified in the URL.');
$this->drupalGet('admin/config/development/configuration/single/export/date_format/fallback'); $this->drupalGet('admin/config/development/configuration/single/export/date_format/fallback');
$this->assertFieldByXPath('//select[@name="config_name"]//option', t('Fallback date format'), 'The fallback date format config entity is selected when specified in the URL.'); $this->assertFieldByXPath('//select[@name="config_name"]//option[@selected="selected"]', t('Fallback date format'), 'The fallback date format config entity is selected when specified in the URL.');
$fallback_date = \Drupal::entityManager()->getStorageController('date_format')->load('fallback'); $fallback_date = \Drupal::entityManager()->getStorageController('date_format')->load('fallback');
$data = \Drupal::service('config.storage')->encode($fallback_date->getExportProperties()); $data = \Drupal::service('config.storage')->encode($fallback_date->getExportProperties());
......
...@@ -23,8 +23,7 @@ ...@@ -23,8 +23,7 @@
* config_prefix = "query", * config_prefix = "query",
* entity_keys = { * entity_keys = {
* "id" = "id", * "id" = "id",
* "label" = "label", * "label" = "label"
* "uuid" = "uuid"
* } * }
* ) * )
* *
......
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
* entity_keys = { * entity_keys = {
* "id" = "id", * "id" = "id",
* "label" = "label", * "label" = "label",
* "uuid" = "uuid",
* "status" = "status" * "status" = "status"
* }, * },
* links = { * links = {
......
...@@ -31,8 +31,7 @@ ...@@ -31,8 +31,7 @@
* bundle_of = "contact_message", * bundle_of = "contact_message",
* entity_keys = { * entity_keys = {
* "id" = "id", * "id" = "id",
* "label" = "label", * "label" = "label"
* "uuid" = "uuid"
* }, * },
* links = { * links = {
* "delete-form" = "contact.category_delete", * "delete-form" = "contact.category_delete",
......
...@@ -17,8 +17,7 @@ ...@@ -17,8 +17,7 @@
* id = "editor", * id = "editor",
* label = @Translation("Editor"), * label = @Translation("Editor"),
* entity_keys = { * entity_keys = {
* "id" = "format", * "id" = "format"
* "uuid" = "uuid"
* } * }
* ) * )
*/ */
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
* config_prefix = "form_display", * config_prefix = "form_display",
* entity_keys = { * entity_keys = {
* "id" = "id", * "id" = "id",
* "uuid" = "uuid",
* "status" = "status" * "status" = "status"
* } * }
* ) * )
......
...@@ -42,8 +42,7 @@ ...@@ -42,8 +42,7 @@
* admin_permission = "administer display modes", * admin_permission = "administer display modes",
* entity_keys = { * entity_keys = {
* "id" = "id", * "id" = "id",
* "label" = "label", * "label" = "label"
* "uuid" = "uuid"
* }, * },
* links = { * links = {
* "delete-form" = "entity.form_mode_delete", * "delete-form" = "entity.form_mode_delete",
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
* config_prefix = "view_display", * config_prefix = "view_display",
* entity_keys = { * entity_keys = {
* "id" = "id", * "id" = "id",
* "uuid" = "uuid",
* "status" = "status" * "status" = "status"
* } * }
* ) * )
......
...@@ -42,8 +42,7 @@ ...@@ -42,8 +42,7 @@
* admin_permission = "administer display modes", * admin_permission = "administer display modes",
* entity_keys = { * entity_keys = {
* "id" = "id", * "id" = "id",
* "label" = "label", * "label" = "label"
* "uuid" = "uuid"
* }, * },
* links = { * links = {
* "delete-form" = "entity.view_mode_delete", * "delete-form" = "entity.view_mode_delete",
......
...@@ -28,8 +28,7 @@ ...@@ -28,8 +28,7 @@
* config_prefix = "field", * config_prefix = "field",
* entity_keys = { * entity_keys = {
* "id" = "id", * "id" = "id",
* "label" = "id", * "label" = "id"
* "uuid" = "uuid"
* } * }
* ) * )
*/ */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment