The Drupal 8 version of EntityFieldQuery

Share this article

Even though Drupal 7 core fell short of a proper way of handling its brand new entity system (we currently rely on the great Entity module for that), it did give us EntityFieldQuery. For those of you who don’t know, EntityFieldQuery is a very powerful querying class used to search Drupal entities programatically (nodes, users, etc).

It provides a number of methods that make it easy to query entities based on conditions such as field values or class properties. If you don’t know how it works, feel free to check out this documentation page or this great tutorial on the subject.

In this article I am going to talk about what we have in Drupal 8 for querying entities. There is no more EntityFieldQuery, but there’s an entity.query service that will instantiate a query object for a given entity type (and that implements the \Drupal\Core\Entity\Query\QueryInterface). We can access this service statically through the \Drupal namespace or using dependency injection.

First up, we’ll look at querying node entities and then we’ll see how to load them. The same techniques will work with other content entities as well (users, comments etc), but also with configuration entities, and that’s really cool.

The entity query service

As mentioned, there are two ways we can access the entity.query service that we use for querying entities. Statically, we can do this:

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

Instead of node, we can specify any other entity type machine name and what we get inside the $query variable is the query object for our entity type. The entityQuery() static method on the \Drupal namespace is a shortcut for doing so using the entity.query service.

Alternatively (and the highly recommended approach) is to use dependency injection.

If you have access to the container, you can load the service from there and then get the right query object:

$entity_query_service = $container->get('entity.query');
$query = $entity_query_service->get('node');

As you can see, we use the get() method on the entity_query service to instantiate a query object for the entity type with the machine name passed as a parameter.

Querying entities

Let’s illustrate a couple of examples of querying for node entities using this object.

A very simple query that returns the published nodes:

$query = \Drupal::entityQuery('node')
    ->condition('status', 1);
    
$nids = $query->execute();

$nids will be an array of entity ids (in our case node ids) keyed by the revision ids (if there is revisioning enabled for the entity type) or the entity ids if not. Let’s see an example in which we add more property conditions as well as field conditions:

$query = \Drupal::entityQuery('node')
    ->condition('status', 1)
    ->condition('changed', REQUEST_TIME, '<')
    ->condition('title', 'cat', 'CONTAINS')
    ->condition('field_tags.entity.name', 'cats');

$nids = $query->execute();

In this query, we retrieve the node ids of all the published nodes that have been last updated before the current time, that have the word cat inside their title and that have a taxonomy term called cats as a reference in the field_tags.

As you can see, there is no more distinction between propertyCondition and fieldCondition (as there is in D7 with EntityFieldQuery). Additionally, we can include conditions based on referenced entities tacking on the entity.(column) to the entity reference field name.

An important thing to note is that we also have the langcode parameter in the condition() method by which we can specify what translation of the node should be included in the query. For instance, we can retrieve node IDs that contain a specific value inside of a field in one language but another value inside the same field for another language.

For more information on the condition() method you should consult the API documentation.

The next thing we are going to look at is using condition groups (both AND and OR) for more powerful queries:

$query = \Drupal::entityQuery('node')
    ->condition('status', 1)
    ->condition('changed', REQUEST_TIME, '<');

$group = $query->orConditionGroup()
    ->condition('title', 'cat', 'CONTAINS')
    ->condition('field_tags.entity.name', 'cats');

$nids = $query->condition($group)->execute();

Above, we altered our previous query so as to retrieve nodes that either have the cat string in their title or have a reference to the term called cats in their field_tags field. And we did so by creating an orConditionGroup object that we then pass to the query as a condition. And we can group together multiple conditions within a andConditionGroup as well.

There are many other methods on the QueryInterface that can extend the query (such as for sorting, range, etc). I encourage you to check them out in the documentation and experiment with them. For now, though, let’s take a quick look at what to do with the result set.

Loading entities

As I mentioned above, the execute() method on the query object we’ve been working with returns an array of entity IDs. Supposedly we now have to load those entity objects and work with them. How do we do that?

In Drupal 7 we had the entity_load() function to which we passed an array of IDs and that would return an array of objects. In Drupal 8, this helper function is maintained and you can use it pretty much in the same way, except only for one entity at a time:

$node = entity_load('node', $nids[1]);

And the return value is a node object. To load multiple nodes, you can use the entity_load_multiple() function:

$nodes = entity_load_multiple('node', $nids);

Which then returns an array of entity objects keyed by their ids.

A bonus nugget of information is that both of these functions are wrappers for the storage manager of the entities in question. They basically retrieve the storage manager statically and then call the load() and loadMultiple() methods, respectively, on it:

