Introduction Entity API in Drupal
The Drupal 8 Entity System
Entities are typed classes with methods.
Generic methods |
$entity->id() |
Entity type specific methods | $node->getTitle() |
Background
The Entity System was introduced late in the Drupal 7 development cycle with basic standards for loading entities. The added entity.module further expanded the API by adding support for saving and deleting entities, and many other enhancements.
Most of these improvements are now built into Drupal 8. Entity validation is now handled by its own API (which can validate an entity saved via REST instead of a form, for example).
Two Variants
Entity types in core come in two variants:
Configuration Entity
Uses the Configuration System. Supports translation and can provide default user settings for installs. Configuration entities are stored in the shared configuration database table as strings.
Content Entity
Consists of configurable and base fields, can have revisions, and supports translations. Content entities are stored in custom database tables as rows. The table name matches the entity "id," and the columns are defined via the entity’s “baseFieldDefinitions” method.
Bundles
Bundles are different variants of an entity type. For example, for the node entity type, bundles are different node types like "article" and "page".
Typically, a bundle is represented by a configuration entity, although other models exist in contrib modules. Thus, in the node example, the node type "article" itself is a configuration entity. The configuration stores differences between content entity types, such as settings and fields. When creating a new entity type with bundles, you will create both a content entity (handling content operations) and a configuration entity (managing bundle-specific differences).
Annotations
When creating a new entity type, you’ll need to use the annotation system built into core. Annotations look like docblock comments above a class but are parsed and cached by Drupal core. In many ways, annotations replace older Drupal 7 mechanisms.
Annotation Parser
Annotations are read and parsed at runtime by the annotation mechanism. Drupal 8 uses the Doctrine annotation parser, which turns them into usable PHP objects.
Syntax: Annotation syntax is enclosed in @ClassName(), mostly made of key/value pairs, and can include arrays using curly braces. Top-level keys do not need quotes, but array keys do. Each key/value pair should be on its own line and end with a comma. Functions can be applied to values, especially @Translation().
Invalid annotation syntax example:
/** * @ContentEntityType( * id = "my_entity_type_id", * label = @Translation("My entity type label"), * example_pair = "this_examples_value", * example_array = { * "array_key" = "array_value", * "some_other_key" = "some_other_value", * }, * ) */
Common top-level annotations:
Key = "Example Value" | Description | Entity Variant |
---|---|---|
id = "node", | Machine name for the entity type. | Content & Config |
label = @Translation("Node"), | Human-readable name for the entity type. | Content & Config |
admin_permission = "administer nodes", | Permission to administer the entity type. | Content & Config |
bundle_label = @Translation("Content type"), | Optional human-readable name for the bundle type. | Content |
bundle_entity_type = "node_type", | ID of the configuration entity for bundles. | Content |
base_table = "node", | Database table for the entity type. | Content |
fieldable = TRUE, | (boolean) Can the entity be extended via Field UI. | Content |
field_ui_base_route = "entity.node_type.edit_form", | Base route for Field UI management. | Content |
Handlers
Handlers are defined in the entity annotation as an array. They delegate responsibilities to PHP classes for different lifecycle aspects of the entity.
- storage - Manages loading, saving, and deleting. Content entities typically use
SqlContentEntityStorage
. Example:"storage" = "Drupal\node\NodeStorage"
- form - Handles entity forms. You can define
add
,edit
,delete
, or usedefault
for both add/edit. - view_builder - Manages display output. Example:
"view_builder" = "Drupal\node\NodeViewBuilder"
- list_builder - Handles the admin list of entities. Example:
"list_builder" = "Drupal\node\NodeListBuilder"
- route_provider - (Optional) Generates routes based on links. Works with the
links
annotation. - access - Provides access control. Typically you extend
EntityAccessControlHandler
. - views_data - Enables Views integration. Example:
"views_data" = "Drupal\node\NodeViewsData"
- storage_schema - Further defines database schema customization.
- translation - Manages multilingual form behavior.
Links
Defined as an array in the entity annotation. These are URI paths for operations like viewing, editing, or deleting an entity.
links = { "canonical" = "/node/{node}", "add-page" = "/node/add", "add-form" = "/node/add/{node_type}", "edit-form" = "/node/{node}/edit", "delete-form" = "/node/{node}/delete", "collection" = "/admin/content", }
Note: Routes must still be defined using routing.yml or provided via route_provider.
Links and Route Provider
When combined with route_provider, the above links map to named routes like:
Link Key | Route Name | Example URI | Description |
---|---|---|---|
canonical | entity.node.canonical | /node/1 | View a specific node |
add-page | entity.node.add_page | /node/add | Select a node type to add |
add-form | entity.node.add_form | /node/add/article | Add a node of a specific bundle |
edit-form | entity.node.edit_form | /node/1/edit | Edit a specific node |
delete-form | entity.node.delete_form | /node/1/delete | Delete a specific node |
collection | entity.node.collection | /admin/content | View all nodes in a list |
Usage: Access these links with toUrl()
method:
$view_url_object = $entity->toUrl(); // Default is 'canonical' $edit_url_string = $entity->toUrl('edit-form')->toString();
References:
- Entity API – Generated documentation
- Creating a Custom Content Entity – Simple example
- Creating a Content Entity Type in Drupal 8 – Advanced example
- Creating a Configuration Entity Type in Drupal 8 – Advanced example
- Entity Type Walkthrough – Practical guide
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.