Entity API Implements API Typed Data
Significant Improvement
- The Entity API now implements the Typed Data API
In this new implementation, the Entity API treats everything as a field based on the same API, making entities predictable and consistent.
Understanding the Drupal Data Model
Before diving into the Typed Data API itself, it's important to understand how Drupal's data model (Entity API) was perceived previously. This is essential because it provides the foundation from which the Typed Data API emerged, and the Entity API is one of the systems for which it was designed.
An entity is a complex data structure consisting of other pieces of data, such as fields with lists of items. A field item is also complex—it contains additional data pieces like a text value and a format. This complexity continues down to primitive data types such as strings or integers.
A simplified example from Drupal 7 (omitting language keys for simplicity, as Drupal 8 handles them differently):
Example 1
// Entities are complex, they contain other pieces of data. $entity; // Fields are not complex, they only contain a list of items. $entity->image; // Items are complex, they contain other pieces of data. $entity->image[0]; // The file ID is a primitive integer. $entity->image[0]['fid']; // The alternative text is a primitive string. $entity->image[0]['alt'];
Putting It All Together
Below is a simplified example showing how the Entity API implements interfaces beyond the Typed Data API. In practice, the Entity API extends these interfaces with additional methods it needs. Still, the following statements all evaluate to true:
Example 2
// Entities are complex. $entity instanceof ComplexDataInterface; // Properties are lists of items. $entity->get('image') instanceof ListInterface; // Items are complex. $entity->get('image')->offsetGet(0) instanceof ComplexDataInterface; // The alt value is a typed data object. $entity->get('image')->offsetGet(0)->get('alt') instanceof TypedDataInterface; // The alt value is a primitive string. is_string($entity->get('image')->offsetGet(0)->get('alt')->getValue());
Here's a summary of how the Entity API extends Typed Data to address additional needs:
Example 3
interface EntityInterface extends ComplexDataInterface, TranslatableInterface, AccessibleInterface { // ... } interface FieldItemListInterface extends ListInterface { // ... } // Note: This interface extends two interfaces. interface FieldItemInterface extends ComplexDataInterface, TypedDataInterface { // ... } // Some implementations: class ImageItem extends FieldItemBase { // ... } class String extends TypedData { // ... }
Note: The next two paragraphs still need further explanation.
Two key observations:
1. EntityInterface
extends utility interfaces for translation and access control.
2. FieldItemInterface
extends both ComplexDataInterface
and TypedDataInterface
. This is because a field item is both a complex structure (e.g., with a value and format) and a piece of typed data itself, with its own definition and data type.
To summarize, in addition to Example 2, the following also evaluate as true:
Example 4
$entity instanceof EntityInterface; $entity->get('image') instanceof FieldItemListInterface; $entity->get('image')->offsetGet(0) instanceof FieldItemInterface; $entity->get('image')->offsetGet(0)->get('alt') instanceof String; is_string($entity->get('image')->offsetGet(0)->get('alt')->getValue());
Using the API
More examples needed here.
The Entity API defines magic methods like __get()
for quick and easy access to field values. This makes the syntax simple and familiar for developers coming from pre-Drupal 8 versions.
Extracting the actual value of an image's alt text can be done as shown below:
Example 5
// Most verbose: $string = $entity->get('image')->offsetGet(0)->get('alt')->getValue(); // With Entity API magic: $string = $entity->image[0]->alt; // Even simpler (defaulting to first item): $string = $entity->image->alt;
The above just improves syntax. The real value of this API shines in scenarios like data validation:
Example 6
// All field definitions. $property_definitions = $entity->getFieldDefinitions(); // All property definitions for the image field. $property_definitions = $entity->image ->getFieldDefinition() ->getFieldStorageDefinition() ->getPropertyDefinitions(); // Definition for the 'alt' property. $string_definition = $entity->image ->getFieldDefinition() ->getFieldStorageDefinition() ->getPropertyDefinition('alt');
These definitions allow us to do smart things like serialization or exposing data through semantically rich APIs such as a JSON-LD endpoint, so that other systems can understand the data structure.
See https://drupal.org/node/2078241 for more on defining and using entity field type definitions.
Drupal’s online documentation is © 2000-2020 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License.