Juanen Bernal
Drupal developer en idealista/news
Profesor Drupal 8 en OpenWebinars
Maintainer S3 File System y
irc: jansete
Qué vamos a ver
¿Os acordáis de ...?
¿y si ahora quiero que se llame blog?
¿por qué no aparezco en Google?
¿cómo defino nuevas URLs?
¿dónde pongo los ficheros php?
¿puedo controlar el acceso?
The requested URL was not found on this server.
POST, GET, PATCH, HEAD, PUT, DELETE ...
¿y la europea?
¿cómo hago un enlace a una URL interna?
¿ qué hacemos con las cabeceras?
/index.php?noticia=71
Sistema de routing en Drupal 8
¿Cuándo se ejecuta?
Flujo de una petición en Drupal 8
Rutas y controladores: creando nuestra primera página
/hello-world
Elementos principales
¿Qué necesitamos para declarar una ruta?
into_the_wild.routing.yml
into_the_wild.hello_world:
path: '/hello-world'
defaults:
_controller: \Drupal\into_the_wild\Controller\HelloController::helloWorld
_title: 'Hello world'
requirements:
_permission: 'access content'
Controladores
HelloController.php
<?php
namespace Drupal\into_the_wild\Controller;
use Drupal\Core\Controller\ControllerBase;
class HelloController extends ControllerBase {
public function helloWorld(Request $request) {
return [
'#type' => 'markup',
'#markup' => $this->t('Hello world'),
];
}
}
Voilà!
Usando parámetros en las rutas
/hello/{name}
Usando parámetros en rutas
into_the_wild.hello_name:
path: '/hello/{name}'
defaults:
_controller: \Drupal\into_the_wild\Controller\HelloController::helloName
requirements:
_access: 'TRUE'
name: '[a-zA-Z]+'
Usando parámetros en rutas
public function helloName($name) {
return [
'#type' => 'markup',
'#markup' => $this->t('Hello @name', ['@name' => $name]),
];
}
Definiendo valores por defecto
into_the_wild.hello_name:
path: '/hello/{name}'
defaults:
_controller: \Drupal\into_the_wild\Controller\HelloController::helloName
name: 'Christopher'
requirements:
_access: 'TRUE'
name: '[a-zA-Z]+'
Otras curiosidades
Parameter converters
/hello/{user}
Parameters upcasting
into_the_wild.hello_user:
path: '/hello/{user}'
defaults:
_controller: \Drupal\into_the_wild\Controller\HelloController::helloUser
requirements:
_access: 'TRUE'
user: \d+
Parameters upcasting: condiciones
Parameters upcasting: condiciones
Ejemplo de entidad: \Drupal\user\Entitity\User
/**
* Defines the user entity class.
*
* The base table name here is plural, despite Drupal table naming standards,
* because "user" is a reserved word in many databases.
*
* @ContentEntityType(
* id = "user",
* label = @Translation("User"),
* …
* )
*/
Parameters upcasting: condiciones
Ejemplo de clase de entidad: \Drupal\user\Entitity\User
public function helloUser(UserInterface $user) {
return [
'#type' => 'markup',
'#markup' => $this->t('Hello @user', ['@user' => $user->getDisplayName()]),
];
}
¿Y si usamos dos parámetros de la misma entidad?
into_the_wild.hello_users:
path: '/hello/{user1}/{user2}'
defaults:
_controller: \Drupal\into_the_wild\Controller\HelloController::helloUsers
requirements:
_access: 'TRUE'
user1: \d+
user2: \d+
options:
parameters:
user1:
type: entity:user
user2:
type: entity:user
Obteniendo los valores originales
$request->attributes->get('_raw_variables')->get('user');
$route_match->getRawParameters('user');
Creando nuestro propio Parameter converter
Parameter Converters
¿Qué necesitamos?
Y obviamente :)
Parameter Converters: routing.yml
into_the_wild.tripper:
path: '/tripper/{tripper}'
defaults:
_controller: \Drupal\into_the_wild\Controller\TripperController::view
requirements:
_access: 'TRUE'
Parameter Converters
class Tripper {
private $id;
public function __construct($id) {
$this->id = $id;
}
public function getId() {
return $this->id;
}
}
Parameter Converters: services.yml
services:
into_the_wild.tripper_param_converter:
class: Drupal\into_the_wild\Routing\TripperParamConverter
tags:
- { name: paramconverter }
Parameter Converters: servicio
<?php
namespace Drupal\into_the_wild\Routing;
use ...
class TripperParamConverter implements ParamConverterInterface {
public function applies($definition, $name, Route $route) {
return !empty($definition['type']) && $definition['type'] == 'tripper';
}
public function convert($value, $definition, $name, array $defaults) {
return new Tripper($value);
}
}
Parameter Converters: routing.yml
into_the_wild.tripper:
path: '/tripper/{tripper}'
defaults:
_controller: \Drupal\into_the_wild\Controller\TripperController::view
requirements:
_access: 'TRUE'
options:
parameters:
tripper:
type: tripper
Parameter Converters: Controlador
class TripperController extends ControllerBase {
public function view(Tripper $tripper) {
return [
'#type' => 'markup',
'#markup' => $this->t('Tripper id is: @tripper_id', ['@tripper_id' => $tripper->getId()]),
];
}
}
Dando un repaso al routing.yml
Dando un repaso al routing.yml
into_the_wild.hello_users:
path: '/hello/{user1}/{user2}'
defaults:
_controller: \Drupal\into_the_wild\Controller\HelloController::helloUsers
requirements:
_access: 'TRUE'
user1: \d+
user2: \d+
methods: [GET, POST] #opcional
options: #opcional
parameters:
user1:
type: entity:user
user2:
type: entity:user
routing.yml: defaults
Define las propiedades por defecto de la ruta.
into_the_wild.hello_users:
defaults:
_controller: \Drupal\into_the_wild\Controller\HelloController::helloUsers
_controller: into_the_wild.service:helloUsers
_form: \Drupal\into_the_wild\Form\SettingsForm
_entity_view: 'node.teaser'
_entity_list: 'node_type'
_entity_form: 'node_type.add'
_title: 'Título de la página' #opcional
_title_context: 'Contexto de traducción' #opcional
_title_callback: \Drupal\into_the_wild\IntoTheWildRouting::titleCallback #opcional
routing.yml: requirements
into_the_wild.hello_users:
requirements:
_permission: 'access content'
_permission: 'access content, administer content types' # AND
_permission: 'access content + administer content types' # OR
_role: 'admin'
_role: 'admin, manager' # AND
_role: 'admin + manager' # OR
_access: 'TRUE'
_entity_access: 'node.view'
_custom_access: '\Drupal\into_the_wild\Controller\ExampleController::access'
_format: json
_content_type_format: json
_module_dependencies: 'image'
_module_dependencies: 'image, file_version' # OR WTF??
_module_dependencies: 'image + file_version' # AND WTF??
user1: \d+
user2: \d+
routing.yml: options
Opciones adicionales de interacción con la ruta.
into_the_wild.hello_users:
options:
_admin_route: 'TRUE'
_auth: ['basic_auth', 'cookie']
no_cache: 'TRUE'
parameters:
user1:
type: entity:user
user2:
type: entity:user
Rutas dinámicas con route callbacks
Rutas dinámicas con Route callbacks
¿Cómo solucionamos esto?
image.routing.yml
route_callbacks:
- '\Drupal\image\Routing\ImageStyleRoutes::routes'
Rutas dinámicas en core: image styles
<?php
namespace Drupal\image\Routing;
use ...
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;
}
}
Parámetros complejos con Path Processors
Parámetros complejos: path processors
¿Os suena de algo?
Image style path processor
Request URI
/sites/default/files
/styles/medium/public
/2017-07/homer.png?itok=7BXqWIP1
Route Path
/$directory_path
/styles/{image_style}/{scheme}
PathProcessorImageStyles::processInbound()
Path:
/sites/default/files
/styles/medium/public
GET:
file = /2017-07/homer.png
itok = 7BXqWIP1
Obteniendo el parámetro GET
<?php
namespace Drupal\image\Controller;
use …
/**
* Defines a controller to serve image styles.
*/
class ImageStyleDownloadController extends FileDownloadController {
public function deliver(Request $request, $scheme, ImageStyleInterface $image_style) {
$target = $request->query->get('file');
$image_uri = $scheme . '://' . $target;
...
}
}
Parámetros complejos: Path processors
Alterando rutas
Alterando rutas
Definiendo el Event Subscriber
services:
into_the_wild.route_subscriber:
class: Drupal\into_the_wild\Routing\RouteSubscriber
tags:
- { name: event_subscriber }
Alterando una ruta
<?php
namespace Drupal\into_the_wild\Routing;
use Drupal\Core\Routing\RouteSubscriberBase;
use Symfony\Component\Routing\RouteCollection;
class RouteSubscriber extends RouteSubscriberBase {
protected function alterRoutes(RouteCollection $collection) {
if ($route = $collection->get('user.login')) {
$route->setPath('/login');
}
}
}
Clases relacionadas
Clases y servicios relacionados
Enlaces de interés
Plataforma de formación IT con más de 50 cursos: ansible, symfony, vagrant, etc, etc ...
Un curso nuevo cada semana.
A finales de año contaremos con la primera parte de un curso de Backend para Drupal 8.