diff --git a/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php b/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php index dd19fcb..ebb0514 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php @@ -953,20 +953,21 @@ protected function doLoadFieldItems($entities, $age) { } // Collect impacted fields. - $fields = array(); + $storage_definitions = array(); $definitions = array(); foreach ($bundles as $bundle => $v) { - foreach ($this->entityManager->getFieldDefinitions($this->entityTypeId, $bundle) as $field_name => $field_definition) { - if ($this->usesDedicatedTable($field_definition)) { - $fields[$field_name] = $field_definition; + $definitions[$bundle] = $this->entityManager->getFieldDefinitions($this->entityTypeId, $bundle); + foreach ($definitions[$bundle] as $field_name => $field_definition) { + if ($this->usesDedicatedTable($field_definition->getFieldStorageDefinition())) { + $storage_definitions[$field_name] = $field_definition->getFieldStorageDefinition(); } } } // Load field data. $langcodes = array_keys(language_list(LanguageInterface::STATE_ALL)); - foreach ($fields as $field_name => $field) { - $table = $load_current ? static::_fieldTableName($field) : static::_fieldRevisionTableName($field); + foreach ($storage_definitions as $field_name => $storage_definition) { + $table = $load_current ? static::_fieldTableName($storage_definition) : static::_fieldRevisionTableName($storage_definition); // Ensure that only values having valid languages are retrieved. Since we // are loading values for multiple entities, we cannot limit the query to @@ -990,12 +991,12 @@ protected function doLoadFieldItems($entities, $age) { $delta_count[$row->entity_id][$row->langcode] = 0; } - if ($field->getCardinality() == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED || $delta_count[$row->entity_id][$row->langcode] < $field->getCardinality()) { + if ($storage_definition->getCardinality() == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED || $delta_count[$row->entity_id][$row->langcode] < $storage_definition->getCardinality()) { $item = array(); // For each column declared by the field, populate the item from the // prefixed database column. - foreach ($field->getColumns() as $column => $attributes) { - $column_name = static::_fieldColumnName($field, $column); + foreach ($storage_definition->getColumns() as $column => $attributes) { + $column_name = static::_fieldColumnName($storage_definition, $column); // Unserialize the value if specified in the column schema. $item[$column] = (!empty($attributes['serialize'])) ? unserialize($row->$column_name) : $row->$column_name; } @@ -1025,11 +1026,12 @@ protected function doSaveFieldItems(EntityInterface $entity, $update) { } foreach ($this->entityManager->getFieldDefinitions($entity_type, $bundle) as $field_name => $field_definition) { - if (!$this->usesDedicatedTable($field_definition)) { + $storage_definition = $field_definition->getFieldStorageDefinition(); + if (!$this->usesDedicatedTable($storage_definition)) { continue; } - $table_name = static::_fieldTableName($field_definition); - $revision_name = static::_fieldRevisionTableName($field_definition); + $table_name = static::_fieldTableName($storage_definition); + $revision_name = static::_fieldRevisionTableName($storage_definition); // Delete and insert, rather than update, in case a value was added. if ($update) { @@ -1049,8 +1051,8 @@ protected function doSaveFieldItems(EntityInterface $entity, $update) { // Prepare the multi-insert query. $do_insert = FALSE; $columns = array('entity_id', 'revision_id', 'bundle', 'delta', 'langcode'); - foreach ($field_definition->getColumns() as $column => $attributes) { - $columns[] = static::_fieldColumnName($field_definition, $column); + foreach ($storage_definition->getColumns() as $column => $attributes) { + $columns[] = static::_fieldColumnName($storage_definition, $column); } $query = $this->database->insert($table_name)->fields($columns); $revision_query = $this->database->insert($revision_name)->fields($columns); @@ -1070,15 +1072,15 @@ protected function doSaveFieldItems(EntityInterface $entity, $update) { 'delta' => $delta, 'langcode' => $langcode, ); - foreach ($field_definition->getColumns() as $column => $attributes) { - $column_name = static::_fieldColumnName($field_definition, $column); + foreach ($storage_definition->getColumns() as $column => $attributes) { + $column_name = static::_fieldColumnName($storage_definition, $column); // Serialize the value if specified in the column schema. $record[$column_name] = !empty($attributes['serialize']) ? serialize($item->$column) : $item->$column; } $query->values($record); $revision_query->values($record); - if ($field_definition->getCardinality() != FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED && ++$delta_count == $field_definition->getCardinality()) { + if ($storage_definition->getCardinality() != FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED && ++$delta_count == $storage_definition->getCardinality()) { break; } } @@ -1101,11 +1103,12 @@ protected function doSaveFieldItems(EntityInterface $entity, $update) { */ protected function doDeleteFieldItems(EntityInterface $entity) { foreach ($this->entityManager->getFieldDefinitions($entity->getEntityTypeId(), $entity->bundle()) as $field_definition) { - if (!$this->usesDedicatedTable($field_definition)) { + $storage_definition = $field_definition->getFieldStorageDefinition(); + if (!$this->usesDedicatedTable($storage_definition)) { continue; } - $table_name = static::_fieldTableName($field_definition); - $revision_name = static::_fieldRevisionTableName($field_definition); + $table_name = static::_fieldTableName($storage_definition); + $revision_name = static::_fieldRevisionTableName($storage_definition); $this->database->delete($table_name) ->condition('entity_id', $entity->id()) ->execute(); @@ -1122,10 +1125,11 @@ protected function doDeleteFieldItemsRevision(EntityInterface $entity) { $vid = $entity->getRevisionId(); if (isset($vid)) { foreach ($this->entityManager->getFieldDefinitions($entity->getEntityTypeId(), $entity->bundle()) as $field_definition) { - if (!$this->usesDedicatedTable($field_definition)) { + $storage_definition = $field_definition->getFieldStorageDefinition(); + if (!$this->usesDedicatedTable($storage_definition)) { continue; } - $revision_name = static::_fieldRevisionTableName($field_definition); + $revision_name = static::_fieldRevisionTableName($storage_definition); $this->database->delete($revision_name) ->condition('entity_id', $entity->id()) ->condition('revision_id', $vid) @@ -1270,8 +1274,9 @@ public function onFieldStorageDefinitionDelete(FieldStorageDefinitionInterface $ * {@inheritdoc} */ public function onFieldDefinitionDelete(FieldDefinitionInterface $field_definition) { - $table_name = static::_fieldTableName($field_definition); - $revision_name = static::_fieldRevisionTableName($field_definition); + $storage_definition = $field_definition->getFieldStorageDefinition(); + $table_name = static::_fieldTableName($storage_definition); + $revision_name = static::_fieldRevisionTableName($storage_definition); $this->database->update($table_name) ->fields(array('deleted' => 1)) ->condition('bundle', $field_definition->getBundle()) @@ -1288,9 +1293,10 @@ public function onFieldDefinitionDelete(FieldDefinitionInterface $field_definiti public function onFieldDefinitionUpdate(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); + $storage_definition = $field_definition->getFieldStorageDefinition(); + $is_deleted = $this->storageDefinitionIsDeleted($storage_definition); + $table_name = static::_fieldTableName($storage_definition, $is_deleted); + $revision_name = static::_fieldRevisionTableName($storage_definition, $is_deleted); $this->database->update($table_name) ->fields(array('bundle' => $field_definition->getBundle())) ->condition('bundle', $original->getBundle()) @@ -1308,14 +1314,15 @@ public function onFieldDefinitionUpdate(FieldDefinitionInterface $field_definiti protected function readFieldItemsToPurge(FieldDefinitionInterface $field_definition, $batch_size) { // Check whether the whole field storage definition is gone, or just some // bundle fields. - $is_deleted = $this->storageDefinitionIsDeleted($field_definition); - $table_name = static::_fieldTableName($field_definition, $is_deleted); + $storage_definition = $field_definition->getFieldStorageDefinition(); + $is_deleted = $this->storageDefinitionIsDeleted($storage_definition); + $table_name = static::_fieldTableName($storage_definition, $is_deleted); // Get the entities which we want to purge first. $entity_query = $this->database->select($table_name, 't', array('fetch' => \PDO::FETCH_ASSOC)); $or = $entity_query->orConditionGroup(); - foreach ($field_definition->getColumns() as $column_name => $data) { - $or->isNotNull(static::_fieldColumnName($field_definition, $column_name)); + foreach ($storage_definition->getColumns() as $column_name => $data) { + $or->isNotNull(static::_fieldColumnName($storage_definition, $column_name)); } $entity_query ->distinct(TRUE) @@ -1325,8 +1332,8 @@ protected function readFieldItemsToPurge(FieldDefinitionInterface $field_definit // Create a map of field data table column names to field column names. $column_map = array(); - foreach ($field_definition->getColumns() as $column_name => $data) { - $column_map[static::_fieldColumnName($field_definition, $column_name)] = $column_name; + foreach ($storage_definition->getColumns() as $column_name => $data) { + $column_map[static::_fieldColumnName($storage_definition, $column_name)] = $column_name; } $entities = array(); diff --git a/core/modules/system/src/Tests/Entity/EntityBundleFieldTest.php b/core/modules/system/src/Tests/Entity/EntityBundleFieldTest.php index f1048eb..0023397 100644 --- a/core/modules/system/src/Tests/Entity/EntityBundleFieldTest.php +++ b/core/modules/system/src/Tests/Entity/EntityBundleFieldTest.php @@ -2,7 +2,7 @@ /** * @file - * Contains Drupal\system\Tests\Entity\EntityBundleFieldTest. + * Contains \Drupal\system\Tests\Entity\EntityBundleFieldTest. */ namespace Drupal\system\Tests\Entity; @@ -27,6 +27,13 @@ class EntityBundleFieldTest extends EntityUnitTestBase { protected $database; /** + * Modules to enable. + * + * @var array + */ + public static $modules = array('menu_link'); + + /** * {@inheritdoc} */ public static function getInfo() { @@ -99,13 +106,26 @@ public function testCustomBundleFieldUsage() { $table = $storage->_fieldTableName($entity->getFieldDefinition('custom_field')); $result = $this->database->select($table, 'f') ->fields('f') - ->condition('entity_id', $entity->id()) + ->condition('f.entity_id', $entity->id()) ->execute(); $this->assertFalse($result->fetchAssoc(), 'Field data has been deleted'); - // Delete the bundle. + // Create another entity to test that values are marked as deleted when a + // bundle is deleted. + $entity = $storage->create(['type' => 'custom', 'custom_field' => 'new']); + $entity->save(); entity_test_delete_bundle('custom'); - $this->assertFalse($this->database->schema()->tableExists($table), 'Custom field table was deleted'); + + $table = $storage->_fieldTableName($entity->getFieldDefinition('custom_field')); + $result = $this->database->select($table, 'f') + ->condition('f.entity_id', $entity->id()) + ->condition('deleted', 1) + ->countQuery() + ->execute(); + $this->assertEqual(1, $result->fetchField(), 'Field data has been deleted'); + + // @todo Test field purge and table deletion once supported. + // $this->assertFalse($this->database->schema()->tableExists($table), 'Custom field table was deleted'); } }