How to use Entity Metadata Wrappers with Drupal 7
Using the Entity API in Drupal 7 is a powerful way to access fields and properties.
It has long been a pain point of mine to see pieces of code like this sprinkled over the code base:
$showid = $node->field_seriesid[LANGUAGE_NONE][0]['value']
Not only does this hard code the language into the field value lookup, it also throws PHP warnings when the field has no data (due to the array keys not being set).
One of the projects we are currently working on is fully multilingual, using a combination of i18n (translation using separate nodes for each translation) and entity_translation (translation using one node, with field translation). It became apparent that a better solution was required here.
Entity metadata wrappers to the rescue
This wrapping class is provided by the Entity API module, which I would highly recommend you run (more than likely you already are as it is required by some other modules).
How to use the API
// use entity metadata wrappers as they are SMART
$wrapper = entity_metadata_wrapper('node', $node);
dsm($wrapper->getPropertyInfo());
This will print out a list of all known fields on the node, and you can access properties easily. Once you have the $wrapper object defined you will now be able to use the below advanced syntax for querying values of fields.
Retrieving an integer value of a field
To retrieve the raw value from a field you can use the raw() accessor method, this will perform no additional logic other than returning the current value. It is useful for integer fields etc.
Old approach
$showid = $node->field_seriesid[LANGUAGE_NONE][0]['value'];
Entity metadata wrapper approach
$showid = $wrapper->field_seriesid->raw();
Retrieving taxonomy term name in a single-select taxonomy
To load entities nested within entities you can use the value() accessor method. This comes in very handy for taxonomy terms, users, files etc.
Old approach
// Extract Te Reo level
$level = $show->field_te_reo_level;
$tid = $level[LANGUAGE_NONE][0]['tid'];
$term = taxonomy_term_load($tid);
$variables['level'] = $term->name;
Entity metadata wrapper approach
$variables['level'] = $wrapper->field_te_reo_level->value()->name;
Retrieving taxonomy term names in a multi-select taxonomy
What if we needed to loop around a unlimited multi-select list of terms. The code is simple to adapt from above.
Old approach
// add the items from the 'show_features' taxonomy
$show_features = array();
$features = $series->field_features;
if (is_array($features[LANGUAGE_NONE])) {
foreach($features[LANGUAGE_NONE] as $tids) {
$tid = $tids['tid'];
$term = taxonomy_term_load($tid);
$featureList[] = $term->name;
}
}
Entity metadata wrapper approach
// add the items from the 'show_features' taxonomy
$show_features = array();
foreach ($show_wrapper->field_features->value() as $index => $feature) {
$show_features[] = $feature->name;
}
In this example you really see a glimpse of the power of entity metadata wrappers, here they have automatically loaded the taxonomy term entities that were contained inside the main $node
entity, and now we can loop directly around the loaded terms. This saves a lot of code and makes it more readable.
Language specific fields
Entity metadata wrappers have native support for accessing the value of language specific fields (e.g. when using field translations),
Entity metadata wrapper approach
global $language;
// get the localised title and body (hence the language param)
$title = $wrapper->language($language->language)->title_field->raw();
$body = $wrapper->language($language->language)->body->value->value(array('sanitize' => TRUE));
Why use entity metadata wrappers?
- Makes your code more readable
- Provides a standardised way of accessing field values and entities through an API
- Stopped you hard coding the language key into the array lookups
- Stops those nasty PHP warnings when you are trying to access properties that do not exist
- The wrapper autoloads entities (when used in conjunction with the ->value() accessor), which allowing you to chain the callbacks
Further reading
I would recommend watching fago's Drupalcon Denver talk on entities as it contains a lot of information on this topic.
Your thoughts
How have you found entity metadata wrappers? Leave a comment if you have found this article helpful or you have some other useful advice.