X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs-website;a=blobdiff_plain;f=web%2Fcore%2Flib%2FDrupal%2FCore%2FEntity%2FSql%2FSqlContentEntityStorage.php;fp=web%2Fcore%2Flib%2FDrupal%2FCore%2FEntity%2FSql%2FSqlContentEntityStorage.php;h=29b8a9aa95ce1373883b7dd35c6732823f72d90d;hp=22238d4bf50548377308ab9e840598354b599ee1;hb=af6d1fb995500ae68849458ee10d66abbdcfb252;hpb=680c79a86e3ed402f263faeac92e89fb6d9edcc0 diff --git a/web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php b/web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php index 22238d4bf..29b8a9aa9 100644 --- a/web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php +++ b/web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php @@ -19,7 +19,6 @@ use Drupal\Core\Entity\Schema\DynamicallyFieldableEntityStorageSchemaInterface; use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Language\LanguageInterface; -use Drupal\field\FieldStorageConfigInterface; use Drupal\Core\Language\LanguageManagerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -469,9 +468,11 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt * Maps from storage records to entity objects, and attaches fields. * * @param array $records - * Associative array of query results, keyed on the entity ID. + * Associative array of query results, keyed on the entity ID or revision + * ID. * @param bool $load_from_revision - * Flag to indicate whether revisions should be loaded or not. + * (optional) Flag to indicate whether revisions should be loaded or not. + * Defaults to FALSE. * * @return array * An array of entity objects implementing the EntityInterface. @@ -506,7 +507,7 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt $translations = array_fill_keys(array_keys($values), []); // Load values from shared and dedicated tables. - $this->loadFromSharedTables($values, $translations); + $this->loadFromSharedTables($values, $translations, $load_from_revision); $this->loadFromDedicatedTables($values, $load_from_revision); $entities = []; @@ -523,11 +524,15 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt * Loads values for fields stored in the shared data tables. * * @param array &$values - * Associative array of entities values, keyed on the entity ID. + * Associative array of entities values, keyed on the entity ID or the + * revision ID. * @param array &$translations * List of translations, keyed on the entity ID. + * @param bool $load_from_revision + * Flag to indicate whether revisions should be loaded or not. */ - protected function loadFromSharedTables(array &$values, array &$translations) { + protected function loadFromSharedTables(array &$values, array &$translations, $load_from_revision) { + $record_key = !$load_from_revision ? $this->idKey : $this->revisionKey; if ($this->dataTable) { // If a revision table is available, we need all the properties of the // latest revision. Otherwise we fall back to the data table. @@ -535,8 +540,8 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt $alias = $this->revisionDataTable ? 'revision' : 'data'; $query = $this->database->select($table, $alias, ['fetch' => \PDO::FETCH_ASSOC]) ->fields($alias) - ->condition($alias . '.' . $this->idKey, array_keys($values), 'IN') - ->orderBy($alias . '.' . $this->idKey); + ->condition($alias . '.' . $record_key, array_keys($values), 'IN') + ->orderBy($alias . '.' . $record_key); $table_mapping = $this->getTableMapping(); if ($this->revisionDataTable) { @@ -581,7 +586,7 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt $result = $query->execute(); foreach ($result as $row) { - $id = $row[$this->idKey]; + $id = $row[$record_key]; // Field values in default language are stored with // LanguageInterface::LANGCODE_DEFAULT as key. @@ -609,19 +614,35 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt * {@inheritdoc} */ protected function doLoadRevisionFieldItems($revision_id) { - $revision = NULL; + @trigger_error('"\Drupal\Core\Entity\ContentEntityStorageBase::doLoadRevisionFieldItems()" is deprecated in Drupal 8.5.x and will be removed before Drupal 9.0.0. "\Drupal\Core\Entity\ContentEntityStorageBase::doLoadMultipleRevisionsFieldItems()" should be implemented instead. See https://www.drupal.org/node/2924915.', E_USER_DEPRECATED); + + $revisions = $this->doLoadMultipleRevisionsFieldItems([$revision_id]); + + return !empty($revisions) ? reset($revisions) : NULL; + } + + /** + * {@inheritdoc} + */ + protected function doLoadMultipleRevisionsFieldItems($revision_ids) { + $revisions = []; + + // Sanitize IDs. Before feeding ID array into buildQuery, check whether + // it is empty as this would load all entity revisions. + $revision_ids = $this->cleanIds($revision_ids, 'revision'); - // Build and execute the query. - $query_result = $this->buildQuery([], $revision_id)->execute(); - $records = $query_result->fetchAllAssoc($this->idKey); + if (!empty($revision_ids)) { + // Build and execute the query. + $query_result = $this->buildQuery(NULL, $revision_ids)->execute(); + $records = $query_result->fetchAllAssoc($this->revisionKey); - if (!empty($records)) { - // Convert the raw records to entity objects. - $entities = $this->mapFromStorageRecords($records, TRUE); - $revision = reset($entities) ?: NULL; + // Map the loaded records into entity objects and according fields. + if ($records) { + $revisions = $this->mapFromStorageRecords($records, TRUE); + } } - return $revision; + return $revisions; } /** @@ -677,20 +698,23 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt * * @param array|null $ids * An array of entity IDs, or NULL to load all entities. - * @param $revision_id - * The ID of the revision to load, or FALSE if this query is asking for the - * most current revision(s). + * @param array|bool $revision_ids + * The IDs of the revisions to load, or FALSE if this query is asking for + * the default revisions. Defaults to FALSE. * * @return \Drupal\Core\Database\Query\Select * A SelectQuery object for loading the entity. */ - protected function buildQuery($ids, $revision_id = FALSE) { + protected function buildQuery($ids, $revision_ids = FALSE) { $query = $this->database->select($this->entityType->getBaseTable(), 'base'); $query->addTag($this->entityTypeId . '_load_multiple'); - if ($revision_id) { - $query->join($this->revisionTable, 'revision', "revision.{$this->idKey} = base.{$this->idKey} AND revision.{$this->revisionKey} = :revisionId", [':revisionId' => $revision_id]); + if ($revision_ids) { + if (!is_array($revision_ids)) { + @trigger_error('Passing a single revision ID to "\Drupal\Core\Entity\Sql\SqlContentEntityStorage::buildQuery()" is deprecated in Drupal 8.5.x and will be removed before Drupal 9.0.0. An array of revision IDs should be given instead. See https://www.drupal.org/node/2924915.', E_USER_DEPRECATED); + } + $query->join($this->revisionTable, 'revision', "revision.{$this->idKey} = base.{$this->idKey} AND revision.{$this->revisionKey} IN (:revisionIds[])", [':revisionIds[]' => (array) $revision_ids]); } elseif ($this->revisionTable) { $query->join($this->revisionTable, 'revision', "revision.{$this->revisionKey} = base.{$this->revisionKey}"); @@ -1114,8 +1138,7 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt * @param array &$values * An array of values keyed by entity ID. * @param bool $load_from_revision - * (optional) Flag to indicate whether revisions should be loaded or not, - * defaults to FALSE. + * Flag to indicate whether revisions should be loaded or not. */ protected function loadFromDedicatedTables(array &$values, $load_from_revision) { if (empty($values)) { @@ -1167,21 +1190,22 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt foreach ($results as $row) { $bundle = $row->bundle; + $value_key = !$load_from_revision ? $row->entity_id : $row->revision_id; // Field values in default language are stored with // LanguageInterface::LANGCODE_DEFAULT as key. $langcode = LanguageInterface::LANGCODE_DEFAULT; - if ($this->langcodeKey && isset($default_langcodes[$row->entity_id]) && $row->langcode != $default_langcodes[$row->entity_id]) { + if ($this->langcodeKey && isset($default_langcodes[$value_key]) && $row->langcode != $default_langcodes[$value_key]) { $langcode = $row->langcode; } - if (!isset($values[$row->entity_id][$field_name][$langcode])) { - $values[$row->entity_id][$field_name][$langcode] = []; + if (!isset($values[$value_key][$field_name][$langcode])) { + $values[$value_key][$field_name][$langcode] = []; } // Ensure that records for non-translatable fields having invalid // languages are skipped. if ($langcode == LanguageInterface::LANGCODE_DEFAULT || $definitions[$bundle][$field_name]->isTranslatable()) { - if ($storage_definition->getCardinality() == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED || count($values[$row->entity_id][$field_name][$langcode]) < $storage_definition->getCardinality()) { + if ($storage_definition->getCardinality() == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED || count($values[$value_key][$field_name][$langcode]) < $storage_definition->getCardinality()) { $item = []; // For each column declared by the field, populate the item from the // prefixed database column. @@ -1192,7 +1216,7 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt } // Add the item to the field values for the entity. - $values[$row->entity_id][$field_name][$langcode][] = $item; + $values[$value_key][$field_name][$langcode][] = $item; } } } @@ -1468,9 +1492,7 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt $this->entityManager->getLastInstalledFieldStorageDefinitions($this->entityType->id()) ); - // @todo Remove the FieldStorageConfigInterface check when non-configurable - // fields support purging: https://www.drupal.org/node/2282119. - if ($storage_definition instanceof FieldStorageConfigInterface && $table_mapping->requiresDedicatedTableStorage($storage_definition)) { + if ($table_mapping->requiresDedicatedTableStorage($storage_definition)) { // Mark all data associated with the field for deletion. $table = $table_mapping->getDedicatedDataTableName($storage_definition); $revision_table = $table_mapping->getDedicatedRevisionTableName($storage_definition); @@ -1554,9 +1576,8 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt // Check whether the whole field storage definition is gone, or just some // bundle fields. $storage_definition = $field_definition->getFieldStorageDefinition(); - $is_deleted = $this->storageDefinitionIsDeleted($storage_definition); $table_mapping = $this->getTableMapping(); - $table_name = $table_mapping->getDedicatedDataTableName($storage_definition, $is_deleted); + $table_name = $table_mapping->getDedicatedDataTableName($storage_definition, $storage_definition->isDeleted()); // Get the entities which we want to purge first. $entity_query = $this->database->select($table_name, 't', ['fetch' => \PDO::FETCH_ASSOC]); @@ -1614,7 +1635,7 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt */ protected function purgeFieldItems(ContentEntityInterface $entity, FieldDefinitionInterface $field_definition) { $storage_definition = $field_definition->getFieldStorageDefinition(); - $is_deleted = $this->storageDefinitionIsDeleted($storage_definition); + $is_deleted = $storage_definition->isDeleted(); $table_mapping = $this->getTableMapping(); $table_name = $table_mapping->getDedicatedDataTableName($storage_definition, $is_deleted); $revision_name = $table_mapping->getDedicatedRevisionTableName($storage_definition, $is_deleted); @@ -1651,7 +1672,7 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt $table_mapping = $this->getTableMapping($storage_definitions); if ($table_mapping->requiresDedicatedTableStorage($storage_definition)) { - $is_deleted = $this->storageDefinitionIsDeleted($storage_definition); + $is_deleted = $storage_definition->isDeleted(); if ($this->entityType->isRevisionable()) { $table_name = $table_mapping->getDedicatedRevisionTableName($storage_definition, $is_deleted); } @@ -1724,15 +1745,14 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt * * @return bool * Whether the field has been already deleted. + * + * @deprecated in Drupal 8.5.x, will be removed before Drupal 9.0.0. Use + * \Drupal\Core\Field\FieldStorageDefinitionInterface::isDeleted() instead. + * + * @see https://www.drupal.org/node/2907785 */ protected function storageDefinitionIsDeleted(FieldStorageDefinitionInterface $storage_definition) { - // Configurable fields are marked for deletion. - if ($storage_definition instanceof FieldStorageConfigInterface) { - return $storage_definition->isDeleted(); - } - // For non configurable fields check whether they are still in the last - // installed schema repository. - return !array_key_exists($storage_definition->getName(), $this->entityManager->getLastInstalledFieldStorageDefinitions($this->entityTypeId)); + return $storage_definition->isDeleted(); } }