Developing with Entity Metadata Wrappers

Exclusive offer: get 50% off this eBook here
Programming Drupal 7 Entities

Programming Drupal 7 Entities — Save 50%

Expose local or remote data as Drupal 7 entities and build custom solutions with this book and ebook

$18.99    $9.50
by Sammy Spets | August 2013 | Open Source

This article created by Sammy Spets, author of the Programming Drupal 7 Entities,covers the following topics:

  • What entity metadata wrappers are
  • Instantiate an entity metadata wrapper for an entity
  • CRUD an entity
  • Entity introspection

(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:


Programming Drupal 7 Entities Expose local or remote data as Drupal 7 entities and build custom solutions with this book and ebook
Published: June 2013
eBook Price: $18.99
Book Price: $34.99
See more
Select your format and quantity:

About the Author :


Sammy Spets

Since 2004, Sammy Spets has been finding pleasure in his life making Drupal do wild things. During that time, Sammy volunteered to be a core maintainer for Drupal 6 and a maintainer of the ecommerce module, which was the commerce module of choice way back when. For the ecommerce module, Sammy made design changes to the payment system, built a few modules to support payment gateways, and added PostgreSQL support, among other things.

In 2008, IDG Australia contracted Sammy to design and lead the development of a hybrid Drupal/legacy platform. The platform allowed IDG developers to gradually migrate their websites and web applications over to Drupal 6, which was still in beta. In addition to the platform, Sammy was tasked with creating a module suite for the IDG staff to create surveys and reports on them. This module suite was built prior to webform, and leveraged the power of the Drupal 6 Form API in all its glory. Sammy also trained IDG developers to develop modules and themes in Drupal 6.

Early in 2009, a short contract with Demonz Media in Sydney, Australia brought about some patches to Ubercart, which Demonz gladly contributed back to the community.

Following that, Sammy travelled to Louisville, Kentucky, USA where he contributed code to improve the developer experience for developers extending Ubercart by using its API. Ryan Szrama introduced Sammy to Chick-fil-A and Lyle Mantooth introduced Sammy to Korean food and some amazing fried chicken.

In 2011, Sammy joined the Magicspark team, building Drupal sites and maintaining servers. During this time, Sammy built a services platform to feed webform data to Marketo and LoopFuse from client Drupal sites via Magicspark's servers. In addition to this, Sammy redeveloped the UI on the Where to Buy page of the Redwood Systems website using OpenLayers mapping.

Aside from the geeky stuff, Sammy loves to cook, fine-tune recipes, play pool, carve turns on a snowboard, hit the gym, ride motorcycles, dine fine, and drink champagne.

Programming Drupal 7 Entities, Packt Publishing, is the first book Sammy has authored. Sammy was the technical reviewer for Migrating to Drupal 7, Packt Publishing.

Sammy can be contacted by e-mail at sammys@sammyspets.com.

Books From Packt


Drupal 7 Multilingual Sites
Drupal 7 Multilingual Sites

Drupal 7 Multi Sites Configuration
Drupal 7 Multi Sites Configuration

Migrating to Drupal 7
Migrating to Drupal 7

Drupal Rules How-to [Instant]
Drupal Rules How-to [Instant]

Drupal 6 Themes
Drupal 6 Themes

Drupal 7 Cookbook
Drupal 7 Cookbook

Drupal 7 Mobile Web Development Beginner’s Guide
Drupal 7 Mobile Web Development Beginner’s Guide

Drupal 7 Module Development
Drupal 7 Module Development


Your rating: None Average: 1.3 (3 votes)

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
f
c
2
g
H
v
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software