A deep dive into Drupal 8 routing

  • Published on
    05-Apr-2017

  • View
    74

  • Download
    3

Transcript

A Deep Dive into Drupal 8 RoutingDrupalCamp MumbaiApril 1, 2017Naveen Valecha About me Drupal: naveenvalecha Git Administer on Drupal.org Site Maintainer of groups.drupal.org Twitter: @_naveenvalecha_ Web: https://www.valechatech.net Drupal 5,6,7,8https://www.valechatech.net Agenda What are Routes. Why we need them? Routes and Controllers Access checking on routes Custom Access Checkers CSRF Prevention on routes Altering routes Dynamic Routes Parameter Upcasting Routing System hook_menu to Symfony2 routing Replace paths with route names for rendering links Converting all page callbacks to controllers New breadcrumb system, new menu link system, conversion of local tasks and actions to plugins Routing System - Cont. menu links, local tasks, local actions, contextual links Split all the pieces from hook_menu into YAML files finally module.routing.yml module.links.menu.yml module.links.task.yml module.links.action.yml module.contextual.yml hook_menu to Symfony Routing PHP array to multiple yaml files Performance improvements Developer Experience(DX) Clean Code Procedural to Object Oriented(OO)D7 hook_menu$items['admin/appearance/settings'] = array( 'title' => 'Settings', 'description' => 'Configure default and theme specific settings.', 'page callback' => 'drupal_get_form', 'page arguments' => array('system_theme_settings'), 'access arguments' => array('administer themes'), 'type' => MENU_LOCAL_TASK, 'file' => 'system.admin.inc', 'weight' => 20,);D8 system.routing.ymlsystem.theme_settings: path: '/admin/appearance/settings' defaults: _form: '\Drupal\system\Form\ThemeSettingsForm' _title: 'Appearance settings' requirements: _permission: 'administer themes' D8 system.links.task.ymlsystem.theme_settings: route_name: system.theme_settings title: 'Settings' base_route: system.themes_page weight: 100Route A route is a path which is defined for Drupal to return some sort of content on. For example, the default front page, '/node' is a route. Use mm.routing.yml for defining routesRoutes and Controllers The routing system is responsible for matching paths to controllers, and you define those relations in routes. You can pass on additional information to your controllers in the route. Access checking is integrated as well.Route - Slugentity.node.preview: path: '/node/preview/{node_preview}/{view_mode_id}' defaults: _controller: '\Drupal\node\Controller\NodePreviewController::view' _title_callback: '\Drupal\node\Controller\NodePreviewController::title' requirements: _node_preview_access: '{node_preview}' options: parameters: node_preview: type: 'node_preview'/*** Defines a controller to render a single node in preview.*/class NodePreviewController extends EntityViewController { /** * {@inheritdoc} */ public function view(EntityInterface $node_preview, $view_mode_id = 'full', $langcode = NULL) { $node_preview->preview_view_mode = $view_mode_id; $build = parent::view($node_preview, $view_mode_id); return $build; }}example.content: path: '/example' defaults: _controller: '\Drupal\example\Controller\ExampleController::content' custom_arg: 12 requirements: _permission: 'access content'// ...public function content(Request $request, $custom_arg) { // Now can use $custom_arg (which will get 12 here) and $request.}Routes Structure Path(*): /node/preview/{node_preview}/{view_mode_id} defaults(*) _controller: \Drupal\node\Controller\NodePreviewController::view _form: \Drupal\Core\Form\FormInterface _entity_view, _entity_form: _title(optional), _title_context(optional), _title_callback(optional)Routes Structure methods(optional) Requirements _permission, _role, _access, _entity_access, _custom_access, _format, _content_type_format _module_dependencies _csrf_tokenAccess checkingPermissionrequirements: _permission: 'administer content types'Rolerequirements: _role: 'administrator' Access checking - Customclass NodeRevisionAccessCheck implements AccessInterface {public function access(Route $route, AccountInterface $account, $node_revision = NULL, NodeInterface $node = NULL) { if ($node_revision) { $node = $this->nodeStorage->loadRevision($node_revision); } $operation = $route->getRequirement('_access_node_revision'); return AccessResult::allowedIf($node && $this->checkAccess($node, $account, $operation))->cachePerPermissions()->addCacheableDependency($node);}} Route - CSRF Protectionaggregator.feed_refresh: path: '/admin/config/services/aggregator/update/{aggregator_feed}' defaults: _controller: '\Drupal\aggregator\Controller\AggregatorController::feedRefresh' _title: 'Update items' requirements: _permission: 'administer news feeds' _csrf_token: 'TRUE' Routes - Alteringclass NodeAdminRouteSubscriber extends RouteSubscriberBase { protected function alterRoutes(RouteCollection $collection) { if ($this->configFactory->get('node.settings')->get('use_admin_theme')) { foreach ($collection->all() as $route) { if ($route->hasOption('_node_operation_route')) { $route->setOption('_admin_route', TRUE); } } } }} Dynamic RoutesImage.routing.ymlroute_callbacks: - '\Drupal\image\Routing\ImageStyleRoutes::routes' Dynamic Routes - Cont.class ImageStyleRoutes implements ContainerInjectionInterface { public function routes() { $routes = []; $directory_path = $this->streamWrapperManager->getViaScheme('public')->getDirectoryPath(); $routes['image.style_public'] = new Route( '/' . $directory_path . '/styles/{image_style}/{scheme}', [ '_controller' => 'Drupal\image\Controller\ImageStyleDownloadController::deliver', ], [ '_access' => 'TRUE', ] ); return $routes; }} Route-Parameter Upcastingentity.node.preview: path: '/node/preview/{node_preview}/{view_mode_id}' defaults: _controller: '\Drupal\node\Controller\NodePreviewController::view' _title_callback: '\Drupal\node\Controller\NodePreviewController::title' requirements: _node_preview_access: '{node_preview}' options: parameters: node_preview: type: 'node_preview' Route-Parameter Upcasting Cont.node.services.ymlnode_preview: class: Drupal\node\ParamConverter\NodePreviewConverter arguments: ['@user.private_tempstore'] tags: - { name: paramconverter } lazy: true Route-Parameter Upcasting Cont.class NodePreviewConverter implements ParamConverterInterface {public function convert($value, $definition, $name, array $defaults) { $store = $this->tempStoreFactory->get('node_preview'); if ($form_state = $store->get($value)) { return $form_state->getFormObject()->getEntity(); }}public function applies($definition, $name, Route $route) { if (!empty($definition['type']) && $definition['type'] == 'node_preview') { return TRUE; } return FALSE;}Whats for Drupal 9? Consider having a single class for Match Dumper, Route Provider and Route Builder Automatically unserialize request data and serialize outgoing dataReferences http://symfony.com/doc/current/components/routing.html https://www.drupal.org/docs/8/api/routing-systemhttp://symfony.com/doc/current/components/routing.htmlhttp://symfony.com/doc/current/components/routing.htmlhttp://symfony.com/doc/current/components/routing.htmlhttps://www.drupal.org/docs/8/api/routing-systemhttps://www.drupal.org/docs/8/api/routing-systemhttps://www.drupal.org/docs/8/api/routing-systemQuestions?THANK YOU!