8 min read

(For more resources related to this topic, see here.)

Introducing entity metadata wrappers

Entity metadata wrappers, or wrappers for brevity, are PHP wrapper classes for simplifying code that deals with entities. They abstract structure so that a developer can write code in a generic way when accessing entities and their properties. Wrappers also implement PHP iterator interfaces, making it easy to loop through all properties of an entity or all values of a multiple value property.

The magic of wrappers is in their use of the following three classes:

  • EntityStructureWrapper
  • EntityListWrapper
  • EntityValueWrapper

The first has a subclass, EntityDrupalWrapper, and is the entity structure object that you’ll deal with the most. Entity property values are either data, an array of values, or an array of entities. The EntityListWrapper class wraps an array of values or entities. As a result, generic code must inspect the value type before doing anything with a value, in order to prevent exceptions from being thrown.

Creating an entity metadata wrapper object

Let’s take a look at two hypothetical entities that expose data from the following two database tables:

  • ingredient
  • recipe_ingredient

The ingredient table has two fields: iid and name. The recipe_ingredient table has four fields: riid, iid , qty , and qty_unit. The schema would be as follows:

Schema for ingredient and recipe_ingredient tables

To load and wrap an ingredient entity with an iid of 1 and, we would use the following line of code:

$wrapper = entity_metadata_wrapper('ingredient', 1);

To load and wrap a recipe_ingredient entity with an riid of 1, we would use this line of code:

$wrapper = entity_metadata_wrapper('recipe_ingredient', 1);

Now that we have a wrapper, we can access the standard entity properties.

Standard entity properties

The first argument of the entity_metadata_wrapper function is the entity type, and the second argument is the entity identifier, which is the value of the entity’s identifying property. Note, that it is not necessary to supply the bundle, as identifiers are properties of the entity type.

When an entity is exposed to Drupal, the developer selects one of the database fields to be the entity’s identifying property and another field to be the entity’s label property. In our previous hypothetical example, a developer would declare iid as the identifying property and name as the label property of the ingredient entity. These two abstract properties, combined with the type property, are essential for making our code apply to multiple data structures that have different identifier fields.

Notice how the phrase “type property” does not format the word “property”? That is not a typographical error. It is indicating to you that type is in fact the name of the property storing the entity’s type. The other two, identifying property and label property are metadata in the entity declaration. The metadata is used by code to get the correct name for the properties on each entity in which the identifier and label are stored. To illustrate this, consider the following code snippet:

$info = entity_get_info($entity_type);
$key = isset($info['entity keys']['name'])
? $info['entity keys']['name'] : $info['entity keys']['id'];
return isset($entity->$key) ? $entity->$key : NULL;

Shown here is a snippet of the entity_id() function in the entity module. As you can see, the entity information is retrieved at the first highlight, then the identifying property name is retrieved from that information at the second highlight. That name is then used to retrieve the identifier from the entity.

Note that it’s possible to use a non-integer identifier, so remember to take that into account for any generic code.

The label property can either be a database field name or a hook. The entity exposing developer can declare a hook that generates a label for their entity when the label is more complicated, such as what we would need for recipe_ingredient. For that, we would need to combine the qty, qty_unit, and the name properties of the referenced ingredient.

Entity introspection

In order to see the properties that an entity has, you can call the getPropertyInfo() method on the entity wrapper. This may save you time when debugging. You can have a look by sending it to devel module’s dpm() function or var_dump:

dpm($wrapper->getPropertyInfo());
var_dump($wrapper->getPropertyInfo());

Using an entity metadata wrapper

The standard operations for entities are CRUD: create, retrieve, update, and delete. Let’s look at each of these operations in some example code. The code is part of the pde module’s Drush file: sites/all/modules/pde/pde.drush.inc.

Each CRUD operation is implemented in a Drush command, and the relevant code is given in the following subsections. Before each code example, there are two example command lines. The first shows you how to execute the Drush command for the operation. ; the second is the help command.

