Lesson 6.1 - Entity queries and loading entities

This lesson is an explanation of how to query entities in Drupal 8.

In this lesson...

  • Assemble the module examples/query_example.
  • Learn about entity queries.
  • Learn about entity loading.
  • Explore and build the QueryExampleController class.

Drupal core has historically provided limited approaches to manipulating and using the entity system which was initially introduced with Drupal-7 and as a result of that need, a solution arose in the contributed module space. This effort is the Entity API module. Drupal 7 core, however, it did provide the EntityFieldQuery class, which can be used to search Drupal entities programmatically. The class contains several methods that aid with entity queries based on conditions such as field values or class properties. Additional documentation on the subject can be found on drupal.org at How to use EntityFieldQuery.

Querying entities has changed since Drupal 7 because EntityFieldQuery has been replaced by the core service called entity.query which can instantiate a query object for a specified entity type. The entity.query is an implementation of the QueryInterface, which is never directly implemented. Instead, the QueryInterface is implemented through QueryFactory classes such as entity.query. It is possible to use this service statically through the \Drupal namespace or by leveraging dependency injection.

The entity query service

The entity query service allows us to get a list of nodes that match a pattern. This is similar to an SQL query, but instead of writing a single statement, we build a query object and then execute it. We can call functions on this query object to add filters or specify parameters of the query. These two techniques function with content entities such as nodes, users, comments, taxonomy terms, and configuration entities.

There are two ways to create this query object.

Class based method (recommended)

We will talk about services more in later chapters. In this example, we will use the following method, using class variables and functions to obtain a query object. We'll use that object to get a list of node ids that match a pattern.

// This function and the next are part of the dependency injection pattern. We will explain those in future chapters.
public function __construct(QueryFactory $entity_query) {
  $this->entity_query = $entity_query;
}
  
public static function create(ContainerInterface $container) {
  return new static(
    // User the $container to get a query factory object. This object lets us create query objects.
    $container->get('entity.query')
  );
}
 
// This function shows how to
public function myCallback() {
  // Use the factory to create a query object for node entities.
  $query = $this->entity_query->get('node');
 
  // Add a filter (published).
  $query->condition('status', 1);
 
  // Run the query.
  $nids = $query->execute();
}

Static method (not recommended)

Most code is no longer stored in a module's *.module file, so if the need arises you will not be able to use the service container. This also holds true with building tests. In these two instances, you may need to use the static call to entity.query (or a similar method).

To statically use the entity.query, add the following to your code:

$query = \Drupal::entityQuery('node');

If you want to use a different type of entity, you can replace node. You can specify any other entity type's machine name to obtain the query object for the specified entity type inside of the $query variable. The entityQuery() static method on the \Drupal namespace is a shortcut, using the entity.query service.

Querying entities

The following are examples of querying for node entities using a query object.

This is an example of a basic static query capable of returning a site's published nodes. The $nids variable will return an array of node ids. These nids will be keyed by revision ids in the event that revisioning is enabled for the entity type of node. Or, the nids will be keyed by the entity ids if revisioning is disabled.

/**
 * @var $query \Drupal\Core\Entity\Query\QueryInterface
 */
$query = $this->entity_query->get('node')
    ->condition('status', 1);
      
$nids = $query->execute();

Query conditions

The next example uses both property and field conditions in addition to checking for a published status of true. In this query, we retrieve the node ids of all the published nodes that were last updated, prior to the time the query was run. The node title must contain the word the words ipsum lorem. The node will contain the taxonomy term called test as a value in the field field_tags.

$query = $this->entity_query->get('node')
    ->condition('status', 1)
    ->condition('changed', REQUEST_TIME, '<')
    ->condition('title', 'ipsum lorem', 'CONTAINS')
    ->condition('field_tags.entity.name', 'test');
 
$nids = $query->execute();

There is no distinction between propertyCondition and fieldCondition which had been different when using EntityFieldQuery in Drupal 7. This is because in Drupal 8 the QueryInterface class provides the condition() method which combines both the property and field conditions and allows for condition groups. It is also possible to specify conditions based on referenced entities by adding the entity.(column) to the entity reference field name like we did for taxonomy and the value of test.

Grouping Query Conditions

This example demonstrates how condition groups which can include both AND and OR operators allow for more powerful queries. It alters the previous query to retrieve nodes that either have:

  • the ipsum lorem string in their title
  • have a reference to the taxonomy term test in their field_tags field.
$query = $this->entity_query->get('node')
    ->condition('status', 1)
    ->condition('changed', REQUEST_TIME, '<');
  
$group = $query->orConditionGroup()
    ->condition('title', 'ipsum lorem', 'CONTAINS')
    ->condition('field_tags.entity.name', 'test');
  
$nids = $query->condition($group)->execute();

This OR test was created with an orConditionGroup object to which the query is passed as a condition. Alternatively, it is possible to group multiple conditions in an andConditionGroup as a test.

These are only two of a longer list of methods provided by the QueryInterface class that can extend the query. For example, it's possible to make this a count query with QueryInterface::count and to create sortable tables for this query with QueryInterface::tableSort.

Querying for Revisions

By default, the entity query will only return the most recent revision for each entity. You can obtain the revisions by using allRevisions().

$query->allRevisions();

Next: Loading entities >

Creative Commons License This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

Contact supportStill need assistance? Contact Acquia Support