function SqlContentEntityStorage::loadFromDedicatedTables
Same name and namespace in other branches
- 11.x core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php \Drupal\Core\Entity\Sql\SqlContentEntityStorage::loadFromDedicatedTables()
- 10 core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php \Drupal\Core\Entity\Sql\SqlContentEntityStorage::loadFromDedicatedTables()
- 9 core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php \Drupal\Core\Entity\Sql\SqlContentEntityStorage::loadFromDedicatedTables()
- 8.9.x core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php \Drupal\Core\Entity\Sql\SqlContentEntityStorage::loadFromDedicatedTables()
Loads values of fields stored in dedicated tables for a group of entities.
Parameters
array &$values: An array of values keyed by entity ID.
bool $load_from_revision: Flag to indicate whether revisions should be loaded or not.
1 call to SqlContentEntityStorage::loadFromDedicatedTables()
- SqlContentEntityStorage::mapFromStorageRecords in core/
lib/ Drupal/ Core/ Entity/ Sql/ SqlContentEntityStorage.php - Maps from storage records to entity objects, and attaches fields.
File
-
core/
lib/ Drupal/ Core/ Entity/ Sql/ SqlContentEntityStorage.php, line 1192
Class
- SqlContentEntityStorage
- A content entity database storage implementation.
Namespace
Drupal\Core\Entity\SqlCode
protected function loadFromDedicatedTables(array &$values, $load_from_revision) {
if (empty($values)) {
return;
}
// Collect entities ids, bundles and languages.
$bundles = [];
$ids = [];
$default_langcodes = [];
foreach ($values as $key => $entity_values) {
$bundles[$this->bundleKey ? $entity_values[$this->bundleKey][LanguageInterface::LANGCODE_DEFAULT] : $this->entityTypeId] = TRUE;
$ids[] = !$load_from_revision ? $key : $entity_values[$this->revisionKey][LanguageInterface::LANGCODE_DEFAULT];
if ($this->langcodeKey && isset($entity_values[$this->langcodeKey][LanguageInterface::LANGCODE_DEFAULT])) {
$default_langcodes[$key] = $entity_values[$this->langcodeKey][LanguageInterface::LANGCODE_DEFAULT];
}
}
// Collect impacted fields.
$storage_definitions = [];
$definitions = [];
$table_mapping = $this->getTableMapping();
foreach ($bundles as $bundle => $v) {
$definitions[$bundle] = $this->entityFieldManager
->getFieldDefinitions($this->entityTypeId, $bundle);
foreach ($definitions[$bundle] as $field_name => $field_definition) {
$storage_definition = $field_definition->getFieldStorageDefinition();
if ($table_mapping->requiresDedicatedTableStorage($storage_definition)) {
$storage_definitions[$field_name] = $storage_definition;
}
}
}
if (!$storage_definitions) {
return;
}
// Load field data.
$langcodes = array_keys($this->languageManager
->getLanguages(LanguageInterface::STATE_ALL));
$single_cardinality_fields = [];
$multiple_cardinality_fields = [];
foreach ($storage_definitions as $field_name => $storage_definition) {
if ($storage_definition->getCardinality() === 1) {
$single_cardinality_fields[$field_name] = $storage_definition;
}
else {
$multiple_cardinality_fields[$field_name] = $storage_definition;
}
}
$id_key = !$load_from_revision ? 'entity_id' : 'revision_id';
// Because any field could potentially have no data, we need to begin
// the query from a table that will reliably exist, which means the base,
// data, or revision table.
$base_table = !$load_from_revision ? $this->dataTable ?? $this->baseTable : $this->revisionDataTable ?? $this->revisionTable;
$base_id_key = !$load_from_revision ? $this->idKey : $this->revisionKey;
$base_query = $this->database
->select($base_table, $base_table)
->fields($base_table, [
$base_id_key,
])
->condition("[{$base_table}].[{$base_id_key}]", $ids, 'IN');
// If the entity is translatable, ensure only rows with valid langcodes
// are loaded.
if ($this->langcodeKey) {
$base_query->condition("[{$base_table}].[{$this->langcodeKey}]", $langcodes, 'IN');
$base_query->addField($base_table, $this->langcodeKey);
}
if ($single_cardinality_fields) {
$query = clone $base_query;
// Add a left join for each single cardinality field.
foreach ($single_cardinality_fields as $field_name => $storage_definition) {
$table = !$load_from_revision ? $table_mapping->getDedicatedDataTableName($storage_definition) : $table_mapping->getDedicatedRevisionTableName($storage_definition);
// If the entity is translatable, add the langcode to the join and
// a condition on valid langcodes.
if ($this->langcodeKey) {
$query->leftJoin($table, $table, "[{$table}].[{$id_key}] = [{$base_table}].[{$base_id_key}] AND [{$table}].[langcode] = [{$base_table}].[{$this->langcodeKey}] AND [{$table}].[deleted] = 0");
}
else {
$query->leftJoin($table, $table, "[{$table}].[{$id_key}] = [{$base_table}].[{$base_id_key}] AND [{$table}].[deleted] = 0");
}
$query->fields($table, $this->tableMapping
->getColumnNames($field_name));
}
$results = $query->execute();
$is_not_null = fn($value) => !is_null($value);
foreach ($results as $row) {
$row = (array) $row;
$value_key = $row[$base_id_key];
// Field values in default language are stored with
// LanguageInterface::LANGCODE_DEFAULT as key.
$langcode = LanguageInterface::LANGCODE_DEFAULT;
if ($this->langcodeKey && isset($default_langcodes[$value_key]) && $row[$this->langcodeKey] != $default_langcodes[$value_key]) {
$langcode = $row[$this->langcodeKey];
}
foreach ($single_cardinality_fields as $field_name => $storage_definition) {
$bundle = $this->bundleKey ? $values[$value_key][$this->bundleKey][LanguageInterface::LANGCODE_DEFAULT] : $this->entityTypeId;
$field_values = array_intersect_key($row, array_flip($this->tableMapping
->getColumnNames($field_name)));
// If all the field values are null, then there was no result for this
// field.
// @todo use array_any() once Drupal core requires PHP 8.4.
if (empty(array_filter($field_values, $is_not_null))) {
continue;
}
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 (empty($values[$value_key][$field_name][$langcode])) {
$item = [];
// For each column declared by the field, populate the item from
// the prefixed database column.
foreach ($storage_definition->getColumns() as $column => $attributes) {
$column_name = $table_mapping->getFieldColumnName($storage_definition, $column);
// Unserialize the value if specified in the column schema.
$item[$column] = !empty($attributes['serialize']) ? $this->handleNullableFieldUnserialize($row[$column_name]) : $row[$column_name];
}
// Add the item to the field values for the entity.
$values[$value_key][$field_name][$langcode][] = $item;
}
}
}
}
}
if ($multiple_cardinality_fields) {
$query = clone $base_query;
$delta_keys = [];
foreach ($multiple_cardinality_fields as $field_name => $storage_definition) {
$table = !$load_from_revision ? $table_mapping->getDedicatedDataTableName($storage_definition) : $table_mapping->getDedicatedRevisionTableName($storage_definition);
// If the entity is translatable, add the langcode to the join and
// a condition on valid langcodes.
if ($this->langcodeKey) {
$query->leftJoin($table, $table, "[{$table}].[{$id_key}] = [{$base_table}].[{$base_id_key}] AND [{$table}].[langcode] = [{$base_table}].[{$this->langcodeKey}] AND [{$table}].[deleted] = 0");
}
else {
$query->leftJoin($table, $table, "[{$table}].[{$id_key}] = [{$base_table}].[{$base_id_key}] AND [{$table}].[deleted] = 0");
}
$query->fields($table, $this->tableMapping
->getColumnNames($field_name));
$delta_keys[$field_name] = $query->addField($table, 'delta', $field_name . '_delta');
}
$results = $query->execute();
foreach ($results as $row) {
$row = (array) $row;
$value_key = $row[$base_id_key];
// Field values in default language are stored with
// LanguageInterface::LANGCODE_DEFAULT as key.
$langcode = LanguageInterface::LANGCODE_DEFAULT;
if ($this->langcodeKey && isset($default_langcodes[$value_key]) && $row[$this->langcodeKey] != $default_langcodes[$value_key]) {
$langcode = $row[$this->langcodeKey];
}
foreach ($multiple_cardinality_fields as $field_name => $storage_definition) {
$delta_key = $delta_keys[$field_name];
$bundle = $this->bundleKey ? $values[$value_key][$this->bundleKey][LanguageInterface::LANGCODE_DEFAULT] : $this->entityTypeId;
// If the delta is null then there are no values at this delta for
// this field.
if (!isset($row[$delta_key])) {
continue;
}
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 || $row[$delta_key] < $storage_definition->getCardinality()) {
$item = [];
// For each column declared by the field, populate the item from
// the prefixed database column.
foreach ($storage_definition->getColumns() as $column => $attributes) {
$column_name = $table_mapping->getFieldColumnName($storage_definition, $column);
// Unserialize the value if specified in the column schema.
$item[$column] = !empty($attributes['serialize']) ? $this->handleNullableFieldUnserialize($row[$column_name]) : $row[$column_name];
}
// Add the item to the field values for the entity.
$values[$value_key][$field_name][$langcode][(int) $row[$delta_key]] = $item;
}
}
}
}
// Ensure that all of the deltas from all of the multiple cardinality
// fields are returned in the correct order.
foreach ($values as &$fields) {
foreach ($fields as $field_name => &$field_data) {
if (isset($multiple_cardinality_fields[$field_name])) {
foreach ($field_data as &$language_data) {
ksort($language_data);
}
}
}
}
}
}
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.