Create

Creation of entities is implemented in the drush_pde_entity_create function.

Drush commands

The following examples show the usage of the entity-create ( ec) Drush command and how to obtain help documentation for the command:

$ drush ec ingredient '{"name": "Salt, pickling"}'
$ drush help ec

Code snippet

$entity = entity_create($type, $data);
// Can call $entity->save() here or wrap to play and save
$wrapper = entity_metadata_wrapper($type, $entity);
$wrapper->save();

In the highlighted lines we create an entity, wrap it, and then save it. The first line uses entity_create, to which we pass the entity type and an associative array having property names as keys and their values. The function returns an object that has Entity as its base class. The save() method does all the hard work of storing our entity in the database. No more calls to db_insert are needed!

Whether you use the save() method on the wrapper or on the Entity object really depends on what you need to do before and after the save() method call. For example, if you need to plug values into fields before you save the entity, it’s handy to use a wrapper.

Retrieve

The retrieving (reading) of entities is implemented in the drush_pde_print_entity() function.

Drush commands

The following examples show the usage of the entity-read (er) Drush command and how to obtain help documentation for the command.

$ drush er ingredient 1
$ drush help er

Code snippet

$header = ' Entity (' . $wrapper->type();
$header .= ') - ID# '. $wrapper->getIdentifier().':';
// equivalents: $wrapper->value()->entityType()
// $wrapper->value()->identifier()
$rows = array();
foreach ($wrapper as $pkey => $property) {
// $wrapper->$pkey === $property
if (!($property instanceof EntityValueWrapper)) {
$rows[$pkey] = $property->raw()

. ' (' . $property->label() . ')';
}
else {
$rows[$pkey] = $property->value();
}
}

On the first highlighted line, we call the type() method of the wrapper, which returns the wrapped entity’s type. The wrapped Entity object is returned by the value() method of the wrapper. Using wrappers gives us the wrapper benefits, and we can use the entity object directly!

The second highlighted line calls the getIdentifier() method of the wrapper. This is the way in which you retrieve the entity’s ID without knowing the identifying property name. We’ll discuss more about the identifying property of an entity in a moment.

Thanks to our wrapper object implementing the IteratorAggregate interface , we are able to use a foreach statement to iterate through all of the entity properties. Of course, it is also possible to access a single property by using its key. For example, to access the name property of our hypothetical ingredient entity, we would use $wrapper->name.

The last three highlights are the raw(), label(), and value() method calls. The distinction between these is very important, and is as follows:

  • raw(): This returns the property’s value straight from the database.
  • label(): This returns value of an entity’s label property. For example, name.
  • value(): This returns a property’s wrapped data: either a value or another wrapper.

Finally, the highlighted raw() and value() methods retrieve the property values for us. These methods are interchangeable when simple entities are used, as there’s no difference between the storage value and property value. However, for complex properties such as dates, there is a difference. Therefore, as a rule of thumb, always use the value() method unless you absolutely need to retrieve the storage value. The example code is using the raw() method only so we that can explore it, and all remaining examples in this book will stick to the rule of thumb. I promise!

  • Storage value: This is the value of a property in the underlying storage media. for example, database.
  • Property value: This is the value of a property at the entity level after the value is converted from its storage value to something more pleasing. For example, date formatting of a Unix timestamp.

Multi-valued properties need a quick mention here. Reading these is quite straightforward, as they are accessible as an array. You can use Array notation to get an element, and use a foreach to loop through them! The following is a hypothetical code snippet to illustrate this:

$output = 'First property: ';
$output .= $wrapper->property[0]->value();
foreach ($wrapper->property as $vwrapper) {
$output .= $vwrapper->value();
}

Summary

This article delved into development using entity metadata wrappers for safe CRUD operations and entity introspection.

Resources for Article:


Further resources on this subject:


LEAVE A REPLY

Please enter your comment!
Please enter your name here