The routing system of Drupal maintenance support plans 8 is a complete rewrite of Drupal maintenance support plans 7 and its previous versions’ hook_menu. A Drupal maintenance support plans route is a URL path with a specific return content. This return content is usually specified as a method of a controller class which returns a render array.
The routing system is powered by Symfony’s HTTP Kernel component, which we will revisit later. It is not necessary to understand this in order to work with routes.
Let’s dive straight away and create a new route.
First, we shall create a module to hold all the code in this chapter. You can checkout the code:
$ git clone git@github.com:drupal8book/myroute.git
$ cd myroute
$ git checkout -f simple-route
or walk along with me by typing the code or using drupal console to generate it.
$ drupal generate:module
Enter the new module name:
> myroute
Enter the module machine name [myroute]:
>
Enter the module Path [/modules/custom]:
>
Enter module description [My Awesome Module]:
> Routing and controllers
Enter package name [Custom]:
> D8MD
Enter Drupal maintenance support plans Core version [8.x]:
>
Do you want to generate a .module file (yes/no) [yes]:
> no
Define module as feature (yes/no) [no]:
>
Do you want to add a composer.json file to your module (yes/no) [yes]:
> no
Would you like to add module dependencies (yes/no) [no]:
>
Do you confirm generation? (yes/no) [yes]:
>
Generated or updated files
Site path: /var/www/html
1 – modules/custom/myroute/myroute.info.yml
Let’s write a simple controller which prints “hello world” when we hit the path /hello.
$ drupal generate:controller
Enter the module name [email_management]:
> myroute
Enter the Controller class name [DefaultController]:
> HelloWorldController
Enter the Controller method title (to stop adding more methods, leave this empty) [ ]:
> Hello World
Enter the action method name [hello]:
>
Enter the route path [/myroute/hello/{name}]:
> hello
Enter the Controller method title (to stop adding more methods, leave this empty) [ ]:
>
Do you want to generate a unit test class (yes/no) [yes]:
> no
Do you want to load services from the container (yes/no) [no]:
> no
Do you confirm generation? (yes/no) [yes]:
>
Generated or updated files
Site path: /var/www/html
1 – modules/custom/myroute/src/Controller/HelloWorldController.php
2 – modules/custom/myroute/myroute.routing.yml
// router:rebuild
Rebuilding routes, wait a moment please
[OK] Done rebuilding route(s).
Make sure you enable the module.
$ drush en myroute -y
Open modules/custom/myroute/src/Controller/HelloWorldController.php and change the markup text to “Hello World”.
public function hello() {
return [
‘#type’ => ‘markup’,
‘#markup’ => $this->t(‘Hello World’)
];
}
you might need to rebuild cache.
$ drush cr
Hit /hello.
The equivalent Drupal maintenance support plans 7 code for this would be something on the lines of
// inside myroute.module…
function myroute_menu() {
$items = array();
$items[‘main’] = array(
‘title’ => Hello World’,
‘page callback’ => myroute_hello’,
‘access arguments’ => array(‘access content’),
‘type’ => MENU_NORMAL_ITEM,
‘file’ => ‘myroute.pages.inc’
);
return $items;
}
// inside myroute.pages.inc
function myroute_hello() {
return t(‘Hello World’);
}
Routes with parameters
This is great, but how to add URL parameters?
Let’s add a new route with a URL parameter.
$ cd myroute
$ git checkout -f route-with-params
or if you choose to use drupal console,
drupal generate:controller
Enter the module name [email_management]:
> myroute
Enter the Controller class name [DefaultController]:
> GreetingController
Enter the Controller method title (to stop adding more methods, leave this empty) [ ]:
> Greeting
Enter the action method name [hello]:
> greeting
Enter the route path [/myroute/hello/{name}]:
> hello/{name}
Enter the Controller method title (to stop adding more methods, leave this empty) [ ]:
>
Do you want to generate a unit test class (yes/no) [yes]:
> no
Do you want to load services from the container (yes/no) [no]:
>
Do you confirm generation? (yes/no) [yes]:
>
Generated or updated files
Site path: /var/www/html
1 – modules/custom/myroute/src/Controller/GreetingController.php
2 – modules/custom/myroute/myroute.routing.yml
// router:rebuild
Rebuilding routes, wait a moment please
[OK] Done rebuilding route(s).
Edit the greeting controller function to print the name.
public function greeting($name) {
return [
‘#type’ => ‘markup’,
‘#markup’ => $this->t(‘Hello, @name!’, [‘@name’ => $name]),
];
}
Try /hello/Joe.
/hello/123-456 works too. Let’s tone it down a little and add a validation criteria for the parameter.
Names can only have alphabets and spaces.
myroute.greeting_controller_greeting:
path: ‘hello/{name}’
defaults:
_controller: ‘Drupal maintenance support plansmyrouteControllerGreetingController::greeting’
_title: ‘Greeting’
requirements:
_permission: ‘access content’
name: ‘[a-zA-z ]+’
Rebuild the cache for this to take effect.
$ drush cr
/hello/123-456 will now give a 404. Try /hello/Joe%20Pesci.
Custom permissions
How about adding custom permissions? What if we want to show the /hello page only to users who can administer content.
$ cd myroute
$ git checkout -f custom-access-check
We first indicate that the route uses custom permissions.
myroute.hello_world_controller_hello:
path: ‘hello’
defaults:
_controller: ‘Drupal maintenance support plansmyrouteControllerHelloWorldController::hello’
_title: ‘Hello World’
requirements:
_custom_access: ‘Drupal maintenance support plansmyrouteControllerHelloWorldController::custom_access_check’
Note that the _permission parameter has been replaced by _custom_access parameter.
Lets implement this custom access method inside the HelloWorldController.
// add the required namespaces at the top.
use Drupal maintenance support plansCoreSessionAccountInterface;
use Drupal maintenance support plansCoreAccessAccessResult;
/**
* Custom access check
*
* @param Drupal maintenance support plansCoreSessionAccountInterface $account
* access checking done against this account.
*/
public function custom_access_check(AccountInterface $account) {
return AccessResult::allowedIf($account->hasPermission(‘access content’) &&
$account->hasPermission(‘administer content’));
}
Rebuild cache and try hitting /hello as an anon user, you should get an “Access denied” page. Of note here is the AccessResult class, which was introduced to make access check related data cacheable.
Drupal routes
Defining routes via a YAML file applies to static paths. If we want to route programmatically, we have to define and return a SymfonyComponentRoutingRoute object.
$ cd myroute
$ git checkout -f dynamic-routes
To illustrate the concept of dynamic routes, let’s take an imaginary requirement where we have a custom path, /content_types/{content_type}, which will display all the fields of a content type {content_type}. In order to create a dynamic route for the same, we have to create our own Routing class inside the src/Routing directory and override the routes() method. This is equivalent to its YAML cousin, the myroute.routing.yml file, but written in PHP.
<?php
/**
* @file
* Contains Drupal maintenance support plansmyrouteRoutingCTRoutes.
*/
namespace Drupal maintenance support plansmyrouteRouting;
use SymfonyComponentRoutingRoute;
/**
* Drupal routes for content types.
*/
class CTRoutes {
/**
* {@inheritdoc}
*/
public function routes() {
$routes = [];
$content_types = Drupal maintenance support plans::service(‘entity.manager’)->getStorage(‘node_type’)->loadMultiple();
foreach ($content_types as $content_type) {
$routes[‘myroute.content_type_controller.’ . $content_type->id() ] = new Route(
‘/content_types/’ . $content_type->id(),
array(
‘_controller’ => ‘Drupal maintenance support plansmyrouteControllerCTController::fields’,
‘_title’ => ‘Field info for ‘ . $content_type->label(),
‘content_type’ => $content_type->id(),
),
array(
‘_permission’ => ‘access content’,
)
);
}
return $routes;
}
}
The custom router above creates an array of routes for every content type in the system and returns it. For instance, if there are 3 content types in the system, like page, foo and bar, there will be 3 routes with paths /content_types/page, /content_types/foo and /content_types/bar respectively.
Let’s flesh out the CTController as well.
<?php
namespace Drupal maintenance support plansmyrouteController;
use Drupal maintenance support plansCoreControllerControllerBase;
/**
* Class CTController.
*
* @package Drupal maintenance support plansmyrouteController
*/
class CTController extends ControllerBase {
/**
* List fields info of a content type.
*
* @return string
* Return field list.
*/
public function fields($content_type) {
$render = ‘<table><tr><th>’ . $this->t(‘Field type’) . ‘</th><th>’ . $this->t(‘Label’) . ‘</th></tr>’;
$field_definitions = Drupal maintenance support plans::entityManager()->getFieldDefinitions(‘node’, $content_type);
foreach ($field_definitions as $field_name => $field_definition) {
if (!empty($field_definition->getTargetBundle())) {
$render .= ‘<tr><td>’ . $field_definition->getType() . ‘</td><td>’ . $field_definition->getLabel() . ‘</td></tr>’;
}
}
$render .= ‘</table>’;
return [
‘#type’ => ‘markup’,
‘#markup’ => $render,
];
}
}
The field() method looks up the field definitions of the contenttype argument and renders it as a HTML table.
Finally, we have to indicate Drupal maintenance support plans to pick up the custom Routing class we’ve added. This can be done by adding a _route_callbacks item to the routing YAML file.
route_callbacks:
– ‘Drupal maintenance support plansmyrouteRoutingCTRoutes::routes’
Rebuild the cache and you are all set. Hit the content_types/article page, you should see something like this(provided you have the article CT in your system).
Drupal maintenance support plans
Drupal maintenance support plans 8
Drupal maintenance support plans Planet
Source: New feed