Viewing an entity on a page requires a route on which the entity’s field values
are output on a given path. This can be automated by amending the entity class
attributes.
The contributed Entity API provides various enhancements
to the core Entity API. One such enhancement is the ability to more easily
provide permissions entity types which we will now use.
-
Add the following use statements to src/Entity/Event.php:
use Drupal\entity\EntityAccessControlHandler;
use Drupal\entity\EntityPermissionProvider;
use Drupal\entity\Routing\DefaultHtmlRouteProvider;
-
Add the following to the annotation in src/Entity/Event.php:
handlers: [
'access' => EntityAccessControlHandler::class,
'permission_provider' => EntityPermissionProvider::class,
'route_provider' => [
'default' => DefaultHtmlRouteProvider::class,
],
],
links: [
'canonical' => "/event/{event}",
],
admin_permission: 'administer event',
The entire Event.php file at this point
<?php
namespace Drupal\event\Entity;
use Drupal\Core\Entity\Attribute\ContentEntityType;
use Drupal\Core\Entity\ContentEntityBase;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Entity\EntityPublishedInterface;
use Drupal\Core\Entity\EntityPublishedTrait;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\entity\EntityAccessControlHandler;
use Drupal\entity\EntityPermissionProvider;
use Drupal\entity\Routing\DefaultHtmlRouteProvider;
use Drupal\user\EntityOwnerInterface;
use Drupal\user\EntityOwnerTrait;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
/**
* Defines the event entity class.
*/
#[ContentEntityType(
id: 'event',
label: new TranslatableMarkup('Event'),
entity_keys: [
'id' => 'id',
'uuid' => 'uuid',
'label' => 'title',
'owner' => 'author',
'published' => 'published',
],
handlers: [
'access' => EntityAccessControlHandler::class,
'permission_provider' => EntityPermissionProvider::class,
'route_provider' => [
'default' => DefaultHtmlRouteProvider::class,
],
],
links: [
'canonical' => "/event/{event}",
],
admin_permission: 'administer event',
base_table: 'event',
)]
class Event extends ContentEntityBase implements EntityOwnerInterface, EntityPublishedInterface {
use EntityOwnerTrait, EntityPublishedTrait;
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
// Get the field definitions for 'id' and 'uuid' from the parent.
$fields = parent::baseFieldDefinitions($entity_type);
$fields['title'] = BaseFieldDefinition::create('string')
->setLabel(t('Title'))
->setRequired(TRUE);
$fields['date'] = BaseFieldDefinition::create('datetime')
->setLabel(t('Date'))
->setRequired(TRUE);
$fields['description'] = BaseFieldDefinition::create('text_long')
->setLabel(t('Description'));
// Get the field definitions for 'author' and 'published' from the trait.
$fields += static::ownerBaseFieldDefinitions($entity_type);
$fields += static::publishedBaseFieldDefinitions($entity_type);
return $fields;
}
/**
* @return string
*/
public function getTitle() {
return $this->get('title')->value;
}
/**
* @param string $title
*
* @return $this
*/
public function setTitle($title) {
return $this->set('title', $title);
}
/**
* @return \Drupal\Core\Datetime\DrupalDateTime
*/
public function getDate() {
return $this->get('date')->date;
}
/**
* @param \Drupal\Core\Datetime\DrupalDateTime $date
*
* @return $this
*/
public function setDate(DrupalDateTime $date) {
return $this->set('date', $date->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT));
}
/**
* @return \Drupal\filter\Render\FilteredMarkup
*/
public function getDescription() {
return $this->get('description')->processed;
}
/**
* @param string $description
* @param string $format
*
* @return $this
*/
public function setDescription($description, $format) {
return $this->set('description', [
'value' => $description,
'format' => $format,
]);
}
}
More information on the above
Entity handlers are objects that take over certain tasks related to
entities. Each entity type can declare which handler it wants to use for
which task. In many cases - as can be seen above - Drupal core provides
generic handlers that can be used as is. In other cases or when more
advanced functionality is required, custom handlers can be used instead.
'route_provider' => [
'default' => DefaultHtmlRouteProvider::class,
],
Instead of declaring routes belonging to entities in a *.routing.yml
file like other routes, they can be provided by a handler, as well. This
has the benefit of being able to re-use the same route provider for
multiple entity types, as is proven by the usage of the generic route
provider provided by core.
links: [
'canonical' => "/event/{event}",
],
Entity links denote at which paths on the website we can see an entity (or
multiple entities) of the given type. They are used by the default route
provider to set the path of the generated route. The usage of canonical
(instead of view, for example) stems from the specification of link
relations in the web by the IANA.
See Wikipedia: Link relation and
IANA: Link relations for more information.
-
Rebuild caches
Run drush cache:rebuild
-
Verify the route has been generated
Visit /event/2
Note that an empty page is shown. However, no field values are shown.
Which fields to display when rendering the entity, as well as how to display
them, can be configured as part of the field definitions. Fields are not
displayed unless explicitly configured to.
-
Add the following to the $fields['date'] section of the
baseFieldDefinitions() method of the Event class before the semicolon:
->setDisplayOptions('view', [
'label' => 'inline',
'settings' => [
'format_type' => 'html_date',
],
'weight' => 0,
])
More information on the above
-
Display mode:
->setDisplayOptions('view'
Display options can be set for two different display modes: view and
form. Form display options will be set below.
-
Label display:
The field label can be configured to be displayed above the field value (the
default), inline in front of the field value or hidden altogether. The
respective values of the label setting are above, inline and hidden.
-
Formatter settings:
'settings' => [
'format_type' => 'html_date',
],
Each field is displayed using a formatter. The field type declares a
default formatter which is used unless a different formatter is chosen by
specifying a type key in the display options. Some formatters have
settings which can be configured through the settings key in the display
options. There is no list of IDs of available field types, but
Drupal API: List of classes annotated with FieldFormatter
lists all field formatter classes (for all field types) in core. The ID of a
given field formatter can be found in its class documentation or by
inspecting the @FieldFormatter annotation which also lists the field types
that the formatter can be used for. Given a formatter class the available
settings can be found by inspecting the keys returned by the class’
defaultSettings() method.
-
Weight:
Weights allow the order of fields in the rendered output to be different
than their declaration order in the baseFieldDefinitions() method. Fields
with heigher weights “sink” to the bottom and are displayed after fields
with lower weights.
Altogether, setting the view display options is comparable to using the
Manage display table provided by Field UI module, which also allows
configuring the label display, formatter, formatter settings and weight for
each field.
-
Add the following to the $fields['description'] section of the
baseFieldDefinitions() method of the Event class before the
semicolon:
->setDisplayOptions('view', [
'label' => 'hidden',
'weight' => 10,
])
The entire Event.php file at this point
<?php
namespace Drupal\event\Entity;
use Drupal\Core\Entity\Attribute\ContentEntityType;
use Drupal\Core\Entity\ContentEntityBase;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Entity\EntityPublishedInterface;
use Drupal\Core\Entity\EntityPublishedTrait;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\entity\EntityAccessControlHandler;
use Drupal\entity\EntityPermissionProvider;
use Drupal\entity\Routing\DefaultHtmlRouteProvider;
use Drupal\user\EntityOwnerInterface;
use Drupal\user\EntityOwnerTrait;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
/**
* Defines the event entity class.
*/
#[ContentEntityType(
id: 'event',
label: new TranslatableMarkup('Event'),
entity_keys: [
'id' => 'id',
'uuid' => 'uuid',
'label' => 'title',
'owner' => 'author',
'published' => 'published',
],
handlers: [
'access' => EntityAccessControlHandler::class,
'permission_provider' => EntityPermissionProvider::class,
'route_provider' => [
'default' => DefaultHtmlRouteProvider::class,
],
],
links: [
'canonical' => "/event/{event}",
],
admin_permission: 'administer event',
base_table: 'event',
)]
class Event extends ContentEntityBase implements EntityOwnerInterface, EntityPublishedInterface {
use EntityOwnerTrait, EntityPublishedTrait;
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
// Get the field definitions for 'id' and 'uuid' from the parent.
$fields = parent::baseFieldDefinitions($entity_type);
$fields['title'] = BaseFieldDefinition::create('string')
->setLabel(t('Title'))
->setRequired(TRUE);
$fields['date'] = BaseFieldDefinition::create('datetime')
->setLabel(t('Date'))
->setRequired(TRUE)
->setDisplayOptions('view', [
'label' => 'inline',
'settings' => [
'format_type' => 'html_date',
],
'weight' => 0,
]);
$fields['description'] = BaseFieldDefinition::create('text_long')
->setLabel(t('Description'))
->setDisplayOptions('view', [
'label' => 'hidden',
'weight' => 10,
]);
// Get the field definitions for 'author' and 'published' from the trait.
$fields += static::ownerBaseFieldDefinitions($entity_type);
$fields += static::publishedBaseFieldDefinitions($entity_type);
return $fields;
}
/**
* @return string
*/
public function getTitle() {
return $this->get('title')->value;
}
/**
* @param string $title
*
* @return $this
*/
public function setTitle($title) {
return $this->set('title', $title);
}
/**
* @return \Drupal\Core\Datetime\DrupalDateTime
*/
public function getDate() {
return $this->get('date')->date;
}
/**
* @param \Drupal\Core\Datetime\DrupalDateTime $date
*
* @return $this
*/
public function setDate(DrupalDateTime $date) {
return $this->set('date', $date->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT));
}
/**
* @return \Drupal\filter\Render\FilteredMarkup
*/
public function getDescription() {
return $this->get('description')->processed;
}
/**
* @param string $description
* @param string $format
*
* @return $this
*/
public function setDescription($description, $format) {
return $this->set('description', [
'value' => $description,
'format' => $format,
]);
}
}
Note that the output of the entity can be further customized by adding a theme
function. This is omitted for brevity.