Biblioteca Online : ¡La Suscripción ENI por 9,90 € el primer mes!, con el código PRIMER9. Pulse aquí
¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
  1. Libros
  2. Symfony 5
  3. Formularios
Extrait - Symfony 5 Desarrolle sitios web PHP estructurados y eficientes
Extractos del libro
Symfony 5 Desarrolle sitios web PHP estructurados y eficientes Volver a la página de compra del libro

Formularios

Un componente MVC

Los formularios son elementos esenciales de los sitios web: constituyen la manera principal que utilizan los usuarios para interactuar con la aplicación.

Se muestran en las páginas (capa Vista) y, una vez enviados, normalmente se utilizan para modificar datos (capa Modelo), todo ello orquestado por el controlador.

Encontramos, pues, a los protagonistas de nuestro famoso patrón de diseño MVC (consulte Arquitectura del framework - El modelo de diseño MVC).

Esta particularidad hace que el componente «Form» de Symfony no sea el más difícil de aprender, pero sí uno de los más completos. Además, para entender mejor este capítulo, es necesario dominar el Contralor y Twig.

1. El modelo

En su uso más común, los formularios permiten interactuar con la capa Modelo (aunque el componente puede trabajar con tablas). Por lo tanto, los «objetivos» de los formularios son objetos.

Imagine una clase que representa a un cliente:

<?php  
namespace App\Model;   
   
class Cliente   
{   
   private $nombre;   
   private $fechaDeNacimiento;   
   
