Creating a route provider

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.

Getting ready

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.

How to do it…

  1. Create a 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 {
    
    }
  2. Override the provided 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;
      }
    }
  3. The parent method for 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.
  4. Add a new route to the 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;
      }
  5. This section of the code defines the route programmatically. The definition created in the routing.yml is implemented in the SymfonyComponentRoutingRoute instance:

    Delete the mymodule.routing.yml file!

  6. Now, we will add routes based on each bundle, iterate through each message bundle, and add a new route that will provide a route to add a message based on the type specified in the route:
      /**
       * {@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;
      }
  7. This new code loads all the message type entities and adds a new route to each. A route will be created at /messages/add/{message_type} that will predefine the type of message being created.

How it works…

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.

There's more…

Drupal 8 introduces a router types and provide the add routes for our entity.

The Entity API module provides add generation

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.

Providing a collection route

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.

See also

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset