February 2012

EntityFieldQuery: Let Drupal Do The Heavy Lifting (Pt 1)

Drupal 7 introduced the EntityFieldQuery API. This class is a mechanism for quickly building queries of entities and fields - typically nodes, but of course not limited to that.

Drupal 7 features a much richer database abstraction layer than previous versions of Drupal, but in the end you are still more or less building SQL. EntityFieldQuery allows you to construct queries without much knowledge of SQL at all.

Drupal core itself mostly uses EntityFieldQuery as a utility function, in many cases simply to check that a given field has a value somewhere in the system or not. It’s strange that such a powerful mechanism is put to so little use by core, but no matter. Let’s see how we can use it.

Starting Your Query

Starting an entity field query looks like this:

$query = new EntityFieldQuery();

Extremely simple, right? That's all it takes to get started. Let's now add some conditions to our query.

$query
 ->entityCondition('entity_type', 'node')
 ->entityCondition('bundle', 'article')
 ->propertyCondition('status', 1)
 ->propertyOrderBy('created', 'DESC');

Let's take a look at what's going on here. First of all, notice the lack of semicolons between method calls. Each EntityFieldQuery method returns the same EntityFieldQuery object the method is called on. This allows us to chain method calls together, which speeds up coding and makes it easier to read. This will look familiar to anyone who uses jQuery. This could just as easily be written like so:

$query->entityCondition('entity_type', 'node')->entityCondition('bundle', 'article')->propertyCondition('status', 1)->propertyOrderBy('created', 'DESC');

But, that is really not easy at all to read. I recommend putting each method on its own line. Future generations of coders will thank you.

Now let's look at each method and see what's happening.

->entityCondition('entity_type', 'node')

The first method uses an entityCondition to tell the query to look for node entities. It may seem like specifying this is redundant, but as many other things in Drupal 7 are also entities - users, taxonomy terms, etc - you need to restrict your set.

->entityCondition('bundle', 'article')

The second method tells the query which node types to restrict the set to. This can be left out if you would like to query all available nodes, but in most cases you will be looking for specific node types. Note also that the second argument, 'article' in this case, can be either a string or an array; the query will adjust automatically. So if you were looking for both article and page node types, you could rewrite that part of the chain as follows:

->entityCondition('bundle', array('article', 'page'))

As you can see, it's extremely easy to expand your query.

->propertyCondition('status', 1)

The third method is a propertyCondition. A property in this case is any column in the base table for the given entity type. In the case of nodes, this could be whether it is published, the user that created the node, time of creation, etc. In our example above, we are modifying our query to only return published values.

->propertyOrderBy('created', 'DESC')

The last method in our example above uses propertyOrderBy to set an order. In this case, we're simply asking for the results to be returned in reverse chronological order.

Querying Fields and Limiting

Now let's add a query on a field value using a fieldCondition. Let's assume each of the node types in our example has a field 'field_us_state' assigned to it. We're going to find nodes that are associated with the New York Tri-state area, which also includes Connecticut and New Jersey. This would look like this:

$query->fieldCondition('field_us_state', 'value', array('CT', 'NJ', 'NY'));

We can order by field values as well, if that is useful to us. Note that ordering conditions are processed in the order that they are added to the query.

Perhaps for our purposes, we want to limit our query to the 10 most recent items. Let’s add a range:

$query->range(0,10);

Et Voilà

Finally, we execute the query and assign that to a variable:

$result = $query->execute();

This returns us an array of entity ids that match the conditions specified for the query. If we are querying nodes, the information will be under $result['node']. In most cases, what you actually want are the nids that have been returned. This is easily accomplished:

$nids = array_keys($result['node']);

Putting that all together, we have:

$query = new EntityFieldQuery();
$query
  ->entityCondition('entity_type', 'node')
  ->entityCondition('bundle', 'article')
  ->propertyCondition('status', 1)
  ->propertyOrderBy('created', 'DESC')
  ->fieldCondition('field_us_state', 'value', array('CT', 'NJ', 'NY'))
  ->range(0,10);
$result = $query->execute();
$nids = array_keys($result['node']);

This is not very much code at all for this result. Moreover, we don’t need to know anything about SQL or even about the underlying storage engine being used. We simply write the query in this simple syntax, and EntityFieldQuery API does the job of translating that into a query that Drupal’s database abstraction layer understands and executes it for us.

What would we do with this list of nids? Pretty much anything. We might load them, for starters:

$nodes = node_load_multiple($nids);

We might want to display these 10 nodes in a teaser style. That’s also easily done. Let’s generate a Drupal render array:

$output = node_view_multiple($nodes);

More To Come

This is just the beginning. Look for part 2 of this post, where we will show more concrete examples of putting EntityFieldQuery to use. Also look out for posts from other Treehouse engineers explaining more advanced topics related to EntityFieldQuery.

Comments

Is it me, or will the trailing semicolon in the broken-out code bits kill it:
$query->entityCondition('bundle', array('article', 'page'));

Might wanna fix that.

AaronELBorg, thanks for calling attention to that. It's a tricky line, trying to explain a chained piece of code segment by segment. In this case, the bit of code you're drawing attention to:

$query->entityCondition('bundle', array('article', 'page'));

should be more viewed as an aside. If you were to literally insert that code into the chain, the semicolon would be a problem, but the variable $query containing the EntityFieldQuery object being in-line there would create a greater problem.

I agree, it is a bit confusing if you're trying to construct the chain literally from the segments as they are explained.

Again, thanks for pointing that out; the post has been edited a bit for clarity.

0 down vote favorite
share [g+] share [fb] share [tw]

$query->join('field_data_field_amountpaid', 'amt', 'n.nid = amt.entity_id and amt.field_amountpaid_value >=500 and amt.field_amountpaid_value <=5000 '); //JOIN node with Body

this is my normal query how can i call the in the enttiy query

i try this way

$query->fieldCondition('field_amountpaid', 'value', array('501','5000'),'BETWEEN');

but it's not working. any idea.

0 down vote favorite
share [g+] share [fb] share [tw]

$query->join('field_data_field_amountpaid', 'amt', 'n.nid = amt.entity_id and amt.field_amountpaid_value >=500 and amt.field_amountpaid_value <=5000 '); //JOIN node with Body

this is my normal query how can i call the in the enttiy query

i try this way

$query->fieldCondition('field_amountpaid', 'value', array('501','5000'),'BETWEEN');

but it's not working. any idea.

In the example given above, sorting was done by a field in the base table (i.e. node). If you want to sort by an entity field, the corresponding sort method is

fieldOrderBy($field, $column, $direction = 'ASC')

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <hr> <blockquote> <h3> <h4> <h5> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • You can enable syntax highlighting of source code with the following tags: <pre>, <c>, <cpp>, <drupal5>, <drupal6>, <java>, <javascript>, <php>, <python>, <ruby>. The supported tag styles are: <foo>, [foo].

More information about formatting options

By submitting this form, you accept the Mollom privacy policy.
Stay Informed

Sign up now for the Treehouse Newsletter.