diff --git a/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php b/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php index 0cfb7c4..ca9ecae 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php @@ -17,7 +17,7 @@ use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Language\Language; -use Drupal\field\FieldConfigUpdateForbiddenException; +use Drupal\Core\Entity\Exception\StorageDefinitionUpdateForbiddenException; use Drupal\field\Entity\FieldConfig; use Drupal\field\FieldInstanceConfigInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -1142,7 +1142,6 @@ public function onFieldCreate(FieldStorageDefinitionInterface $storage_definitio * {@inheritdoc} */ public function onFieldUpdate(FieldStorageDefinitionInterface $storage_definition, FieldStorageDefinitionInterface $original) { - if (!$storage_definition->hasData()) { // There is no data. Re-create the tables completely. @@ -1180,7 +1179,7 @@ public function onFieldUpdate(FieldStorageDefinitionInterface $storage_definitio } else { if ($storage_definition->getColumns() != $original->getColumns()) { - throw new FieldConfigUpdateForbiddenException("The SQL storage cannot change the schema for an existing field with data."); + throw new StorageDefinitionUpdateForbiddenException("The SQL storage cannot change the schema for an existing field with data."); } // There is data, so there are no column changes. Drop all the prior // indexes and create all the new ones, except for all the priors that @@ -1262,21 +1261,19 @@ public function onInstanceDelete(FieldDefinitionInterface $field_definition) { /** * {@inheritdoc} */ - public function onBundleRename($bundle, $bundle_new) { - // We need to account for deleted fields and instances. The method runs - // before the instance definitions are updated, so we need to fetch them - // using the old bundle name. - $instances = entity_load_multiple_by_properties('field_instance_config', array('entity_type' => $this->entityTypeId, 'bundle' => $bundle, 'include_deleted' => TRUE)); - foreach ($instances as $instance) { - $table_name = static::_fieldTableName($instance); - $revision_name = static::_fieldRevisionTableName($instance); + public function onInstanceUpdate(FieldDefinitionInterface $field_definition, FieldDefinitionInterface $original) { + // Update the stored bundle, when the bundle changes. + if ($field_definition->getBundle() != $original->getBundle()) { + $is_deleted = $this->storageDefinitionIsDeleted($field_definition); + $table_name = static::_fieldTableName($field_definition, $is_deleted); + $revision_name = static::_fieldRevisionTableName($field_definition, $is_deleted); $this->database->update($table_name) - ->fields(array('bundle' => $bundle_new)) - ->condition('bundle', $bundle) + ->fields(array('bundle' => $field_definition->getBundle())) + ->condition('bundle', $original->getBundle()) ->execute(); $this->database->update($revision_name) - ->fields(array('bundle' => $bundle_new)) - ->condition('bundle', $bundle) + ->fields(array('bundle' => $field_definition->getBundle())) + ->condition('bundle', $original->getBundle()) ->execute(); } } @@ -1287,7 +1284,7 @@ public function onBundleRename($bundle, $bundle_new) { protected function readFieldItemsToPurge(FieldDefinitionInterface $field_definition, $batch_size) { // Check whether the whole field storage definition is gone, or just some // bundle fields. - $is_deleted = !array_key_exists($field_definition->getName(), $this->entityManager->getFieldStorageDefinitions($this->entityTypeId)); + $is_deleted = $this->storageDefinitionIsDeleted($field_definition); $table_name = static::_fieldTableName($field_definition, $is_deleted); $query = $this->database->select($table_name, 't', array('fetch' => \PDO::FETCH_ASSOC)) ->fields('t') @@ -1330,7 +1327,7 @@ protected function readFieldItemsToPurge(FieldDefinitionInterface $field_definit * {@inheritdoc} */ protected function purgeFieldItems(ContentEntityInterface $entity, FieldDefinitionInterface $field_definition) { - $is_deleted = !array_key_exists($field_definition->getName(), $this->entityManager->getFieldStorageDefinitions($this->entityTypeId)); + $is_deleted = $this->storageDefinitionIsDeleted($field_definition); $table_name = static::_fieldTableName($field_definition, $is_deleted); $revision_name = static::_fieldRevisionTableName($field_definition, $is_deleted); $revision_id = $entity->getRevisionId() !== NULL ? $entity->getRevisionId() : $entity->id(); @@ -1356,7 +1353,7 @@ public function finalizePurge(FieldStorageDefinitionInterface $storage_definitio * {@inheritdoc} */ public function countFieldData($storage_definition, $as_bool = FALSE) { - $is_deleted = !array_key_exists($storage_definition->getName(), $this->entityManager->getFieldStorageDefinitions($this->entityTypeId)); + $is_deleted = $this->storageDefinitionIsDeleted($storage_definition); $table_name = static::_fieldTableName($storage_definition, $is_deleted); $query = $this->database->select($table_name, 't'); @@ -1374,6 +1371,19 @@ public function countFieldData($storage_definition, $as_bool = FALSE) { } /** + * Returns whether the passed field has been already deleted. + * + * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition + * The field storage definition. + * + * @return bool + * Whether the field has been already deleted. + */ + protected function storageDefinitionIsDeleted(FieldStorageDefinitionInterface $storage_definition) { + return !array_key_exists($storage_definition->getName(), $this->entityManager->getFieldStorageDefinitions($this->entityTypeId)); + } + + /** * Gets the SQL table schema. * * @private Calling this function circumvents the entity system and is @@ -1555,7 +1565,7 @@ public static function _fieldSqlSchema(FieldStorageDefinitionInterface $storage_ * @return string * A string containing the generated name for the database table. */ - static public function _fieldTableName(FieldStorageDefinitionInterface $storage_definition, $is_deleted = FALSE) { + public static function _fieldTableName(FieldStorageDefinitionInterface $storage_definition, $is_deleted = FALSE) { if ($is_deleted) { // When a field is a deleted, the table is renamed to // {field_deleted_data_FIELD_UUID}. To make sure we don't end up with @@ -1588,7 +1598,7 @@ static public function _fieldTableName(FieldStorageDefinitionInterface $storage_ * @return string * A string containing the generated name for the database table. */ - static public function _fieldRevisionTableName(FieldStorageDefinitionInterface $storage_definition, $is_deleted = FALSE) { + public static function _fieldRevisionTableName(FieldStorageDefinitionInterface $storage_definition, $is_deleted = FALSE) { if ($is_deleted) { // When a field is a deleted, the table is renamed to // {field_deleted_revision_FIELD_UUID}. To make sure we don't end up with @@ -1616,7 +1626,7 @@ static public function _fieldRevisionTableName(FieldStorageDefinitionInterface $ * @return string * The final table name. */ - static protected function _generateFieldTableName(FieldStorageDefinitionInterface $storage_definition, $revision) { + protected static function _generateFieldTableName(FieldStorageDefinitionInterface $storage_definition, $revision) { $separator = $revision ? '_revision__' : '__'; $table_name = $storage_definition->getTargetEntityTypeId() . $separator . $storage_definition->getName(); // Limit the string to 48 characters, keeping a 16 characters margin for db @@ -1649,7 +1659,7 @@ static protected function _generateFieldTableName(FieldStorageDefinitionInterfac * A string containing a generated index name for a field data table that is * unique among all other fields. */ - static public function _fieldIndexName(FieldStorageDefinitionInterface $storage_definition, $index) { + public static function _fieldIndexName(FieldStorageDefinitionInterface $storage_definition, $index) { return $storage_definition->getName() . '_' . $index; } @@ -1672,7 +1682,7 @@ static public function _fieldIndexName(FieldStorageDefinitionInterface $storage_ * A string containing a generated column name for a field data table that is * unique among all other fields. */ - static public function _fieldColumnName(FieldStorageDefinitionInterface $storage_definition, $column) { + public static function _fieldColumnName(FieldStorageDefinitionInterface $storage_definition, $column) { return in_array($column, FieldConfig::getReservedColumns()) ? $column : $storage_definition->getName() . '_' . $column; } diff --git a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php index c72f7de..76371ef 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php @@ -288,7 +288,7 @@ public function onInstanceCreate(FieldDefinitionInterface $field_definition) { } /** * {@inheritdoc} */ - public function onInstanceUpdate(FieldDefinitionInterface $field_definition) { } + public function onInstanceUpdate(FieldDefinitionInterface $field_definition, FieldDefinitionInterface $original) { } /** * {@inheritdoc} diff --git a/core/lib/Drupal/Core/Entity/Exception/StorageDefinitionUpdateForbiddenException.php b/core/lib/Drupal/Core/Entity/Exception/StorageDefinitionUpdateForbiddenException.php new file mode 100644 index 0000000..073bee6 --- /dev/null +++ b/core/lib/Drupal/Core/Entity/Exception/StorageDefinitionUpdateForbiddenException.php @@ -0,0 +1,13 @@ +range(0, 1) ->execute(); if ($found) { - throw new FieldConfigUpdateForbiddenException("Cannot update a list field not to include keys with existing data"); + throw new \Drupal\Core\Entity\Exception\StorageDefinitionUpdateForbiddenException("Cannot update a list field not to include keys with existing data"); } } } diff --git a/core/modules/field/field.module b/core/modules/field/field.module index 4e0157d..2295a16 100644 --- a/core/modules/field/field.module +++ b/core/modules/field/field.module @@ -211,20 +211,17 @@ function field_entity_bundle_field_info(EntityTypeInterface $entity_type, $bundl } } - /** * Implements hook_entity_bundle_rename(). */ function field_entity_bundle_rename($entity_type, $bundle_old, $bundle_new) { - $instances = entity_load_multiple_by_properties('field_instance_config', array('entity_type' => $entity_type, 'bundle' => $bundle_old)); + $instances = entity_load_multiple_by_properties('field_instance_config', array('entity_type' => $entity_type, 'bundle' => $bundle_old, 'include_deleted' => TRUE)); foreach ($instances as $instance) { - if ($instance->entity_type == $entity_type && $instance->bundle == $bundle_old) { - $id_new = $instance->entity_type . '.' . $bundle_new . '.' . $instance->field_name; - $instance->set('id', $id_new); - $instance->bundle = $bundle_new; - $instance->allowBundleRename(); - $instance->save(); - } + $id_new = $instance->entity_type . '.' . $bundle_new . '.' . $instance->field_name; + $instance->set('id', $id_new); + $instance->bundle = $bundle_new; + $instance->allowBundleRename(); + $instance->save(); } } diff --git a/core/modules/field/src/Entity/FieldConfig.php b/core/modules/field/src/Entity/FieldConfig.php index f9b3a53..66aa577 100644 --- a/core/modules/field/src/Entity/FieldConfig.php +++ b/core/modules/field/src/Entity/FieldConfig.php @@ -368,7 +368,7 @@ protected function preSaveUpdated(EntityStorageInterface $storage) { // Notify the storage. The controller can reject the definition // update as invalid by raising an exception, which stops execution before // the definition is written to config. - $entity_manager->getStorage($this->entity_type)->onFieldUpdate($this); + $entity_manager->getStorage($this->entity_type)->onFieldUpdate($this, $this->original); } /** diff --git a/core/modules/field/src/Entity/FieldInstanceConfig.php b/core/modules/field/src/Entity/FieldInstanceConfig.php index 25d511f..32130f4 100644 --- a/core/modules/field/src/Entity/FieldInstanceConfig.php +++ b/core/modules/field/src/Entity/FieldInstanceConfig.php @@ -350,7 +350,7 @@ public function preSave(EntityStorageInterface $storage) { // Set the default instance settings. $this->settings += $field_type_manager->getDefaultInstanceSettings($this->field->type); // Notify the entity storage. - $entity_manager->getStorage($this->entity_type)->onInstanceUpdate($this); + $entity_manager->getStorage($this->entity_type)->onInstanceUpdate($this, $this->original); } if (!$this->isSyncing()) { // Ensure the correct dependencies are present. diff --git a/core/modules/field/src/FieldConfigUpdateForbiddenException.php b/core/modules/field/src/FieldConfigUpdateForbiddenException.php deleted file mode 100644 index 412e146..0000000 --- a/core/modules/field/src/FieldConfigUpdateForbiddenException.php +++ /dev/null @@ -1,13 +0,0 @@ -save(); $this->pass(t("A changeable setting can be updated.")); } - catch (FieldException $e) { + catch (StorageDefinitionUpdateForbiddenException $e) { $this->fail(t("An unchangeable setting cannot be updated.")); } $field->settings['unchangeable']++; @@ -448,7 +449,7 @@ function testUpdateFieldForbid() { $field->save(); $this->fail(t("An unchangeable setting can be updated.")); } - catch (FieldException $e) { + catch (StorageDefinitionUpdateForbiddenException $e) { $this->pass(t("An unchangeable setting cannot be updated.")); } } diff --git a/core/modules/field/tests/modules/field_test/field_test.field.inc b/core/modules/field/tests/modules/field_test/field_test.field.inc index 79b57a3..3768f07 100644 --- a/core/modules/field/tests/modules/field_test/field_test.field.inc +++ b/core/modules/field/tests/modules/field_test/field_test.field.inc @@ -10,7 +10,7 @@ use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Session\AccountInterface; use Drupal\field\FieldConfigInterface; -use Drupal\field\FieldConfigUpdateForbiddenException; +use Drupal\Core\Entity\Exception\StorageDefinitionUpdateForbiddenException; /** * Implements hook_field_widget_info_alter(). @@ -24,7 +24,7 @@ function field_test_field_widget_info_alter(&$info) { */ function field_test_field_config_update_forbid(FieldConfigInterface $field, FieldConfigInterface $prior_field) { if ($field->getType() == 'test_field' && $field->getSetting('unchangeable') != $prior_field->getSetting('unchangeable')) { - throw new FieldConfigUpdateForbiddenException("field_test 'unchangeable' setting cannot be changed'"); + throw new StorageDefinitionUpdateForbiddenException("field_test 'unchangeable' setting cannot be changed'"); } } diff --git a/core/modules/options/options.module b/core/modules/options/options.module index 71bbf33..e51720d 100644 --- a/core/modules/options/options.module +++ b/core/modules/options/options.module @@ -8,7 +8,7 @@ use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\field\FieldConfigInterface; -use Drupal\field\FieldConfigUpdateForbiddenException; +use Drupal\Core\Entity\Exception\StorageDefinitionUpdateForbiddenException; use Symfony\Component\HttpFoundation\Request; /** @@ -100,7 +100,7 @@ function options_field_config_update_forbid(FieldConfigInterface $field, FieldCo $prior_allowed_values = $prior_field->getSetting('allowed_values'); $lost_keys = array_diff(array_keys($prior_allowed_values), array_keys($allowed_values)); if (_options_values_in_use($field->entity_type, $field->getName(), $lost_keys)) { - throw new FieldConfigUpdateForbiddenException(t('A list field (@field_name) with existing data cannot have its keys changed.', array('@field_name' => $field->getName()))); + throw new StorageDefinitionUpdateForbiddenException(t('A list field (@field_name) with existing data cannot have its keys changed.', array('@field_name' => $field->getName()))); } } }