Introducción al Backend de Drupal es un taller impartido durante el Drupal Day Spain 2019 en Zaragoza, estas son las slides de la actividad.
Incluye aspectos como:
- Creación de módulos custom en Drupal
- Creación de formularios custom en Drupal
- Inyección de Dependencias para Servicios en Drupal
- Prefilling de valores en campos de formulario
- Comandos útiles para herramientas de consola en Drupal
2. BIENVENIDA
David Rodríguez Vicente
(Drupal) Center Leader Specialist en Everis Sevilla
Responsable técnico de Proyectos basados en Drupal
Director técnico del equipo Drupal de Everis Center Sevilla
Profile
https://www.linkedin.com/in/davidjguru
https://www.drupal.org/u/davidjguru
Blogs
https://medium.com/@davidjguru (esp)
https://davidjguru.github.io (en)
Repos
https://gitlab.com/davidjguru
https://github.com/davidjguru
Contacto
https://twitter.com/davidjguru
davidjguru@gmail.com
https://twitter.com/DrupalSevilla
HELLO MY NAME IS.
1, HOLA QUE TAL
2
3. Ver Drupal por dentro
Introducción a tu nuevo backend favorito
Progresivo, iterativo e incremental
Asentemos conceptos básicos
Observa las posibilidades
Experiencia Inicial Motivadora
Cogiendo cariño a Drupal
PRESENTACIÓN
2, dE QUÉ VA ESTO
picture from Unsplash, user Konstantin Aal - @kostic86
4. Practicaremos creando nuevos módulos Custom de Drupal.
Expondremos los fundamentos del sistema de rutas y
controladores de Drupal con la idea de construir accesos a
nuestros formularios. Conoceremos los fundamentos de la
creación de formularios con Drupal, crearemos varios tanto a
mano como con su versión rápida usando Drupal Console.
Dotaremos a los campos de formulario con valores ya cargados
previamente, y para ese pre-filling de campo usaremos algunos
servicios proporcionados por Drupal. Usaremos servicios web para
realizar peticiones externas vía REST y cargar información en
nuestros formularios. Realizaremos consultas a la base de datos y
cargaremos valores dinámicamente en nuestro formulario.
PRESENTACIÓN
2, qUÉ VAMOS A HACER
5. MÓDULOS CUSTOM EN DRUPAL 3 4 RUTAS Y CONTROLADORES EN DRUPAL
PERMISOS Y MENÚS EN DRUPAL 5 6 FORMULARIOS EN DRUPAL
COMANDOS ÚTILES EN DRUPAL 7 8 INYECCIÓN DE DEPENDENCIAS EN DRUPAL
PREFILLING DE VALORES EN CAMPOS 9
BIENVENIDA 1 2 PRESENTACIÓN
LECTURAS RECOMENDADAS 11 12 DESPEDIDA Y CIERRE
PRESENTACIÓN
10 CONSULTAS DINÁMICAS A LA BASE DE DATOS
2, QUÉ VA A PASAR
5
6. MÓDULOS CUSTOM EN DRUPAL
3, QUÉ ES UN MÓDULO
6
1- Elegir un nombre.
2- Elegir un nombre corto,
“machine_name”.
3- Será usado en la creación de diversos
ficheros internos.
4- Servirá para identificar el módulo por
parte del sistema Drupal.
5- Debe empezar con una letra.
6- Debe contener solo letras en minúscula y guiones
bajos.
7- Debe ser único y no puede coincidir con otro módulo,
theme o profile.
8- No debe contener palabras reservadas: lib, js, src, css,
vendor, files, assets, images, templates, includes, Drupal.
7. MÓDULOS CUSTOM EN DRUPAL
3, CREAR UN MÓDULO
/MODULES/CUSTOM/WORKSHOP_FORMS/
WORKSHOP_FORMS.INFO.YML
name: 'Workshop Forms'
type: module
description: 'My Custom Module for Forms.'
core: 8.x
package: 'Workshop'
7
8. RUTAS Y CONTROLADORES EN DRUPAL
4, ESO DE ROUTING
RUTA CONTROLADOR
Esquema de definición de una ruta:
Nombre de sistema (machine_name)
Ruta física (path)
Controladores: clase y método responsables
Título
Especificación de permisos
Nos referimos en realidad a una clase que
se hace responsable de gestionar el
procesamiento de una ruta.
Forma Class::method
_controller:
Drupal[module_name]Controller[ClassName]::[method]
Forma Service:method
_controller: ‘[name_service].controller:[method]’
Forma ClassFormulario
_form: ‘Drupal[module_name]Form[FormClassName]’
Una ruta es (conceptualmente) el camino a
seguir para alcanzar un destino a partir de
un punto de partida.
En Drupal se sigue el modelo de Symfony
para gestionar rutas, basado en MVC, donde
se definen rutas en un fichero descriptivo y
se les asigna una clase responsable
(Controlador, Formulario, Servicio).
8
9. RUTAS Y CONTROLADORES EN DRUPAL
4, CREAR EL ROUTING
/MODULES/CUSTOM/WORKSHOP_FORMS/
WORKSHOP_FORMS.ROUTING.YML
workshop_forms.form:
path: '/workshop/forms/form'
defaults:
_form:
'Drupalworkshop_formsFormCustomForm’
_title: 'Workshop Forms Custom Form'
requirements:
_permission: 'workshop forms access'
9
11. PERMISOS Y MENÚS EN DRUPAL
5, DEFINIR PERMISOS
/MODULES/CUSTOM/WORKSHOP_FORMS/
WORKSHOP_FORMS.PERMISSIONS.YML
Workshop forms access:
title: 'Workshop forms access'
description: 'Access to Workshop form'
11
En Drupal el acceso se puede
gestionar a través de permisos,
establecidos en un fichero
declarativo y luego vinculados a
un rol o a un usuario específico.
12. PERMISOS Y MENÚS EN DRUPAL
12
5, CONSTRUIR MENÚ
/MODULES/CUSTOM/WORKSHOP_FORMS/
WORKSHOP_FORMS.LINKS.MENU.YML
workshop_forms.admin_workshop:
title: ‘Workshop’
parent: system.admin
route_name: workshop_forms.admin_workshop
description: ‘Links to resources from Workshop’
weight: -11
En Drupal 8 la especificación
de una ruta se mantiene
desacoplada de la definición
de un enlace de menú.
Los gestionamos como
configuración en un fichero
propio.
13. PERMISOS Y MENÚS EN DRUPAL
5, ELEMENTOS HIJOS
workshop_forms.forms_view:
title: 'Workshop Form'
parent: workshop_forms.admin_workshop
route_name: workshop_forms.form
description: 'Showing Workshop Form'
weight: 1
workshop_forms.forms_page:
title: 'Workshop Page'
parent: workshop_forms.admin_workshop
route_name: workshop_forms.page
description: 'Showing Workshop Page'
weight: 2
SI QUIERES AMPLIAR CON OTRO ENLACE HIJO
PERO RECUERDA DEFINIR RUTA Y CONTROLADOR
13
14. PERMISOS Y MENÚS EN DRUPAL
4, AMPLIAMOS ROUTING
DEFINIMOS UNA RUTA MADRE
WORKSHOP_FORMS.ROUTING.YML
workshop_forms.admin_workshop
path: '/admin/workshop'
defaults:
_controller:
'DrupalsystemControllerSystemController::systemAdminMenuBlockPage'
_title: 'Workshop First Link'
requirements:
_access: 'TRUE'
14
15. FORMULARIOS EN DRUPAL
6, FORM API DE DRUPAL
CONCEPTOS BÁSICOS DE FORMULARIOS
TIPOS DE FORMULARIOS EN DRUPAL
1- Basic Form: a normal form of general purpose, adaptable.
Created from the FormBase Class in Drupal API and maybe the
most basic kind of form. Class FormBase.php
2- Config Form: a form of specific use to establish an object
and configuration values. Created from the ConfigFormBase in
Drupal API. Class ConfigFormBase.php
3- Confirm Form: a form to request confirmation from the user
before executing an irreversible action. Created from the
ConfigFormBase in Drupal API. Class ConfirmFormBase.php 15
18. FORMULARIOS EN DRUPALFORMULARIOS EN DRUPAL
6, BASIC FORM DRUPAL
/src/Form/CustomForm.php
<?php
namespace Drupalworkshop_formsForm;
use DrupalCoreFormFormBase;
use DrupalCoreFormFormStateInterface;
class CustomForm extends FormBase {
}
picture from Unsplash, user Mitil - @gigantfotos
18
19. FORMULARIOS EN DRUPAL
6, MÉTODOS BÁSICOS
RESPONSABILIDADES CLAVE
public function getFormId() {
return 'workshop_form';
}
public function buildForm(array $form,
FormStateInterface $form_state) {
return $form;
}
public function validateForm(array &$form,
FormStateInterface $form_state) {
}
public function submitForm(array &$form,
FormStateInterface $form_state) {
}
Devolver el nombre del formulario ->
Construir el formulario y devolverlo ->
Validar los valores del formulario ->
Enviar y procesar valores del formulario ->
$form -> Formulario, $form_state -> Valores
19
21. COMANDOS ÚTILES EN DRUPAL
21
7, ENABLE / DISABLE
INSTALAR / DESINSTALAR / LIMPIAR CACHÉ
USANDO DRUSH O DRUPAL CONSOLE
drush en workshop_forms
drush cr
drush pmu workshop_forms
drupal moi workshop_forms
drupal mou workshop_forms
22. INYECCIÓN DE DEPENDENCIAS EN DRUPAL
8, QUÉ ES UN SERVICIO
Dependency Injection (DI) es un patrón de diseño orientado a objetos, en el que se suministran objetos a
una clase en lugar de ser la propia clase la que cree dichos objetos. Nuestras clases no crean los objetos, sino
que se los suministra otra clase ‘contenedora’ que inyectará la implementación deseada. (Wikipedia).
Un Service Container (o Dependency Injection container) es un objeto PHP que administra instancias de
servicios (otros objetos).
Un Servicio, es en sí mismo una clase que cumple una única responsabilidad, generada de manera única para
un contexto concreto (Singleton).
// Antes:
$servicio = new FooMehBah;
$servicio = FooMehBah::getInstance();
22
https://www.drupal.org/docs/8/api/services-and-dependency-injection
https://symfony.com/doc/current/components/dependency_injection.html
https://www.drupal.org/docs/8/api/services-and-dependency-injection/dependency-injection-for-a-form
// Ahora:
$container = $this->getContainer();
$servicio= $container->get('foo.meh.bah');
23. INYECCIÓN DE DEPENDENCIAS EN DRUPAL
8, USO DE SERVICIOS
DECLARANDO SERVICIOS
services:
ban.ip_manager:
class: DrupalbanBanIpManager
arguments: ['@database']
tags:
- { name: backend_overridable }
ban.middleware:
class: DrupalbanBanMiddleware
arguments: ['@ban.ip_manager']
tags:
- { name: http_middleware, priority: 250 }
USANDO SERVICIOS DINÁMICAMENTE
private $database;
private $current_user;
public function __construct( Connection $database,
AccountProxyInterface $current_user ) {
$this->database = $database;
$this->current_user = $current_user;
}
public static function create(ContainerInterface $container) {
return new static(
$container->get('database'),
$container->get('current_user'),
);
}
USANDO SERVICIOS ESTÁTICAMENTE
Drupal::service('module_installer')->uninstall(['action']);
Drupal::messenger()->addMessage(‘Message to print’);
$user = Drupal::currentUser(); 23
SERVICIOS DISPONIBLE EN CORE
CORE.SERVICES.YML
25. public function validateForm(array &$form, FormStateInterface $form_state) {
// Get the email value from the field.
$mail = $form_state->getValue('email');
// Test the format of the email.
if(!$this->email_validator->isValid($mail)) {
$form_state->setErrorByName('email', $this->t('The %email is not valid email.', ['%email' => $mail]));
}
}
PREFILLING DE VALORES EN CAMPOS
25
9, USOS DE SERVICIOS
ADEMÁS DE CAMPOS DE FORMULARIO
PODEMOS USARLOS EN TODA LA CLASE
26. composer require drupal/devel
exec drush en devel devel_generate
exec drush genc 10 5 --types=article
CONSULTAS DINÁMICAS A LA BASE DE DATOS
26
10, PREPARANDO NODOS
INSTALAMOS Y HABILITAMOS DEVEL
GENERAMOS CONTENIDO
27. // Build the base query.
$query = $this->database->select('comment_field_data', 'c')
->fields('c')
->condition('c.uid', $this->currentUser->id(), '=');
// Get the number of registers.
$query_counter = $query->countQuery();
$result = $query_counter->execute();
$count = $result->fetchField();
// Using the count value for prefilling the value.
$form['number_comments'] = [
'#type' => 'number',
'#value' => $count,
'#title' => $this->t('Number of Comments'),
'#description' => $this->t('Number of Coments'),
'#weight' => 3,
];
CONSULTAS DINÁMICAS A BASE DE DATOS
27
10, CONSULTA Y CARGA
EN DRUPAL PODEMOS USAR
CONSULTAS ESTÁTICAS O DINÁMICAS
// Consultas estáticas.
$database = Drupal::database();
$query = $database->query("SELECT id,
example FROM {mytable}");
$result = $query->fetchAll();
https://www.drupal.org/docs/8/api/datab
ase-api/static-queries
28. $options = node_type_get_names();
$defaults = array_keys($options);
$form['types'] = [
'#type' => 'checkboxes',
'#title' => $this->t('Content Types'),
'#description' => $this->t('Select Content
Types'),
'#options' => $options,
'#default_value' => $defaults,
'#weight' => '4',
];
PREFILLING DE VALORES EN CAMPOS
28
9, OTROS ORÍGENES
Hemos visto cómo precargar valores en
campos a lo largo de diversos ejemplos
para nuestros campos de formulario
basado en la Form API de Drupal:
hemos usado servicios bajo el modelo de
Inyección de Dependencias (DI) de
Symfony y también hemos realizado
consultas directas a la base de datos
través de la Database API de Drupal.
Ahora veremos otro origen de datos más a
partir del que podemos extraer
información: simples funciones
pre-existentes.
29. FORMULARIOS EN DRUPAL
29
6, ALTERANDO EL FORM
if(!$this->current_user->isAuthenticated()) {
$form['help'] = [
'#type' => 'item',
'#title' => $this->t('Please, read the conditions.'),
'#markup' => $this->t('<strong>Only for registered users.</strong>'),
];
}else {
$form['email'] = [
'#type' => 'email',
'#value' =>
$this->current_user->getEmail(),
'#title' => $this->t('Email'),
'#description' => $this->t('User email'),
'#weight' => '2',
];
$form['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Submit'),
'#weight' => 5,
];
}
No debemos perder de vista que en realidad, nunca nos hemos movido del contexto propio de
una Clase PHP y un método buildForm(). Así que vamos a jugar con algunas cláusulas if - else.
31. INYECCIÓN DE DEPENDENCIAS EN DRUPAL
31
public function validateForm(array &$form, FormStateInterface $form_state) {
// Get the email value from the field.
$mail = $form_state->getValue('email');
// Test the format of the email.
if(!$this->email_validator->isValid($mail)) {
$form_state->setErrorByName('email', $this->t('The %email is not a valid email.', ['%email' => $mail]));
}
}
public function submitForm(array &$form, FormStateInterface $form_state) {
// Display result in submit.
foreach ($form_state->getValues() as $key => $value) {
Drupal::messenger()->addMessage($key . ': ' . ($key === 'text_format'?$value['value']:$value));
}
}
INYECCIÓN DE DEPENDENCIAS EN DRUPAL
8, VALIDACIÓN GLOBAL
USAR SERVICIOS PARA VALIDACIONES
EN MÉTODOS VALIDATEFORM O SUBMIT
32. $form['titulo'] = [
'#type' => 'textfield',
'#title' => $this->t('Título'),
'#description' => $this->t('Titulo en el formulario.'),
'#required' => TRUE,
'#weight' => '0',
'#element_validate' => ['::titleCustomValidation'],
];
public function titleCustomValidation($element, FormStateInterface $form_state) {
// Insert new custom conditions for valitions in the ‘titulo’ field.
$form_state->setErrorByName('titulo', $this->t($error_message));
}
PREFILLING DE VALORES EN CAMPOS
32
INYECCIÓN DE DEPENDENCIAS EN DRUPALINYECCIÓN DE DEPENDENCIAS EN DRUPAL
8, VALIDACIÓN CUSTOM
ES POSIBLE USAR VALIDACIONES CUSTOM
ESPECÍFICAS PARA CADA CAMPO DE FORM
33. Modo interactivo
drupal generate:module
drupal gm
COMANDOS ÚTILES EN DRUPAL
33
7, CREAR MÓDULOS
CREACIÓN AUTOMÁTICA
USANDO DRUPAL CONSOLE
Modo no interactivo
drupal generate:module
--module="My Random module"
--machine-name="my_random_module"
--module-path="modules/custom"
--description="Random generated custom module"
--core="8.x"
--package="Custom"
--module-file
--no-interaction
36. “Hacia rutas salvajes” (Routing en Drupal 8) by @jansete
https://docs.google.com/presentation/d/17KVjfmgMtIIIDl0N40Vm1iyaUBg27mGE1hV2byIR4OM/edit
“Structure of routes” (Drupal 8 documentation)
https://www.drupal.org/docs/8/api/routing-system/structure-of-routes
Let’s take the best route - Exploring Drupal 8 routing system
https://www.srijan.net/blog/exploring-drupal-8-routing-system
Using Links in Drupal 8
https://davidjguru.github.io/blog/drupal-fast-tips-using-links-in-drupal-8
Formularios en Drupal 8 (Crear formularios, modificar formularios, ejemplos con Hooks)
https://medium.com/drupal-y-yo/form-api-i-comprender-crear-y-modificar-formularios-en-drupal-8-22c0cf4d72d3
https://medium.com/drupal-y-yo/form-api-ii-modificando-formularios-en-drupal-8-mediante-form-alter-78fa949b43d0
https://medium.com/drupal-y-yo/form-api-iii-caso-pr%C3%A1ctico-de-modificaci%C3%B3n-de-formulario-en-drupal-8-f8ab4dd40a5c
Prefilling fields in forms (Precargando campos en formularios)
https://davidjguru.github.io/blog/drupal-fast-tips-prefilling-fields-in-forms
LECTURAS RECOMENDADAS
36
11, AMPLIA INFORMACIÓN