Validating Route Parameters

Objectives
  • Learn how to restrict the type of data the route parameters accept
  • Add a basic calculator function to your module
Prerequisites
  • Can define routes
  • Know how to make routes flexible using parameters

Let's say you have a route such as /hello/{param1}/{param2}.

If you browse to /hello/12/DDTPV, for example, you're greeted with the text "Hello, 12 DDTPV". The routing mechanism simply passes the route parameters on to the controller without performing any security checks, formatting checks, or other checks.

So far this hasn't been a problem because our sample code is very basic - it just prints on screen what it receives via the parameters.

However, there are many scenarios where developers do want to have at least a little control over which kinds of values are acceptable before passing them on to the controller.

Validation requirements

You can make the routing mechanism validate the values that parameters receive by adding requirements to your route definition.

Here's an example:

Code
my_route_demo.addition:
  path: '/add/{num_1}/{num_2}'
  defaults:
    _controller: '\Drupal\my_route_demo\Controller\HelloController::addition'
    _title: 'Addition'
  requirements:
    _permission: 'access content'
    num_1: '[0-9]+'
    num_2: '[0-9]+'

Most of the route definition is similar to what you've already used, but the 'requirements' section has two new entries:

num_1: '[0-9]+'
num_2: '[0-9]+'

For both num_1 and num_2 we're stating that the values have to match a certain pattern, in this case they can only contain numbers 0 to 9.

The type of pattern ([0-9]+) is called a regular expression.

Regular expressions are extremely useful and powerful in day to day programming, regardless of which programming language you use. However, learning how to construct regular expressions isn't always easy as the syntax can become complex very quickly.

Explaining regular expressions is beyond the scope of this course, but if you're interested, check out the following resources:

Activity

  • Add the new route definition to your module.
  • Add the following method to your HelloController class and save:
 public function addition($num_1, $num_2) {
   return [
     '#markup' => $this->t('Total is @total', [
       '@total' => $num_1 + $num_2,
     ]),
   ];
 }
  • Clear your caches and see if browsing to /add/5/3 shows you the correct result.
Hide hints
show hints

If everything went well you should now have a basic web based calculator that shows the sum of the two values passed via its route.

This example should illustrate why it can sometimes be interesting to validate parameter values before passing them on to the controller. In our example it wouldn't make sense to pass "John" and "Doe" to the addition() method.

Activity

  • What is going to happen when you try to browse to /add/john/doe?
  • The routing mechanism will validate the parameter values before passing them on to the controller. If one of the values doesn't match the requirements, you get an Error 404 (page not found.
Hide hints
show hints

Activity

  • Create a new route and controller. You can choose the path, name, and other details.
  • The route should accept one parameter
  • The parameter has to be a 4-digit code, only digits, no other characters. The regular expression you can use for this is [1-9]{4}+
  • When you browse to your new route and pass along a valid parameter, you should see the message "Code accepted".
     
Hide hints
show hints

Type Validation

(Even though type validation is beyond the scope of this course, but we have included it for completeness, as it's important to know there are more advanced types of parameter checking available.)

Scenario

Let's say you define the route /unfriend/{user_id} where you intend to have the controller remove the user with id {user_id} from your list of friends.

In this scenario you want to instruct the route to only accept {user_id} as valid if there actually is a Drupal user with that user id.

The routing mechanism lets you do this in the following way:

Code
example.user:
  path: '/example/{user_id}'
  defaults: 
    _controller: '\Drupal\example\Controller\ExampleController::content' 
  requirements: 
    _permission: 'access content' 
  options:
    parameters:
      user_id:
        type: entity:user

Note the options: part of the route definition.

Going into further detail on parameter type validation is outside the scope of this course.
For more information, please refer to:

Summary

  • You can validate route parameters before the route's controller method is called by adding a requirement for each parameter in the route definition.
  • Two common validation scenarios are:
    • Using a regular expression to validate the format, length, or type of characters (numeric, alphanumeric, digits, …)
    • Specifying a 'type hint' to ensure the id matches a certain type of entity (user, node, taxonomy term, …)