Statically, you could do similarly:

$node_storage = \Drupal::entityManager()->getStorage('node');

// Load multiple nodes
$node_storage->loadMultiple($ids);
// Load a single node
$node_storage->load($id);

But better yet, you could use dependency injection and retrieve the storage class from the container:

$node_storage = $container->get('entity.manager')->getStorage('node');

And then proceed with the loading. Using dependency injection is usually the recommended way to go when it’s possible, i.e. when working within a class. This makes it easier to test your class and better decouples it from the rest of the application.

Conclusion

In this article we’ve seen how to work with querying and loading entities in Drupal 8. There has been an overhaul of the D7 EntityFieldQuery class that turned into a robust API for querying both content and configuration entities. We’ve looked at querying content entities but the system works just the same with config entities. And that is a bit of a win for the new Drupal 8 entity system.

We’ve also seen how to load entities based on the IDs resulted in these queries and what is actually behind the wrapper functions that perform these operations. Next up, we are going to look at defining our own content entity type in Drupal 8. For a refresher on how we do it in Drupal 7, you can check out these Sitepoint articles on the subject.

Frequently Asked Questions (FAQs) about Drupal 8 Version of EntityFieldQuery

What is the main difference between EntityFieldQuery in Drupal 7 and Drupal 8?

The main difference between EntityFieldQuery in Drupal 7 and Drupal 8 is the introduction of the Entity Query API in Drupal 8. This new API provides a more streamlined and efficient way to query data from the database. It uses a more object-oriented approach, allowing for more complex queries to be built using methods and properties of the query object. This is a significant improvement over the procedural approach used in Drupal 7.

How can I use Entity Query API in Drupal 8?

To use the Entity Query API in Drupal 8, you first need to get an instance of the query object. This can be done using the \Drupal::entityQuery() method. Once you have the query object, you can use its methods to build your query. For example, you can use the condition() method to add conditions to your query, and the execute() method to run the query and get the results.

Can I use EntityFieldQuery to query custom entities in Drupal 8?

Yes, you can use EntityFieldQuery to query custom entities in Drupal 8. The Entity Query API in Drupal 8 is designed to work with any entity type, including custom entities. You just need to specify the entity type in the entityQuery() method.

How can I sort the results of an EntityFieldQuery in Drupal 8?

To sort the results of an EntityFieldQuery in Drupal 8, you can use the sort() method of the query object. This method takes two parameters: the field to sort by, and the direction of the sort (either ‘ASC’ for ascending order, or ‘DESC’ for descending order).

Can I use EntityFieldQuery to query fields in Drupal 8?

Yes, you can use EntityFieldQuery to query fields in Drupal 8. The Entity Query API in Drupal 8 allows you to query any field of an entity, including custom fields. You just need to specify the field name in the condition() method of the query object.

How can I limit the number of results returned by an EntityFieldQuery in Drupal 8?

To limit the number of results returned by an EntityFieldQuery in Drupal 8, you can use the range() method of the query object. This method takes two parameters: the offset of the first result, and the maximum number of results to return.

Can I use EntityFieldQuery to query multiple entity types in Drupal 8?

No, you cannot use EntityFieldQuery to query multiple entity types in Drupal 8. The Entity Query API in Drupal 8 only allows you to query one entity type at a time. If you need to query multiple entity types, you will need to run multiple queries.

How can I use EntityFieldQuery to query entities based on their status in Drupal 8?

To query entities based on their status in Drupal 8, you can use the condition() method of the query object. This method allows you to add a condition to the query based on the status field of the entity.

Can I use EntityFieldQuery to query entities based on their creation date in Drupal 8?

Yes, you can use EntityFieldQuery to query entities based on their creation date in Drupal 8. The Entity Query API in Drupal 8 allows you to query any field of an entity, including the creation date. You just need to specify the creation date field in the condition() method of the query object.

How can I use EntityFieldQuery to query entities based on their author in Drupal 8?

To query entities based on their author in Drupal 8, you can use the condition() method of the query object. This method allows you to add a condition to the query based on the author field of the entity.

Daniel SiposDaniel Sipos
View Author

Daniel Sipos is a Drupal developer who lives in Brussels, Belgium. He works professionally with Drupal but likes to use other PHP frameworks and technologies as well. He runs webomelette.com, a Drupal blog where he writes articles and tutorials about Drupal development, theming and site building.

didrupaldrupal 8drupal-7drupal-planetentityentityfieldqueryentityqueryOOPHPPHP
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week