Drupal 8 - Display core forms through custom routes

We can display drupal core forms such as node edit and add, through our own routes. This gives us much more control and flexibility regarding how we can manage those form pages.

For instance, you might want to display node edit form in one of your own set of tasks (tabs). And since tasks work with routes, you need to be able to render edit form from your custom route, so that you can skip default drupal tasks and have full control over which kind of tasks you want in the page.

Node edit form example

To achieve this, first, we need to see how those forms are working already. For example, for node edit form, we need to see how drupal is building the route internally.

First of all, we need the name of the route, which we can find using web profiler module. Web profiler is part of the devel module.

While web profiler module enabled, if you visit any content edit form, you can find out route name like following:

Node edit form route

In this case route name is entity.node.edit_form

Once we have got internal route name, we can use a tool such as Drupal Console to debug the route and get all information regarding how this is being built.

The Drupal console has a nice router:debug command which we can use in following way, from root directory:

$ drupal router:debug entity.node.edit_form

Above command will give us following information for entity.node.edit_form

 Route                  entity.node.edit_form
 Path                   /node/{node}/edit
 Defaults
  _entity_form          node.edit
 Options
  compiler_class        \Drupal\Core\Routing\RouteCompiler
  _node_operation_route 1
  _admin_route          1
  parameters            node:
                          type: 'entity:node'
                          converter: paramconverter.entity

  _route_filters        method_filter
                        content_type_header_matcher

  _route_enhancers      route_enhancer.param_conversion
                        route_enhancer.entity

  _access_checks        access_check.entity

In Defaults we can see that above route is pointing to an entity form node.edit. And then there are a couple of options which might or might not relevant for us.

Another way to get the information of route is to search for route name in drupal core files and try to find the file in which drupal is defining it. In this case, entity.node.edit_form is defined in Drupal\node\Entity\NodeRouteProvider.

Using information from above, we can create our own custom route and displays the same node.edit entity form.

album.edit_form:
  path: '/admin/album/edit/{node}'
  defaults:
    _entity_form: 'node.edit'
    _title: 'Album'
  requirements:
    _entity_access: 'node.update'
    _permission: 'access content'
    node: \d+
  options:
    _admin_route: true
    parameters:
      node:
        type: 'entity:node'

Once this route is implemented, you can access the same edit form, from URL path mentioned in above configuration.

Node add form example

By default, drupal displays add form according to the specific node type. So you have the following path by default:

/node/add/{node_type}

Now suppose that you need to add support for node id as well. Consider a use case where you are adding a content called song which has a reference field for another content called album and you want to pre-populate album field for song add form. One way to solve this could be to provide album id in add form URL, so that we can use it while rendering the form.

Node add form is implemented in a slightly different way, so it's a good candidate to demonstrate another example.

If we go to any add content form, using web profiler we can see that its route name is node.add.

Node add form route

Using drupal console, we get the following information for this route:

Route                  node.add
 Path                   /node/add/{node_type}
 Defaults
  _controller           \Drupal\node\Controller\NodeController::add
  _title_callback       \Drupal\node\Controller\NodeController::addPageTitle
 Options
  compiler_class        \Drupal\Core\Routing\RouteCompiler
  _node_operation_route 1
  parameters            node_type:
                          with_config_overrides: true
                          type: 'entity:node_type'
                          converter: paramconverter.entity

  _admin_route          1
  _route_filters        method_filter
                        content_type_header_matcher

  _route_enhancers      route_enhancer.param_conversion

  _access_checks        access_check.node.add

And by searching in drupal core, we find route definition in core/modules/node/node.routing.yml file.

node.add:
  path: '/node/add/{node_type}'
  defaults:
    _controller: '\Drupal\node\Controller\NodeController::add'
    _title_callback: '\Drupal\node\Controller\NodeController::addPageTitle'
  requirements:
    _node_add_access: 'node:{node_type}'
  options:
    _node_operation_route: true
    parameters:
      node_type:
        with_config_overrides: true

We can see that, in this case add action of NodeController is being used to get the contents of this form.

For the sake of example, we can try to re-implement this action in our own custom controller action:

public function addSong(NodeTypeInterface $node_type, $node) {
  $entity = $this->entityTypeManager()->getStorage('node')->create(array(
    'type' => $node_type->id(),
  ));

  // build form
  $form = $this->entityFormBuilder()->getForm($entity);

  return $form;
}

Since we are building the form by ourselves now, you can imagine and do all sorts of things with form before returning it.

Lastly, we can create a route like following to display add content form through our own controller action.

song.add_form:
  path: '/admin/songs/add/{node_type}/{node}'
  defaults:
    _controller: '\Drupal\music\Controller\SongController::addSong'
    _title: 'Add song'
  requirements:
    _node_add_access: 'node:{node_type}'
  options:
    _node_operation_route: true
    parameters:
      node_type:
        with_config_overrides: true

And then we can access the song add form using a URL like following

 /admin/songs/add/song/4 

Where song is the node_type and 4 is the node (album) id.

Above two examples are just to give you an idea about how can we hack into drupal core routing and modify it according to our needs. While most of the time you would want to avoid it if possible, but still it's good to know about the possibilities.


  PHP, Drupal 8