Routing in Drupal 8

55
Routing in Drupal 8 November 13, 2014

Transcript of Routing in Drupal 8

Routing in Drupal 8

November 13, 2014

Nice to Meet You!

Kalpana GoelDeveloper

Drupal.org - kgoel

Twitter - @kalpanagoel

William HurleyManager, Technical

Development

Routes are the mappings between URL paths and

their corresponding page and access callbacks.

What is a route?

What’s Changed

hook_menu defines the

routing in Drupal 7

1:1 mapping of path to route

hook_menu is dead in 8.0.x

There is no hook_menu in Drupal 8!

MODULENAME.routing.yml

One path may map to multiple routes

Why the Change?

D7 hook_menu● Routing (page and access callbacks)

● Menu links

● Local actions

● Local tasks

● Breadcrumbs

● Contextual links

● Title

● Weight

*.links.actin.ml *.links.contexual.yml

Basic Example

D7: hook_menu()

function user_menu() {

$items['user/logout'] = array(

'title' => 'Log out',

'access callback' => 'user_is_logged_in',

'page callback' => 'user_logout',

'weight' => 10,

'menu_name' => 'user-menu',

'file' => 'user.pages.inc',

);

return $items;

}

D7: page callback

/**

* Menu callback; logs the current user out, and redirects to the home page.

*/

function user_logout() {

global $user;

watchdog('user', 'Session closed for %name.', array('%name' => $user->name));

module_invoke_all('user_logout', $user);

// Destroy the current session, and reset $user to the anonymous user.

session_destroy();

drupal_goto();

}

D8: Routing

user.routing.yml

user.logout:

path: '/user/logout'

defaults:

_controller: '\Drupal\user\Controller\UserController::logout'

requirements:

_user_is_logged_in: 'TRUE'

D8: Controller

namespace Drupal\user\Controller;

