Subscribe To Our NewsLetter
Share This Post:
In Drupal 8 and later versions, the routing system allows developers to define routes for various pages in their applications. These routes can include placeholder elements in the path, which are essentially variables or dynamic values in the URL. These placeholders are enclosed in curly braces, such as {node} in the example I have provided.
How upcasting parameters work: Step-by-Step Process
Placeholder Elements
These are parts of the URL that are variable or dynamic.In the example, /node/{node}, {node} is a placeholder indicating that this part of the URL can vary. The placeholders are named to make them identifiable. In the example, {node} is named to indicate that it represents a node ID.
Upcasting
Upcasting refers to the process of converting a placeholder value from the URL into an actual object instance.In the example, the system wants to convert the {node} placeholder value into an actual node object.
ParamConverter System
Drupal's ParamConverter system is responsible for performing this conversion automatically.
The ParamConverter system takes the placeholder value (e.g., a node ID) and converts it into an instance of the corresponding object (e.g., a node object).
Example:
Note: This example is from the contrib module Profile.
Suppose you have a route with the path /user/{user}/{profile_type}/add.
When a user visits a URL like /user/12/editor, the ParamConverter system would automatically convert the value 12 to an actual user object with the ID 12.
Here's an example to illustrate how parameter upcasting works in Drupal 9:
Step 1: FILENAME: profile.routing.yml
FILENAME: profile.routing.yml
profile.user_page.add_form:
path: '/user/{user}/{profile_type}/add'
defaults:
_controller: '\Drupal\profile\Controller\UserController::addForm'
_title: 'Add profile'
requirements:
_profile_type_multiple: 'TRUE'
_custom_access: '\Drupal\profile\Controller\UserController::checkCreateAccess'
Step 2: Filename: UserController.php
Filename: UserController.php
<?php
namespace Drupal\profile\Controller;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Session\AccountInterface;
use Drupal\profile\Entity\ProfileInterface;
use Drupal\profile\Entity\ProfileTypeInterface;
use Drupal\user\UserInterface;
/**
* Provides the profile UI for users.
*/
class UserController extends ControllerBase {
/**
* Checks access for the single/multiple pages.
*
* @param \Drupal\user\UserInterface $user
* The user account.
* @param \Drupal\profile\Entity\ProfileTypeInterface $profile_type
* The profile type.
* @param \Drupal\Core\Session\AccountInterface $account
* The currently logged in account.
*
* @return \Drupal\Core\Access\AccessResultInterface
* The access result.
*/
public function checkAccess(UserInterface $user, ProfileTypeInterface $profile_type, AccountInterface $account) {
$user_access = $user->access('view', $account, TRUE);
if (!$user_access->isAllowed()) {
// The account does not have access to the user's canonical page
// ("/user/{user}"), don't allow access to any sub-pages either.
return $user_access;
}
$access_control_handler = $this->entityTypeManager()->getAccessControlHandler('profile');
$profile_storage = $this->entityTypeManager()->getStorage('profile');
$profile_stub = $profile_storage->create([
'type' => $profile_type->id(),
'uid' => $user->id(),
]);
$operation = $profile_type->allowsMultiple() ? 'view' : 'update';
$result = $access_control_handler->access($profile_stub, $operation, $account, TRUE);
return $result;
}
}
Well, Drupal lands with many built-in parameter converters:
Drupal\Core\ParamConver\EntityConverter : Parameter converter for upcasting entity IDs to full objects.
Drupal\Core\ParamConver\EntityRevisionParamConverter : Parameter converter for upcasting entity revision IDs to full objects.
Drupal\Core\ParamConver\MenuLinkPluginConverter: Parameter converter for upcasting menu entity ids to full objects.
Drupal\ctools\ParamConverter\TempstoreConverter: Parameter converter for pulling entities out of the tempstore. This is particularly useful when building non-wizard forms (like dialogs) that operate on data in the wizard and getting the route access properly.
Drupal\jsonapi\ParamConverter\EntityUuidConverter: Parameter converter for upcasting entity UUIDs to full objects. Be aware JSON:API maintains no PHP API since its API is the HTTP API. This class may change at any time and this will break any dependencies on it.
How to create a custom ParamConvertor
Here are the steps to create a custom ParamConverter.
Step1: Create my_module.routing.yml
my_module.custom_entity_page:
path: '/node/{dynamic_title}/page'
defaults:
_title: 'My Title'
_form: '\Drupal\mymodule\Form\MyModuleformControllerForm'
options:
parameters:
dynamic_title:
type: custom_entity
parameter_conversion: true
options:: This is the root key for additional options in a route definition.
parameters:: This section is used to define parameters for the route.
dynamic_title:: This is the name of the parameter. In this case, it's referring to a parameter named dynamic_title.
type: custom_entity: This specifies the type of the parameter. It tells Drupal that the dynamic_title parameter should be an entity of type custom_entity. This is useful for Drupal to understand the expected type of the parameter and apply appropriate validation and conversion.
parameter_conversion: true: This option indicates that parameter conversion should be applied for the dynamic_title parameter. Parameter conversion is the process by which Drupal automatically converts placeholder values in the URL to actual objects based on the specified type.
Step 2: Create my_module.services.yml
Describing metadata for your custom paramconverter implementing the paramconverter interface.
my_module.services.yml
services:
my_module.custom_param_converter:
class: Drupal\my_module\ParamConverter\CustomEntityConverter
arguments: ['@entity_type.manager']
tags:
- { name: 'paramconverter' }
{ name: 'paramconverter' } : This is a tag applied to the service. It specifies that the service should be recognized as a paramconverter. The name attribute is set to 'paramconverter'.
Step 3. Implement the custom param converter in a PHP class namespace in my_module.services.yml
Note: Create the file inside the /src folder.
<?php
namespace Drupal\custom_entity;
use Drupal\Core\ParamConverter\ParamConverterInterface;
use Symfony\Component\Routing\Route;
/**
* Converts parameters for upcasting section types.
*/
class CustomConverter implements ParamConverterInterface {
/**
* {@inheritdoc}
*/
public function convert($value, $definition, $name, array $defaults) {
$title = $value . 'CustomTitle';
return $title;
}
/**
* {@inheritdoc}
*/
public function applies($definition, $name, Route $route) {
return (!empty($definition['type']) && $definition['type'] === 'custom_entity');
}
}
After all this, clear the cache.
In the convert function, you can manipulate the actual value of the placeholder. You can also add some logic in it if the condition is not satisfied then you can return null which can lead it to 404 page not found error.
Returning null from the convert method of a custom ParamConverter in Drupal can result in a "Page Not Found" error. When a ParamConverter returns null, it signals to Drupal that the conversion process was not successful.
How upcasting parameters work
There are a couple of tagged services ('route_enhancer' tag) which change the values in the request attributes. One example is the param converter. (Drupal\Core\ParamConverter\ParamConverterManager).
The param converter manager 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 a 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.
Conclusion
In Drupal, Parameter Upcasting enables dynamic URL values to be converted into object instances through the ParamConverter system. The above information illustrates creating a custom ParamConverter for a custom entity type.
This process involves defining parameters in the routing YAML file, configuring services, and implementing a converter class. Understanding this mechanism is vital for developers managing dynamic URLs effectively, offering flexibility in handling diverse scenarios.
LN Webworks can help you with the process. We are known for our incredible Drupal development services across the world. As a trusted Drupal company, our primary focus is the utmost satisfaction of our clients. So, reach out to us today and experience the magic we create.
Share This Post:
Author Information
LN Webworks
Your Drupal Solution PartnerLN Webworks have championed open-source technologies for nearly a decade, bringing advanced engineering capabilities and agile practices to some of the biggest names across media, entertainment, education, travel, hospitality, telecommunications and other industries.