Entities can implement a route provider that will create the route definitions for the entity's canonical (view), edit, and delete routes. As of Drupal 8.0.1, the add path for an entity is not handled through the default route provider.
In this recipe, we will extend the default DrupalCoreEntityRoutingDefaultHtmlRouteProvider
and provide the add routes for our entity.
You will need a custom module to place the code into in order to implement a configuration entity type. Create an src
directory for your classes. A custom content entity type needs to be implemented, such as the one in the Creating a content entity type recipe.
MessageHtmlRouteProvider
class in the src
directory that extends DrupalCoreEntityRoutingDefaultHtmlRouteProvider
:<?php /** * @file Contains DrupalmymoduleMessageHtmlRouteProvider. */ namespace Drupalmymodule; use DrupalCoreEntityRoutingDefaultHtmlRouteProvider; /** * Provides HTML routes for the message entity type. */ class MessageHtmlRouteProvider extends DefaultHtmlRouteProvider { }
getRoutes
method and collect the parent class's collection of routes returned:<?php /** * @file Contains DrupalmymoduleMessageHtmlRouteProvider. */ namespace Drupalmymodule; use DrupalCoreEntityEntityTypeInterface; use DrupalCoreEntityRoutingDefaultHtmlRouteProvider; /** * Provides HTML routes for the message entity type. */ class MessageHtmlRouteProvider extends DefaultHtmlRouteProvider { /** * {@inheritdoc} */ public function getRoutes(EntityTypeInterface $entity_type) { $collection = parent::getRoutes($entity_type); return $collection; } }
getRoutes
invokes other methods that check whether the entity has defined edit, canonical, or delete route links in its annotation definition. If the entity has, it will return those as a SymfonyComponentRoutingRouteCollection
containing the available routes.collection
that represents the message entity's add route. This will allow us to remove the mymodule.routing.yml
file:/** * {@inheritdoc} */ public function getRoutes(EntityTypeInterface $entity_type) { $collection = parent::getRoutes($entity_type); $route = (new Route('/messages/add')) ->addDefaults([ '_entity_form' => 'message.add', '_title' => 'Add message', ]) ->setRequirement('_entity_create_access', 'message'); $collection->add('entity.message.add_form', $route); return $collection; }
routing.yml
is implemented in the SymfonyComponentRoutingRoute
instance:Delete the mymodule.routing.yml
file!
/** * {@inheritdoc} */ public function getRoutes(EntityTypeInterface $entity_type) { $collection = parent::getRoutes($entity_type); $route = (new Route('/messages/add')) ->addDefaults([ '_entity_form' => 'message.add', '_title' => 'Add message', ]) ->setRequirement('_entity_create_access', 'message'); $collection->add('entity.message.add_form', $route); /** @var DrupalmymoduleEntityMessageTypeInterface $message_type */ foreach (MessageType::loadMultiple() as $message_type) { $route = (new Route('/messages/add/{message_type}')) ->addDefaults([ '_entity_form' => 'message.add', '_title' => "Add {$message_type->label()} message", ]) ->setRequirement('_entity_create_access', 'message'); $collection->add("entity.message.{$message_type->id()}.add_form", $route); } return $collection; }
/messages/add/{message_type}
that will predefine the type of message being created.Entities are powered by the plugin system in Drupal, which means that there is a plugin manager. The default DrupalCoreEntityEntityTypeManager
provides discovery and handling of entities. The DrupalCoreEntityEntityTypeManagerInterface
specifies a getRouteProviders
method that is expected to return an array of strings that provide the fully qualified class name of an implementation of the DrupalCoreEntityRoutingEntityRouteProviderInterface
interface.
There is an event subscriber defined in core.services.yml
called the entity_route_subscriber
. This service subscribes to the dynamic route event. When this happens, it uses the entity type manager to retrieve all entity type implementations, which provide route subscribers. It then aggregates all the SymfonyComponentRoutingRouteCollection
instances received and merges them into the main route collection for the system.
Drupal 8 introduces a router types and provide the add routes for our entity.
In Drupal 8, the Entity module lives on, even though most of its functionalities from Drupal 7 are now in core. The goal of the module is to develop improvements for the developer experience around entities. One of these is the generation of the add form and its routes.
The Entity module provides two new route provider aimed specifically for add routes, the DrupalentityRoutingCreateHtmlRouteProvider
and DrupalentityRoutingAdminCreateHtmlRouteProvider
. The latter option forces the add form to be presented in the administrative theme.
With the Entity module installed, you can add a create
entry for the router_providers
array pointing to the new route provider:
* "route_provider" = {
* "html" = "DrupalCoreEntityRoutingDefaultHtmlRouteProvider",
* "create" = "DrupalentityRoutingCreateHtmlRouteProvider",
* },
Then, you just need to define the add-form
entry in your entity's links
definition, if not already present:
* links = {
* "add-form" = "/admin/structure/message-types/add",
* "delete-form" = "/admin/structure/message-types/{message_type}/delete",
* "edit-form" = "/admin/structure/message-types/{profile_type}",
* "admin-form" = "/admin/structure/message-types/{profile_type}",
* "collection" = "/admin/structure/message-types"
* }
This reduces the amount of boilerplate code required to implement an Entity
.
In the previous recipe, we also needed to define a collection
route manually. The route provider can be used to provide this collection
route:
$route = (new Route('/admin/content/messages')) ->addDefaults([ '_entity_list' => 'message', '_title' => 'Messages', ]) ->setRequirement('permission', $entity_type->getAdminPermission()); $collection->add('entity.message.collection', $route);
This route definition will replace the one in routing.yml
. Route generation items should exist in their own handlers, even if only for a specific item. The collection
route generation will go into a CollectionHtmlRouteProvider
class and can be added as a new route handler. The reasoning is that for ease
of deprecation in the event such a functionality is added to Drupal core.