class UserController extends ControllerBase {

public function logout() {

user_logout();

return $this->redirect('<front>');

}

Path Variables

D8: Path (required)

For dynamic properties, you can include them in curly braces.

For example -

‘/admin/structure/views/{js}/display/{view}/{display_id}/{type}'

The {display_id} element in the URL is called a placeholder and

is available as $display_id in the controller method.

D8: dynamic path example

views_ui.form_display:

path: '/admin/structure/views/{js}/display/{view}/{display_id}/{type}'

defaults:

_content: '\Drupal\views_ui\Form\Ajax\Display::getForm'

class Display extends ViewsFormBase {

public function getForm(ViewStorageInterface $view, $display_id, $js, $type =

NULL) {

$this->setType($type);

return parent::getForm($view, $display_id, $js);

}

D8: Optional Attributes

user.cancel_confirm:

path: '/user/{user}/cancel/confirm/{timestamp}/{hashed_pass}'

defaults:

_title: 'Confirm account cancellation'

_content: '\Drupal\user\Controller\UserController::confirmCancel'

timestamp: 0

hashed_pass: ''

D8: Page Title

user.view:

path: '/user/{user}'

defaults:

_entity_view: 'user.full'

_title_callback: 'Drupal\user\Controller\UserController::userTitle'

requirements:

_entity_access: 'user.view'

D8: Page Types

_content : - display content on a page

_form : - display form on a page.

_controller : - use to generate raw data like json output

_entity_view : - for example - node.teaser

_entity_form : - display a form for a entity

_entity_list : - display list of entity like node

Access Restrictions

D8: Access checking

user.admin_account:

path: '/admin/people'

defaults:

_entity_list: 'user'

_title: 'People'

requirements:

_permission: 'administer users'

D8: Access checkers

Based upon roles, permissions:

_permission - A permission string (e.g. - _permission: ‘access

content’)

_role : A specific user role (e.g.- administrator)

D8: Access checkers

Based upon access to Entities (view, update, delete)

_entity_access: In case where an entity is part of route, can check

a certain access level before granting access (e.g. node.view)

Example:

_entity_access: node.view

D8: Access checkCustom Access

_custom_access: You can also do custom access checking on

route.

Same as title callback (define as method on class)Read more -

https://www.drupal.org/node/2122195

_custom_access: Drupal\shortcut\Form\SwitchShortcutSet::checkAccess

public function checkAccess(UserInterface $user = NULL) {

return shortcut_set_switch_access($user);

}

D8: Access check

Access check for everyone

grant access to everyone

_access: TRUE

D8: Access check

Multiple access check -

node.add_page:

path: '/node/add'

defaults:

_title: 'Add content'

_content:

'\Drupal\node\Controller\NodeController::addPage'

options:

_access_mode: 'ANY'

_node_operation_route: TRUE

requirements:

_permission: 'administer content types'

_node_add_access: 'node'

Forms

D7: Form Router

$items['user/password'] = array(

'title' => 'Request new password',

'page callback' => 'drupal_get_form',

'page arguments' => array('user_pass'),

'access callback' => TRUE,

'type' => MENU_LOCAL_TASK,

'file' => 'user.pages.inc',

);

D7: User Password Form

function user_pass() {

$form['name'] = array(

'#type' => 'textfield',

'#title' => t('Username or e-mail address'),

'#size' => 60,

'#maxlength' => max(USERNAME_MAX_LENGTH,

EMAIL_MAX_LENGTH),

'#required' => TRUE,

'#default_value' => isset($_GET['name']) ? $_GET['name'] : '',

);

[...]

}

function user_pass_validate($form, &$form_state)

function user_pass_submit($form, &$form_state)

D8: Form Router

Forms are classes

There is no method in forms as forms are presented as one class

Use _form instead of _content or _controller

user.pass:

path: '/user/password'

defaults:

_form: '\Drupal\user\Form\UserPasswordForm'

_title: 'Request new password'

requirements:

_access: 'TRUE'

options:

_maintenance_access: TRUE

D8: Form Interface

namespace Drupal\Core\Form;

interface FormInterface {

public function getFormId() {

return 'user_pass';

}

D8: Form Interfacepublic function buildForm(array $form, FormStateInterface $form_state) {

$form['name'] = array(

'#type' => 'textfield',

'#title' => $this->t('Username or email address'),

'#size' => 60,

'#maxlength' => max(USERNAME_MAX_LENGTH,

Email::EMAIL_MAX_LENGTH),

'#required' => TRUE,

'#attributes' => array(

'autocorrect' => 'off',

'autocapitalize' => 'off',

'spellcheck' => 'false',

'autofocus' => 'autofocus',

),

);

D8: Form Interfacepublic function validateForm(array &$form, FormStateInterface $form_state) {

$name = trim($form_state->getValue('name'));

$users = $this->userStorage->loadByProperties(array('mail' => $name, 'status' =>

'1'));

if (empty($users)) {

$users = $this->userStorage->loadByProperties(array('name' => $name, 'status'

=> '1'));

}

if ($account && $account->id()) {

$form_state->setValueForElement(array('#parents' => array('account')),

$account);

}

else {

$form_state->setErrorByName('name', $this->t('Sorry, %name is not recognized

as a username or an email address.', array('%name' => $name)));

$account = reset($users);

}

public function submitForm(array &$form, FormStateInterface $form_state) {

$langcode = $this->languageManager->getCurrentLanguage()->getId();

$account = $form_state->getValue('account');

// Mail one time login URL and instructions using current language.

$mail = _user_mail_notify('password_reset', $account, $langcode);

if (!empty($mail)) {

$this->logger('user')->notice('Password reset instructions mailed to %name

at %email.', array('%name' => $account->getUsername(), '%email' =>

$account->getEmail()));

drupal_set_message($this->t('Further instructions have been sent to your

email address.'));

}

$form_state->setRedirect('user.page');

}

D8: Form Base class

** generic base class - this includes string translation, link generator

Drupal\Core\Form\FormBase

for example -

class UserLoginForm extends FormBase

* * Base class for implementing system configuration forms.

Drupal\core\form\ConfigFormBase

for example -

class MenuSettingsForm extends ConfigFormBase

** base class for a confirmation form.

Drupal\Core\Form\ConfirmFormBase

for example -

class UserMultipleCancelConfirm extends ConfirmFormBase

Other functionality

from hook_menu

local task

local task

local task

D7: menu local tasks

$items['user/password'] = array(

'title' => 'Request new password',

'page callback' => 'drupal_get_form',

'page arguments' => array('user_pass'),

'access callback' => TRUE,

'type' => MENU_LOCAL_TASK,

'file' => 'user.pages.inc',

);

D8: menu local tasks

user.links.task.yml

user.page:

route_name: user.page

base_route: user.page

title: 'Log in'

weight: -10

user.pass:

route_name: user.pass

base_route: user.page

title: 'Request new password'

local action

D7: Local action

$items['admin/structure/types/add'] = array(

'title' => 'Add content type',

'page callback' => 'drupal_get_form',

'page arguments' => array('node_type_form'),

'access arguments' => array('administer content types'),

'type' => MENU_LOCAL_ACTION,

'file' => 'content_types.inc',

);

D8: Local action

node.links.action.yml

node.add_page:

route_name: node.add_page

title: 'Add content'

appears_on:

- system.admin_content

D8: Local action on multiple pagesblock_content.links.action.yml

block_content_add_action:

route_name: block_content.add_page

title: 'Add custom block'

class:

\Drupal\block_content\Plugin\Menu\LocalAction\BlockContentAddLocalAction

appears_on:

- block.admin_display

- block.admin_display_theme

- block_content.list

D8: Contextual

links

D7: Contextual

links$items['admin/structure/block/manage/%/%/configure'] = array(

'title' => 'Configure block',

'type' => MENU_DEFAULT_LOCAL_TASK,

'context' => MENU_CONTEXT_INLINE,

);

D8: Contextual

links

block.links.contextual.yml

block_configure:

title: 'Configure block'

route_name: 'entity.block.edit_form'

group: 'block'

D8: Path based breadcrumb

breadcrumb is path based in Drupal 8

/node/add/content

/node/add

/node

/

https://www.drupal.org/node/2098323

Useful Tips

Options

Useful Tips

_admin_route -- whether to use the admin theme for this route

_maintenance_access -- whether route is publicly available when the site

is in maintenance mode

_access_mode -- whether requirements are ANY or ALL

Useful links

https://www.drupal.org/node/1800686 - change record

https://www.drupal.org/node/2118147 - D7 to D8 upgrade tutorial

https://www.drupal.org/developing/api/8/routing - Routing system in D8

THANK YOU!

Kalpana Goel

William Hurley