function Query::prepare

Prepares the basic query with proper metadata/tags and base fields.

Return value

$this Returns the called object.

Throws

\Drupal\Core\Entity\Query\QueryException Thrown if the base table does not exist.

1 call to Query::prepare()
QueryAggregate::prepare in core/lib/Drupal/Core/Entity/Query/Sql/QueryAggregate.php
Prepares the basic query with proper metadata/tags and base fields.
2 methods override Query::prepare()
Query::prepare in core/modules/workspaces/src/EntityQuery/Query.php
Prepares the basic query with proper metadata/tags and base fields.
QueryAggregate::prepare in core/lib/Drupal/Core/Entity/Query/Sql/QueryAggregate.php
Prepares the basic query with proper metadata/tags and base fields.

File

core/lib/Drupal/Core/Entity/Query/Sql/Query.php, line 97

Class

Query
The SQL storage entity query class.

Namespace

Drupal\Core\Entity\Query\Sql

Code

protected function prepare() {
  if ($this->allRevisions) {
    if (!$base_table = $this->entityType
      ->getRevisionTable()) {
      throw new QueryException("No revision table for " . $this->entityTypeId . ", invalid query.");
    }
  }
  else {
    if (!$base_table = $this->entityType
      ->getBaseTable()) {
      throw new QueryException("No base table for " . $this->entityTypeId . ", invalid query.");
    }
  }
  $simple_query = TRUE;
  if ($this->entityType
    ->getDataTable()) {
    $simple_query = FALSE;
  }
  $this->sqlQuery = $this->connection
    ->select($base_table, 'base_table', [
    'conjunction' => $this->conjunction,
  ]);
  // Reset the tables structure, as it might have been built for a previous
  // execution of this query.
  $this->tables = NULL;
  $this->sqlQuery
    ->addMetaData('entity_type', $this->entityTypeId);
  $id_field = $this->entityType
    ->getKey('id');
  // Add the key field for fetchAllKeyed().
  if (!$revision_field = $this->entityType
    ->getKey('revision')) {
    // When there is no revision support, the key field is the entity key.
    $this->sqlFields["base_table.{$id_field}"] = [
      'base_table',
      $id_field,
    ];
    // Now add the value column for fetchAllKeyed(). This is always the
    // entity id.
    $this->sqlFields["base_table.{$id_field}" . '_1'] = [
      'base_table',
      $id_field,
    ];
  }
  else {
    // When there is revision support, the key field is the revision key.
    $this->sqlFields["base_table.{$revision_field}"] = [
      'base_table',
      $revision_field,
    ];
    // Now add the value column for fetchAllKeyed(). This is always the
    // entity id.
    $this->sqlFields["base_table.{$id_field}"] = [
      'base_table',
      $id_field,
    ];
  }
  // Use a subquery with MAX() to only return the latest revision in the most
  // optimal way. Note that this query is extremely performance-sensitive and
  // changes here need to be tested on a database where there are many
  // revisions and many entities.
  if ($this->latestRevision && $revision_field) {
    // Fetch all latest revision ids in a sub-query.
    $revision_subquery = $this->connection
      ->select($base_table, 'subquery_base_table');
    $revision_subquery->fields('subquery_base_table', [
      $id_field,
    ]);
    $revision_subquery->addExpression("MAX(subquery_base_table.{$revision_field})", 'maximum_revision_id');
    $revision_subquery->groupBy("subquery_base_table.{$id_field}");
    // Optimize the query if the query is only looking for a single entity.
    // This improves the performance of
    // \Drupal\Core\Entity\ContentEntityStorageBase::getLatestRevisionId().
    $conditions = $this->condition
      ->conditions();
    if (count($conditions) === 1 && isset($conditions[0]['field']) && $conditions[0]['field'] === $id_field) {
      $revision_subquery->condition($id_field, $conditions[0]['value'], $conditions[0]['operator']);
    }
    // Restrict results only to latest ids.
    $this->sqlQuery
      ->innerJoin($revision_subquery, 'sq_base_table', "base_table.{$id_field} = sq_base_table.{$id_field} AND base_table.{$revision_field} = sq_base_table.maximum_revision_id");
  }
  if (is_null($this->accessCheck)) {
    throw new QueryException('Entity queries must explicitly set whether the query should be access checked or not. See Drupal\\Core\\Entity\\Query\\QueryInterface::accessCheck().');
  }
  if ($this->accessCheck) {
    $this->sqlQuery
      ->addTag($this->entityTypeId . '_access');
  }
  $this->sqlQuery
    ->addTag('entity_query');
  $this->sqlQuery
    ->addTag('entity_query_' . $this->entityTypeId);
  // Add further tags added.
  if (isset($this->alterTags)) {
    foreach ($this->alterTags as $tag => $value) {
      $this->sqlQuery
        ->addTag($tag);
    }
  }
  // Add further metadata added.
  if (isset($this->alterMetaData)) {
    foreach ($this->alterMetaData as $key => $value) {
      $this->sqlQuery
        ->addMetaData($key, $value);
    }
  }
  // This now contains first the table containing entity properties and
  // last the entity base table. They might be the same.
  $this->sqlQuery
    ->addMetaData('all_revisions', $this->allRevisions);
  $this->sqlQuery
    ->addMetaData('simple_query', $simple_query);
  return $this;
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.