Skip to main content
Up

Parameter upcasting is a feature in Drupal 9 that allows developers to declare the type of a parameter in a controller method to be an interface or a base class, instead of a specific class. This allows the controller method to accept any class that implements that interface or extends that base class.

When a request is made to a controller method, Drupal's dependency injection system automatically creates an instance of the class that corresponds to the parameter type declared in the method signature. If the type is an interface or a base class, the system will look for a class that implements the interface or extends the base class and instantiate that class.

Here's an example to illustrate how parameter upcasting works in Drupal 9:

</php

use Drupal\Core\Entity\EntityInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Drupal\Core\Controller\ControllerBase;


/**
 * Example controller.
 */
class MyController extends ControllerBase {

  /**
   * Displays a node.
   *
   * @param \Drupal\Core\Entity\EntityInterface $node
   *   The node entity.
   *
   * @return \Symfony\Component\HttpFoundation\Response
   *   The HTTP response.
   *
   * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
   *   Thrown if the node cannot be loaded.
   */
  public function viewNode(NodeInterface $node) {
    if (!$node) {
      throw new NotFoundHttpException();
    }

    // Build and return the response.
    $build = [
      '#markup' => $node->label(),
    ];
    return $build;
  }

}

In the above example, the viewNode() method accepts an EntityInterface parameter instead of a specific class. This allows the method to accept any entity type that implements the EntityInterface interface, such as NodeInterface, UserInterface, or TermInterface provided the routing.yml also accepts parameter of the same type. This also means you can use EntityInterface in the above example and it will still work because of "Liskov Substitution principle".

When a request is made to this method with a node entity, Drupal's dependency injection system will automatically create an instance of the Node class, which extends the ContentEntityBase base class and implements the NodeInterface and EntityInterface interfaces. The method can then use the $node parameter as if it were a Node object.

Parameter upcasting in Drupal 9 can make controller methods more flexible and easier to maintain, as it allows them to work with a wider range of entity types without requiring changes to the method signature.

The above should work automatically without having to add any additional parameters in routing.yml file. But in-case the above alone doesn't work, you will have to tell the routing.yml file what entity type is needed to be upcast. Then your .routing.yml file will look like this:

my_module.view_node:
  path: '/node/{node}'
  defaults:
    _controller: '\Drupal\my_module\Controller\MyController::viewNode'
    _title: 'View Node'
  requirements:
    _permission: 'access content'
    node: \d+
  options:
    parameters:
      node:
        type: entity:node
        parameter_conversion: true

How and where it actually works

There are a couple of tagged services ('route_enhancer' tag) which changes the values in the request attributes.
One example is the param converter. (Drupal\Core\ParamConverter\ParamConverterManager). 

The param converter manager basically runs all the raw values through a list of registered parameter converters of which the entity one (Drupal\Core\ParamConverter\EntityConverter) is the important one.
ParamConverterManager->convert() calls the EntityConverter->convert() method with the NID as parameter and sets the result into the request attributes. This entity converter contains the logic to convert {entity_type} to the corresponding entity object, though you can configure it just how it is shown above.

x

Work

Therefore logo
80 Atlantic Ave, Toronto, ON Canada
Email: hello@therefore.ca
Call us: +1 4166405376
Linkedin

Let us know how we can help!