Parameter upcasting in routes
Routes in Drupal 8 or later may include placeholder elements which designate places where the URL contains dynamic values. By naming these placeholders, the system can upcast (convert) those values to actual object instances. For example if a node's base path is '/node/{node}'
, then {node}
is a placeholder.
The ParamConverter system takes care of converting that parameter to a node object instance automatically (because there exists a content entity called node
).
Menu parameter upcasting means converting a menu argument to anything which could be used in the route controllers. It can be an object or an array.
Let's take an example of the following code in Drupal 7:
In my_module.module
function my_module_menu() {
$items['node/%my_menu/mytab'] = array(
// ...
// ...
);
}
The my_module_menu()
function implementing hook_menu()
shows a menu item with an argument %my_menu
. Suppose we want the callback function for this menu item to receive an object after doing some processing on the value passed from the url. e.g., we want to load a specific field of the node with nid
1 when we visit node/1/mytab
.
To accomplish the above in Drupal 7, would require us to create a loader function like the one below:
function my_menu_load($arg) {
// Do whatever with argument and return your values
}
The page callback for the menu would receive whatever is returned from the loader function defined above.
To accomplish same in Drupal 8 or higher makes use of ParamConverter interface. To port the example mentioned above, we will need to do the following:
- Create my_module.routing.yml
- Create my_module.services.yml describing metadata for your custom paramconverter implementing the paramconverter interface
- Implement the custom paramconverter in a PHP class namespaced in my_module.services.yml
- Implement the callback for your menu item defined in my_module.routing.yml
Porting your menu item to Drupal 8 or later
In my_module.routing.yml
my_module.mymenu:
path: '/node/{my_menu}/mytab'
defaults:
_title: 'My Title'
_form: '\Drupal\mymodule\Form\MyModuleformControllerForm'
options:
parameters:
my_menu:
type: my_menu
This is what a typical route would look like in Drupal 8. The route described above is going to render a form on the page depending on the my_menu argument passed down to it.
It's very important that the name of the parameter matches the variable in the page callback arguments. e.g., if the parameter name is declared as my_menu in routing.yml file, the callback function would receive the upcasted value in the $my_menu variable.
Special case: Entity ID parameters
In the case that a route parameter matches the ID of an entity type, you do not need to implement the ParamConverter
class. In routing.yml
, simply write type: entity:my_entity_type
instead of type: my_menu
.
In the case that you are loading your own custom entity Controller implementation, it is important that
- The actual variable name of the entity in the Controller method callback argument should be the identical to the route parameter name. If the route parameter name is
{foobar}
then the variable name must be$foobar
. The route parameter name is typically defined either in a module's routing.yml file, or in the entity classes annotation in the links section. - The variable for the entity in the controller must be type hinted on the entity class, e.g.
\Drupal\foobar\Entity\Foobar $foobar
.
foobar.view:
path: '/foobar/{foobar}'
defaults:
_controller: '\Drupal\foobar\Controller\Foobar::content'
_title: 'Oh yeah foobar'
requirements:
_access: 'TRUE'
And the Controller Implementation
class Foobar extends ControllerBase {
public function content(\Drupal\foobar\Entity\Foobar $foobar, Request $request) {
return [
'#markup' => 'cheesus slice',
];
}
}
Upcasting route slug name options
Routing parameters are not limited to raw entity IDs (like /node/123
) but can also use arbitrary string placeholders known as "slugs". A slug is a short human readable name that uniquely identifies a piece of content. For example if you have a node called "The best recipe for Crème Brûlée!" then you can identify this with the slug best-recipe-creme-brulee
. You can use the options:
for defining slugs:
foobar.view:
path: '/foobar/{foobar_placeholder}'
defaults:
_controller: '\Drupal\foobar\Controller\Foobar::content'
_title: 'Oh yeah foobar'
options:
parameters:
foobar_placeholder:
type: entity:foobar
In this example, my entity type is called foobar
and the first argument on the callback should be named the same as the slug name.
class Foobar extends ControllerBase {
public function content(\Drupal\foobar\Entity\Foobar $foobar_placeholder, Request $request) {
}
}
Building a Parameter Converter service
See https://www.drupal.org/docs/8/api/routing-system/implementing-custom-parameter-converters
Content is originally taken from : http://www.qed42.com/blog/upcasting-menu-parameters-drupal-8
Help improve this page
You can:
- Log in, click Edit, and edit this page
- Log in, click Discuss, update the Page status value, and suggest an improvement
- Log in and create a Documentation issue with your suggestion