   public function setNombre($nombre)   
   {   
       $this->nombre...

Funcionamiento del componente

1. El objeto «Form»

El objeto Form es el elemento principal utilizado a nivel de controlador. En el ejemplo anterior, está contenido en la variable $form. Representa el conjunto de campos del formulario en forma jerárquica.

Este es el punto central alrededor del que gira todo. El objeto que representa la consulta HTTP o el objeto de la capa Modelo, se «inyecta» en él. Las tareas de procesamiento típicas (como administrar el envío, validar o crear la vista de formulario) también se realizan a través de este objeto Form.

a. Envío (submit)

El objeto Form tiene un método llamado handleRequest(), que recibe como parámetro el objeto Request (la consulta HTTP actual). Este método es capaz de realizar introspección.

De esta introspección surgirá una conclusión, a saber, una respuesta a la siguiente pregunta: durante la consulta HTTP actual, ¿el usuario envía el formulario o solo lo muestra?

Si se está enviando (normalmente esta acción se reconoce porque el método de consulta HTTP actual es de tipo POST), los datos publicados se adjuntan al formulario y el objeto de la capa Modelo también se actualiza (siempre que los datos introducidos por el usuario sean válidos; veremos esto con más detalle más adelante).

De forma predeterminada, invocar el método handleRequest() equivaldría a:

if ($request->isMethod('POST')) {  
    $form->submit($request);  
} 

El método submit() permite adjuntar manualmente datos a un formulario.

b. Validación

El método isValid() permite saber si los valores enviados por el usuario son correctos, basándose en un conjunto de reglas (denominadas «restricciones») definidas por el desarrollador.

Estas reglas se pueden definir sobre la marcha, es decir, durante la creación del formulario o directamente en el objeto de la capa Modelo.

La validación se aborda en detalle más adelante en este capítulo.

c. Vista

Para terminar, un objeto especial, una «vista» del formulario, se puede recuperar del objeto Form utilizando su método createView(). Aquí no sería interesante entrar en detalles; solo es necesario saber que las templates necesitan este objeto especial...

Tipos de campos de formulario

El objetivo de esta sección del capítulo es darle una visión general de los diferentes tipos de campos de formulario y sus opciones. Esta no es de ninguna manera una lista exhaustiva, sino más bien una referencia básica para entender cómo funcionan estos campos.

Para encontrar la lista completa de tipos de campos de formulario y sus opciones, visite la página de documentación dedicada al componente «Form» en la dirección https://symfony.com/doc/5.4/reference/forms/types.html

1. Herencia

Antes de abordar los diferentes tipos y sus opciones, es necesario entender la herencia de estos.

Cada tipo puede heredar de un padre. En la práctica, casi todos los tipos utilizados con Symfony heredan del mismo tipo: FormType. Ya hemos usado este tipo indirectamente: por defecto, el «nodo» principal de la jerarquía del formulario es de tipo FormType.

En esta sección dedicada a los tipos, se especificará el padre de cada tipo. Esto le permitirá encontrar todas sus opciones. Si el tipo B tiene como padre A, entonces todas las opciones de A están disponibles cuando se usa B.

2. FormType

Este es un tipo bastante abstracto, que contiene opciones de configuración generales. La mayoría de las veces no lo usamos directamente, sino a través de sus muchos subtipos.

a. label

Esta opción especifica la etiqueta que se va a utilizar para el campo. Si esta opción no se indica, el framework hace todo lo posible para «adivinar» la etiqueta. Por ejemplo, un campo llamado fecha_de_nacimiento se etiquetará como Fecha de nacimiento.

b. label attr

Al pasar una tabla asociativa a esta opción, puede establecer atributos HTML para la etiqueta <label>.

c. data

Esta opción permite cambiar el valor predeterminado del campo.

Por ejemplo, para rellenar previamente un campo de tipo text (hereda de form) con un valor determinado, simplemente configure el tipo de la siguiente manera:

$formBuilder->add('campo', TextType::class, array(  
    'data' => 'Valor por defecto'  
)); 

d. required

Si esta opción vale true, el atributo required se agrega al campo.

Este atributo HTML5 especifica que el campo en cuestión se debe rellenar obligatoriamente y, hasta que se rellene...

Crear formularios reutilizables

Por ahora, hemos creado formularios directamente desde el controlador, gracias al FormBuilder. Sin embargo, una práctica recomendada es extraer la configuración de un formulario dentro de una clase dedicada. Esto permite una mejor claridad del código y, al mismo tiempo, hace que el formulario sea reutilizable.

1. Definir un formulario con la clase AbstractType

Para ello, necesitamos crear una clase que implemente la interfaz Symfony\Component\Form\FormTypeInterface. Para simplificar esta tarea, podemos usar la clase Symfony\Component\Form\AbstractType. Esta clase contiene varios métodos relacionados con la configuración de un formulario.

En realidad, y como hemos visto anteriormente, lo que entendemos por «formulario» simplemente es el nodo principal de una determinada arborescencia. A este respecto, la principal diferencia entre un formulario que permite modificar información sobre un cliente y un campo de tipo text es que el primero es un nodo con hijos, mientras que el segundo es un nodo simple. Por esta razón, para configurar un formulario dentro de una clase, definimos un tipo.

Esto puede resultar confuso, pero es muy importante entender el punto anterior porque tiene dos usos distintos para la clase AbstractType:

  • Configurar los formularios de una aplicación (registro de usuarios, realización de pedidos, etc.).

  • Configurar sus propios tipos para poder reutilizarlos en sus aplicaciones o ampliar los tipos nativos del framework para personalizarlos. Además, los tipos nativos de Symfony extienden esta misma clase y puede encontrarlos dentro del espacio de nombres Symfony\Component\Form\Extension\Core\Type.

El siguiente ejemplo contiene la configuración de un formulario para la información de contacto de un cliente:

<?php  
// src/Form/Type/ClienteType.php   
   
namespace App\Form\Type;   
   
use Symfony\Component\Form\AbstractType;   
use Symfony\Component\Form\FormBuilderInterface;   
use Symfony\Component\OptionsResolver\OptionsResolver;   
   
class ClienteType extends AbstractType   
{   
   public function buildForm(   
       FormBuilderInterface $builder,   
       array...

Validar los datos

1. Objetivos

Con Symfony, la validación es un componente que se puede utilizar de forma autónoma. Sin embargo, en la práctica, se usa principalmente para validar datos que provienen de formularios. Por esta razón lo abordamos en este capítulo.

Aquí nos referimos a la validación «en el lado del servidor». Es importante no confundirlo con la validación en el lado del cliente en HTML5.

Las opciones como required, o el hecho de utilizar un campo de tipo email, provocarán una validación a nivel del navegador, pero esto no se debe considerar fiable de ninguna manera. Es solo un complemento de la validación en el lado del servidor, ya que reduce las interacciones con el servidor al detectar errores antes del envío.

2. Definir restricciones de validación

Las restricciones de validación son un conjunto de reglas que se pueden aplicar a un valor. Estas reglas permiten garantizar que el valor se corresponda con uno o más criterios dados.

Concretamente, para un formulario de inscripción, por ejemplo, estas reglas podrían ser las siguientes:

  • El pseudo debe contener entre 3 y 20 caracteres.

  • La dirección de correo electrónico introducida debe ser válida.

  • Se deben introducir los nombres y los apellidos.

  • Etc.

Hay dos métodos para configurar las restricciones de un formulario:

  • A nivel del objeto de la capa Modelo asociada al formulario.

  • En los campos de formulario usando la opción constraints.

Configuremos la validación de un formulario de correo electrónico con ambos métodos. El formulario consta de los siguientes campos y reglas:

  • destinatario: campo de tipo email; su valor se debe completar y debe corresponder a un correo electrónico válido.

  • título: campo de tipo text; este valor es opcional.

  • mensaje: campo de tipo textArea; este campo es obligatorio.

  • elemento_adjunto: campo opcional de tipo file para un posible archivo adjunto. 

a. Añadir restricciones durante la configuración de un formulario

...  
use Symfony\Component\HttpFoundation\Request;   
use Symfony\Component\Form\Extension\Core\Type\EmailType;   
use Symfony\Component\Form\Extension\Core\Type\TextType;   
use Symfony\Component\Form\Extension\Core\Type\FileType;   
use Symfony\Component\Form\Extension\Core\Type\SubmitTyp   ...

Personalizar la representación: temas de formulario

El formulario se representa a nivel de la capa Vista. Al igual que sucede para la gestión de las templates, se puede utilizar con dos lenguajes: Twig y PHP. Aquí también nos centraremos en su uso a través de Twig.

Existen varios enfoques para personalizar la representación de un formulario, que van desde un control directo desde la template donde se muestra hasta procesos más automatizados con los «temas de formulario».

1. Ver el formulario manualmente

Por ahora, usamos el método Twig form() en el objeto FormView para mostrar un formulario:

{{ form(form) }} 

Esta sencilla función permite la visualización del formulario completo. Por lo tanto, es muy práctica, pero también muy restrictiva. De hecho, no ofrece ninguna posibilidad de control sobre la representación final.

El siguiente fragmento de código es equivalente a la función form():

{{ form_start(form) }}   
   
   {{ form_label(form) }}   
  
   {{ form_errors(form) }}   
   
   {{ form_widget(form) }}   
   
{{ form_end(form) }} 

Introduce nuevas funciones Twig relacionadas con la visualización de formularios: form_start(), form_label(), form_errors(), form_widget() y form_end()

a. form_start()

Esta función abre el formulario mostrando la etiqueta de apertura <form>.

Los principales atributos contenidos en esta etiqueta son action y method. El primero especifica la página a la que se debe enviar el formulario, mientras que el segundo especifica el método HTTP que se utilizará para la consulta.

Puede controlar estos atributos de diferentes maneras. En primer lugar, existen las opciones method y action, que se pueden pasar al formulario principal:

$form = $this->createForm(new BusquedaType(), null, array(  
    'action' => $this->generateUrl('buscar'),  
    'method' => 'GET',  
)); 

Aquí, el formulario está configurado para enviar los datos a través de una consulta de tipo...