A New Entity Property API for Drupal 8
Why?
While the conversion to full CRUD for entities and classed objects for Drupal 8 made good progress, we’ve not yet reached the goals of fully translatable entities and having a default entity serialization for import/export, content staging and web services. For those points, we need to know what’s in an entity! Yes, we can look up the fields, but there are also base entity properties and further stuff modules put on entities, which both are no fields so we do not know anything about them. That is what the new Entity Property API is supposed to change: It’s about providing a unified interface to entity properties *and* fields, avoiding the split between fields and non-field properties. So fields will be entity properties working with the same API as well! Then, it’s about being able to introspect what’s going to be in an entity - regardless of whether it has been added by a module or by the user via field UI. But furthermore, with classed entity objects as the basis we can improve the developer facing API and make it easier to access property and field values (I’m looking at you, $entity->field_body[LANGUAGE_NONE][0][‘value’]).
What?
As we’ve outlined in the WSCCI Web Services Format Sprint report we want to have a modern OOP, interface based API for properties. The API should allow for introspection, so that it’s possible to look up the defined properties of an entity type in advance. If you know the Entity property information system of the Drupal 7 Entity module, it’s a bit similar to that, but instead of adding an extra layer above the existing entities, it’s about supporting it natively. So there will be no need for entity wrappers - all the easy API and information will be directly available in $entity. See the Entity Property API meta issue for a more complete list of planned features.
The current state
Work on that is currently done in a sandbox, where we’ll flush out the API with a test entity type. Once this works out, the plan is to convert the first entity type and post a patch for further review to the core queue (here). So let me shortly explain the overall architecture of what we currently have or plan for: The idea is that *every* entity has to follow the following data model:
Thus, an entity consists of multiple entity properties, which consist of one or more property items (just as field API $items), which each have one or more values (just as field API’s columns). You may notice that no language is in there - the idea is that this all just works with a reasonable language default, while it’s possible to get properties in a certain language by specifying an optional language parameter in the property getter. In order to ease access to the properties (in default language) we plan to implement magic getters, so that e.g. the node’s image alt text could be accessed like that:
echo $node->field_image[0]->alt;
As all entity properties have to follow the structure, it works the same way for others like the node title:
echo $node->title[0]->value;
$node->title[0]->value = 'updated title';
However, we actually know there can be only one title yes? So you can also do:
echo $node->title->value;
$node->title->value = 'updated title';
If the array access is omitted, it will just default to the first property item. That makes it easier to deal with single-valued properties, while it makes sure the code does not break if a single-valued field gets changed to be multi-valued later on (or vice versa). Next, dealing with entity references should become easier as well, such that the system cares about loading referenced entities for you. E.g. to access the node author’s user name could work like that:
echo $node->user->entity->name->value;
For that, all to work the system maintains so-called “property definitions", which are a bit similar to $field and $instance for fields but are there for all properties. The system defines methods to look them up:
foreach ($entity->getPropertyDefinitions() as $name => $definition) {
echo "Property label: {$definition['label']}";
echo "Property type: {$definition['type']}";
}
It will be possible to look up those definitions up front, i.e. without having a concrete $entity with data. So you can use it to generate UI. Of course, there will be some more keys in the entity property definitions and we’ll add more keys on the way as necessary. Then the idea is to use the same API for other levels in the entity as well:
foreach ($propertyitem->getPropertyDefinitions() as $name => $definition) {
echo "Property label: {$definition['label']}";
echo "Property type: {$definition['type']}";
}
That’s roughly where we are so far - of course, some things will be adapted and changed on the way. There is some prototype code in the sandbox, but nothing is ready yet. If you’d like to get involved, contact me and/or dive into the sandbox’s issue queue. If you are Drupalcon, don’t miss the Entity Property API core conversation and join the entity API sprints!
The time is running...
Yes, Drupal 8 feature freeze is not far away (December), so the time is running out. Unfortunately, recently I’ve not been able to invest enough time into this all to move on as quickly as it’s needed now, so thankfully Acquia is helping out and funding some of my development on this. This will speed up things now, so expect a patch ready to review before Drupalcon :-)