1. Using entities for data storage
1.1. Create a module
Section titled “1.1. Create a module”-
Within the
/modules/eventdirectory create anevent.info.ymlfile with the following:See the documentation on Drupal.org for more information about module info files.
-
Run
drush pm:enable eventor visit/admin/modulesand install the Event module
1.2. Create a minimal entity class
Section titled “1.2. Create a minimal entity class”-
Create a
src/Entity/Event.phpfile with the following:More information on the above
-
File and Directory Structure:
The
srcdirectory contains all object-oriented PHP code of a module. Each file contains a single unit of code: a class, trait, interface or an enum. In this tutorial only classes will be created.See the PHP documentation for more information on object-oriented PHP.
Files can either be directly in the
srcdirectory or in any (direct or nested) subdirectory. Certain directory names have a special meaning in Drupal, however. In particular, Drupal looks inEntityfor entity type classes.See Drupal API: Object-oriented programming conventions for more information.
-
Namespace:
Namespaces allow code from different frameworks (Drupal, Symfony, …) to be used simultaneously without risking naming conflicts. Namespaces can have multiple parts. All classes in Drupal core and modules have
Drupalas the top-level namespace. The second part of module classes must be the module name. Further sub-namespaces correspond to the directory structure within thesrcdirectory of the module. -
Import:
In the same way we declare a namespace for the
Eventclass theContentEntityTypeclass used below also belongs to a namespace. Thus, in order to use it below, we need to import the class using the full namespace. -
Attributes:
Attributes are a way to provide metadata about code. Because the attributes are placed right next to the code itself, this allows making classes truly self-contained as both functionality and metadata are in the same file. Note that we have not registered or declared this class in any way to Drupal (and will not do so below, either).
The concrete values that are part of the attribute are defined by the
ContentEntityTypeattribute class. The ones used here will be explained below as they are used. See the class API documentation for more information.See Drupal API: Attribute based plugins for more information.
-
Entity Type ID:
This is the ID of the entity type that is needed whenever interacting with a specific entity type in code. Other entity type IDs used in Drupal are
media,node,taxonomy_termoruser, for example. -
Label:
This is the label of this entity type when presented to a user. This is only used in administrative interfaces.
To make the values we provide in the annotation translatable we need to wrap them in
new TranslatableMarkup(). This would allow us to translate this label as part of Drupal’s Interface Translation system, but we will not do this as part of this tutorial. -
Storage information:
We need to specify the name of the database table we want the event data to be stored. This is called the base table, as there can be multiple tables that store entity information, as we will see below.
Entities are required to have an ID which they can be loaded by. We need to specify what the ID field will be called for our entity. This will also determine the name of the database column that will hold the entity IDs. Other entity types use the convention of prefixing the ID field with the first letter of the entity type ID. For example the
mediaentity type usesmidas the name of its ID field and thenodeentity type usesnid. Following that convention we could name our fieldeidand replace the respective line withThis is only pointed out to clarify the difference between the key and the value in the
'id' => 'id'line. We do not actually follow that convention here as it makes the field naming inconsistent.Similarly to the ID entity types can (and are encouraged to) provide a UUID field. We specify the name of the UUID field to be
uuid.Note that the parameter names of the attribute (such as
entity_keys) are not quoted, but keys in arrays (such asidanduuid) are strings and need to be quoted as such. Also note that trailing commas are allowed both for the parameter list and for arrays.See the PHP documentation for more information on the parameter syntax.
-
Class declaration:
The file name (without the file extension) must correspond to class name (including capitalization).
Classes allow categorizing objects as being of a certain type. Event entities, that will be created below, will be objects that are instances of the entity class
Event. In terms of code organization, classes can be used to group related functionality, which will also be done below. -
Inheritance:
Base classes can be used to implement functionality that is generic and useful for many classes. Classes can inherit all functionality from such a base class by using the
extendskeyword. Then they only need to provide functionality specific to them, which avoids code duplication. -
Content entities:
Content entities are entities that are created by site users. They are typically stored in the database, often with a auto-incrementing integer ID. The examples noted above (Media, Nodes, Taxonomy terms and Users) are all examples of content entities.
-
1.3. Install the entity type
Section titled “1.3. Install the entity type”Drupal can create the database schema for our entity type automatically but this needs to be done explicitly. The preferred way of doing this is with Drush.
-
Run
drush entity:updatesNote that the
{event}table has been created in the database withidanduuidcolumns. -
Create and save an event
Run the following PHP code:
Note that there is a new row in the
{event}table with an ID and a UUID.More information on the above
The
Eventclass inherits thecreate()andsave()methods fromContentEntityBaseso they can be called without being present in theEventclass itself.create()is a static method so it is called by using the class name and the::syntax.save()is not a static method so it is used with an instance of the class and the->syntax. -
Load an event fetch its ID and UUID
Run the following PHP code:
Note that the returned values match the values in the database.
-
Delete the event
Run the following PHP code:
Note that the row in the
{event}table is gone.
1.4. Add field definitions
Section titled “1.4. Add field definitions”Fields are the pieces of data that make up an entity. The ID and UUID that were saved as part of the event above are examples of field values. To be able to store actual event data in our entities, we need to declare additional fields.
Just like with the ID and UUID fields above, Drupal can automatically provide Author and Published fields for us, which we will take advantage of so that we can track who created events and distinguish published and unpublished events.
-
Add the following to
event.info.yml: -
Add the following use statements to
src/Entity/Event.php: -
Add the following to the
entity_keyspart of the attributes of theEventclass:Declaring a
labelkey makes the (inherited)label()method on theEventclass work and also allows autocompletion of events by their title. -
Add the following to the end of the class declaration of the
Eventclass: -
Add the following inside of the class declaration of the
Eventclass:More information on the above
-
Type hint:
Interfaces are contracts that specify the methods a class must have in order to fulfill it.
The interface name in front of the
$entity_typeparameter is a type hint. It dictates what type of object must be passed. Type hinting an interface allows any class that implements the interface to be passed. -
Entity ownership:
When creating an entity with owner support from an entity reference widget, the owner of the host entity is taken over.
-
Inheritance:
The class that is extended (
ContentEntityBasein this case) is called the parent class. ThebaseFieldDefinitions()method inContentEntityBaseprovides field definitions for theidanduuidfields. Inheritance allows us to re-use those field definitions while still adding additional ones. -
Field definition:
Field definitions are objects that hold metadata about a field. They are created by passing the field type ID into the static
createmethod. There is no list of IDs of available field types, but Drupal API: List of classes annotated with FieldType lists all field type classes in core. The ID of a given field type can be found in its class documentation or by inspecting the@FieldTypeannotation. -
Chaining:
Many setter methods return the object they were called on to allow chaining multiple setter methods after another. The setting up of the
titlefield definition above is functionally equivalent to the following code block which avoids chaining:
-
The entire Event.php file at this point
1.5. Install the fields
Section titled “1.5. Install the fields”Drupal notices changes to the entity type that affect the database schema and can update it automatically.
-
Run
drush entity:updatesNote that
title,date,description__value,description__formatandpublishedcolumns have been created in the{event}table.Although most field types consist of a single
valueproperty, text fields, for example, have an additionalformatproperty. Therefore two database columns are required for text fields. -
Create and save an event
Run the following PHP code:
Note that there is a new row in the
{event}table with the proper field values. -
Load an event and fetch its field values.
Run the following PHP code:
Note that the returned values match the values in the database.
In addition to the stored properties field types can also declare computed properties, such as the
dateproperty of a datetime field or theprocessedproperty of text fields. -
Update an event’s field values and save them.
Run the following PHP code:
Note that the values in the database have been updated accordingly.
1.6. Add field methods
Section titled “1.6. Add field methods”Instead of relying on the generic get() and set() methods it is recommended
to add field-specific methods that wrap them. This makes interacting with
events in code more convenient. Futhermore, it is recommended to add an
interface
-
Add the following use statements to
src/Entity/Event.php: -
Add the following methods to the
Eventclass:
Field methods not only provide autocompletion, but also allow designing richer
APIs than the bare field types provide. The setDate() method, for example,
hides the internal storage format of datetime values from anyone working with
events. Similarly the setDescription() method requires setting the
description and the text format simultaneously for security. The publish()
and unpublish() methods make the code more readable than with a generic
setPublished() method.
Note that entity types in core provide an entity-type-specific interface (such
as EventInterface in this case) to which they add such field methods. This
is omitted here for brevity.
The entire Event.php file at this point
-
Try out the new getter methods
Run the following PHP code:
Note that the returned values match the values in the database.
-
Try out the new setter methods
Run the following PHP code:
Note that the values in the database have been updated accordingly.