D8 Formularios Avanzado - pierregermain/MyDrupal GitHub Wiki
Páginas relacionadas:
Índice:
- Formularios de configuración
- Mofificar otros Formularios
- Propiedades de Formularios
- #element_validate
- Añadir botones adicionales tipo submit
- Añadir un valores por defecto a un nodo y guardarlo en DB
- Control de acceso a elementos de formulario
- Formulario de confirmación
- Cargar Formularios sin ruta
- Creación de Formularios con drupal console
- Agregar un Submit y Validate a un Form
Formularios normales heredan de FormBase, los de configuración heredan de ConfigFormBase que nos permite disponer del objeto $config de forma fácil.
Pasos para generar un formulario de configuración
my_module_forms.settings:
path: '/admin/config/development/my_module'
defaults:
_form: '\Drupal\my_module_forms\Form\my_moduleSettingsForm'
_title: 'my_module Forms'
requirements:
_permission: 'my_module form access'
my_module_forms.settings:
title: my_module Forms Settings
route_name: my_module_forms.settings
parent: system.admin_config_development
description: 'Configuration form example.'
my_module form access:
title: 'my_module form access'
description: 'Access form'
Añadimos lo siguiente al *.info.yml de nuestro módulo para poder tener un link de "configure" en el listado de los módulos.
configure: my_module_forms.settings
message: 'Default message'
allowed_types:
- page
- article
Consideraciones importantes:
-
Hay que definir getEditableConfigNames() para devolver el nombre del fichero de configuración
-
Para escribir/leer configuraciones usamos:
-
En los nombres de elementos del formulario, añadiremos como prefijo el nombre del módulo
$config = $this->config('my_module_forms.settings'); $config->get('allowed_types'); $config->set('allowed_types', $allowed_types);
-
no es necesario añadir el botón de Sumit.
<?php
namespace Drupal\my_module_forms\Form;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
class my_moduleSettingsForm extends ConfigFormBase {
public function getFormId() {
return 'my_module_forms_admin_settings';
}
protected function getEditableConfigNames() {
return [
'my_module_forms.settings'
];
}
public function buildForm(array $form, FormStateInterface $form_state) {
$config = $this->config('my_module_forms.settings');
// Listado con todos los tipos de contenido
$types = node_type_get_names();
$form['my_module_forms_allowed_types'] = [
'#type' => 'checkboxes',
'#title' => $this->t('Content types allowed'),
'#default_value' => $config->get('allowed_types'),
'#options' => $types,
'#description' => $this->t('Select content types.'),
'#required' => TRUE,
];
$form['my_module_forms_message'] = [
'#type' => 'textarea',
'#title' => t('Message'),
'#cols' => 60,
'#rows' => 5,
'#default_value' => $config->get('message'),
];
return parent::buildForm($form, $form_state);
}
public function validateForm(array &$form, FormStateInterface $form_state) {
parent::validateForm($form, $form_state);
}
public function submitForm(array &$form, FormStateInterface $form_state) {
$allowed_types =
array_filter($form_state->getValue('my_module_forms_allowed_types'));
sort($allowed_types);
$this->config('my_module_forms.settings')
->set('allowed_types', $allowed_types)
->set('message', $form_state->getValue('my_module_forms_message'))
->save();
parent::submitForm($form, $form_state);
}
}
/**
* Implements hook_form_alter.
*/
function my_module_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
dpm($form_id);
// Nos da el id para usar el hook siguiente
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function my_module_forms_form_system_site_information_settings_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
dpm($form);
$form['site_information']['site_slogan']['#required'] = TRUE;
}
function my_module_form_alter(&$form,
\Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
switch($form_id){
case 'system_site_information_settings':
$form['site_information']['site_slogan']['#required'] = TRUE;
break;
case 'node_page_form':
case 'node_page_edit_form':
// Abre el grupo de opciones
$form['options']['#open'] = TRUE;
// Añadir un nuevo elemento llamado highlighted
$form['options']['highlighted'] = [
'#type' => 'checkbox',
'#title' => t('Highlighted'),
'#weight' => 100,
];
break;
}
}
Primero averiguamos el BASE FORM desde el form_alter.
$form_state->getBuildInfo()['base_form_id'];
// Para nodos por ejemplo nos da
// "node_form"
Una vez averiguado usamos el hook_form_BASE_FORM_ID_alter
/**
* Implements hook_form_BASE_FORM_ID_alter() for node_form.
*/
function my_module_form_node_form_alter(&$form,
\Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
$form['options']['#open'] = TRUE;
$form['options']['highlighted'] = [
'#type' => 'checkbox',
'#title' => t('Highlighted'),
'#weight' => 100,
];
}
Estas propiedades se aplican directamente al formulario (array $form
).
siempre es form
es el id del form
indica el método del submit del form, por defecto es "post".
$form['#attributes']['class']= ['node-article-form', 'node-form'];
$form['#attributes']['style'] = 'color:#DDD; font-size: 12px;';
$form['#validate'][] = '::validateForm';
$form['#submit'][] = '::submitForm';
public function buildForm(array $form, FormStateInterface $form_state) {
$form['#validate'][] = '::customValidateForm';
$form['#submit'][] = '::customSubmitForm';
// ...
}
public function customValidateForm(array &$form,
FormStateInterface $form_state) {
// ...
}
public function customSubmitForm(array &$form,
FormStateInterface $form_state) {
// ...
}
$form['#submit'][] = 'contact_form_user_admin_settings_submit';
- No es una propiedad de $form sino de un elemento del $form.
- Sirve para validar cada elemento por separado sin usar la función validate.
Referencia hacia funciones externas:
$form['pattern_container']['pattern'] = [
'#type' => 'textfield',
'#title' => 'Path pattern',
'#default_value' => $this->entity->getPattern(),
'#size' => 65,
'#maxlength' => 1280,
'#element_validate' => [
'token_element_validate',
'pathauto_pattern_validate'
],
];
Referencia hacia funciones internas de la clase:
$form['foo'] = [
'#title' => 'Test foo',
'#type' => 'textfield',
'#element_validate' => ['::elementCustomValidation'],
];
$form['foo'] = [
'#title' => 'Test foo',
'#type' => 'textfield',
'#element_validate' => [
[get_class($this), 'elementCustomValidation'],
],
];
Ahora definimos la función
public function elementCustomValidation($element, FormStateInterface $form_state) {
if ($element['#value'] == 'invalid') {
$form_state->setError($element, t('@label element is invalid', ['@label' => $element['#title']]));
}
}
(...)
Pasos:
- Crear tabla en db con un nuevo $schema['nombre_tabla'] que tenga las columnas 'nid' y 'nuevo_campo'
- Desde el hook_form_alter obtener el $nid usando
$nid = $form_state->getFormObject()->getEntity()->id();
- Hacer una query en el hook_form_alter contra la tabla creada y obtener el valor
$highlighted = $connection->select('my_table', 'f') ->fields('f', ['highlighted']) ->condition('f.nid', $nid) ->execute() ->fetchField();
- Asignar el valor usando
'#default_value' => $nuevo_campo,
- Crear un nuevo custom submit que meta el valor en la 'nombre_tabla'
- Desde el hook_form_alter agregar el nuevo submit usando
$form['actions']['submit']['#submit'][] = 'nombre_modulo_custom_submit';
// Desde Clase Form POO
$access = $this->currentUser()->hasPermission('my_module form access');
// Desde hook_form_alter
$access = \Drupal::currentUser()->hasPermission('my_module form access');
$form['foo']['#access'] = $access;
Lo hacemos desde el fichero de routing
- Lo hacemos con la propiedad
#access_callback
. - Sólo se ejecuta si no existe la propiedad
#access
.
$form['user_email'] = [
'#type' => 'email',
'#title' => $this->t('User email'),
'#description' => $this->t('Your email.'),
'#access_callback' => ['Drupal\my_module\Form\Simple','checkEmailAccess'],
];
(...)
public function checkEmailAccess($element) {
$currentUser = \Drupal::currentUser();
return ($currentUser->id() != 1) &&
$currentUser->hasPermission('my_module form access');
}
- Extienden de ConfirmFormBase
- Deben implementar los siguientes métodos:
- getQuestion(). Devuelve la pregunta de confirmación.
- getConfirmText(). Devuelve el título del botón de confirmación.
- getCancelText(). Devuelve el título del botón de cancelación.
- getCancelUrl().
Pasos:
- Crear el routing
my_module.confirm:
path: '/my_module/forms/confirm/{node}'
defaults:
_form: '\Drupal\my_module\Form\ConfirmForm'
_title: 'Confirm Form'
requirements:
_permission: 'my_module form access'
- Crear la clase
<?php
namespace Drupal\my_module_forms\Form;
use Drupal\Core\Database\Connection;
use Drupal\Core\Url;
use Drupal\Core\Form\ConfirmFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\node\NodeInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class my_moduleConfirmForm extends ConfirmFormBase {
protected $database;
protected $node;
public function __construct(Connection $database) {
$this->database = $database;
}
public static function create(ContainerInterface $container) {
return new static(
$container->get('database')
);
}
public function getFormId() {
return 'my_module_forms_confirm';
}
public function buildForm(array $form,
FormStateInterface $form_state,
NodeInterface $node = NULL) {
$this->node = $node;
return parent::buildForm($form, $form_state);
}
public function getQuestion() {
return $this->t('Are you sure you want to delete node "%title"
(%nid) from <em>my_module_node_highlighted</em> table?',
array('%title' => $this->node->getTitle(), '%nid' => $this->node->id()));
}
public function getConfirmText() {
return $this->t('Delete');
}
public function getCancelText() {
return $this->t('Don\'t Delete');
}
public function getCancelUrl() {
return new Url('<front>');
}
public function submitForm(array &$form,
FormStateInterface $form_state) {
$this->database->delete('my_module_node_highlighted')
->condition('nid', $this->node->id())
->execute();
\Drupal::messenger()->addStatus(t('The node has been removed'));
\Drupal::logger('my_module_forms')->notice(t('Node %nid has been deleted from custom table.'),
[
'%nid' => $this->node->id(),
]);
$form_state->setRedirectUrl($this->getCancelUrl());
}
}
$form = \Drupal::formBuilder()->getForm('Drupal\my_module\Form\Simple');
$form = \Drupal::formBuilder()
->getForm('Drupal\my_module\Form\ForcontuConfirmForm',
$node);
// ..
public function construct (FormBuilderInterface $form_builder) {
$this->formBuilder = $form_builder;
}
public static function create(...){
// ..
$container->get('form_builder')
// ..
}
//..
$form =$this->formBuilder->getForm(
drupal generate:form:config
drupal generate:form:alter
<?php
/*
* Implements hook_form_alter
*/
use Drupal\Core\Form\FormStateInterface;
use Symfony\Components\HttpFoundation\Request;
function mymodule_form_alter(&$form, FormStateInterface $form_state, $form_id) {
if ($form_id == 'my_form_id' {
// custom validate
$form['#validate'][] = 'mymodule_custom_validate';
// custom submit
$form['actions'][$action]['#submit'][] = 'mymodule_custom_submit';
}
}
// Validate Form
function mymodule_custom_validate($form, FormStateInterface &$form_state) {
// ...
}
// Submit Form
function mymodule_custom_validate(&$form, FormStateInterface &$form_state) {
// ...
}
public function messages() {
//...
$result = $query->execute();
$rows = [];
$build['forcontu_messages_table'] = [
'#type' => 'table',
'#header' => ['nid', 'title', 'active', 'message', 'operations','operations POO'],
];
foreach ($result as $record) {
//dpm($record);
// Nid y Title
$nid = $record->nid;
$node_storage = \Drupal::entityTypeManager()->getStorage('node');
$node = $node = $node_storage->load($nid);
$title = $node->get('title')->value;
$operations = "<a href='/node/".$nid."/edit/'>Edit</a> <a href='/admin/structure/forcontu-pec-message/delete/".$nid."'>Delete</a>";
$rows[] = [
$nid,
$title,
$record->checked,
$record->message,
Markup::create($operations),
$this->renderDropbutton($nid),
];
}
$build['forcontu_messages_table']['#rows'] = $rows;
return $build;
}
public function renderDropbutton($nid) {
$operations =
[
'#type' => 'dropbutton',
'#links' => [
'edit' => [
'title' => 'Edit',
'url' => Url::fromRoute('entity.node.edit_form', ['node' => $nid]),
],
'delete' => [
'title' => 'Delete',
'url' => Url::fromRoute('mymodule.delete', ['node' => $nid]),
],
],
];
return \Drupal::service('renderer')->render($operations);
}