Continuando con la serie de tutoriales de iniciación a Symfony, vengo aquí con otra de las mejores cosas que tiene Symfony. Esta vez se trata del manejo y creación de los formularios. Podríamos seguir creando formularios a la antigua, mediante HTML, construyendo poco a poco dichos formularios. Pero si quieres ser realmente productivo construyendo aplicaciones que gestionan mucha información, interactuando con los usuarios, deberías de usar ésta herramienta y aprovechar lo que Symfony nos ofrece.
Es decir, tenemos un componente de Symfony que automatiza gran parte de la creación, y recepción de los datos de formularios. Les puedes añadir fácilmente tokens de seguridad, generar formularios responsivos con Bootstrap de forma automática, generarlos automáticamente a partir de la definición de la base de datos, y un largo muy largo etcétera.
Un poco de teoría sobre formularios
De forma tradicional, los formularios se defininen mediante HTML, CSS y Javascript. Y se reciben los datos en el servidor mediante PHP para nuestro caso.
Mediante el componente symfony/form gran parte de la generación de formularios se hace en el servidor. Es decir, con Symfony deberíamos de tener en PHP la generación del formulario. Este formulario se lo pasamos a la plantilla Twig como un objeto en donde lo pintamos. Si lo hacemos así nos ahorramos el generar todo el HTML, CSS y Javascript que antes teníamos que hacer. Incluso si usamos la plantilla Bootstrap para los formularios haremos que esta generación sea responsiva. Y para rizar el rizo, tenemos un montón de validaciones automáticas de los campos.
Es decir, con Symfony deberíamos de tener en PHP la generación del formulario.
Me repito más que el ajo, podemos seguir trabajando los formularios a la antigua, pero estaríamos sacrificando una de las herramientas de Symfony que más productividad te puede dar a la hora de crear aplicaciones web.
Y además, para la recepción de formularios mediante Symfony, tenemos una serie de funciones que nos harán más fácil la vida. Podemos recibir automáticamente los datos en un objeto si así lo queremos, y hasta comprobar si es válido el formulario, devolviendo los errores definidos mediante las asserts.
Un ejemplo de estudio, para trabajar los formularios
Es más fácil verlo con un ejemplo, que explicar los muchos casos. Imaginemos que creamos una aplicación para gestionar una agenda de contactos. Creamos el proyecto:
symfony new symfony-tutorial-11 cd symfony-tutorial-11 composer require --dev maker composer require doctrine twig form validator security-csrf annotations
Y creamos una entidad que llamamos Contact:
php bin/console make:entity Contact
Respondiendo a lo que nos pregunta el generador de código de Symfony desde línea de comando, creo los siguientes campos para la entidad Contact:
- Name: de tipo string de 255 caracteres.
- Email: de tipo string de 255 caracteres.
- PhoneNumber: de tipo string de 255 caracteres.
- Observations: de tipo text.
Con todo esto se nos generarán los ficheros src/Entity/Contact.php y src/Repository/ContactRepository.php con todo el código fuente. Lo siguiente que propongo es usar el generador de CRUDs, ya que una de las cosas que crea es el formulario, junto con el controlador y todas las acciones de guardado. Ejecutamos:
php bin/console make:crud Contact
Y se nos generarán automáticamente los siguientes ficheros:
created: src/Controller/ContactController.php
created: src/Form/ContactType.php
created: templates/contact/_delete_form.html.twig
created: templates/contact/_form.html.twig
created: templates/contact/edit.html.twig
created: templates/contact/index.html.twig
created: templates/contact/new.html.twig
created: templates/contact/show.html.twig
Ahora podemos arrancar la nueva agenda de contactos para probarla haciendo:
symfony server:start
Tenemos que crear la base de datos para poder usar esta agenda así que configuramos nuestro fichero .env del proyecto, le ponemos conexión a la BD y luego hacemos hacemos esto:
php bin/console doctrine:database:create php bin/console doctrine:schema:create
Ahora ya podemos conectar al servidor local en: http://127.0.0.1:8000/contact Y podremos probar nuestra nueva agenda de contactos. Podremos crear nuevos contactos, listarlos, editarlos o borrarlos, que son las cuatro acciones CRUD.
Poniendo bonitos los formularios, haciéndolos responsivos
Como éste post va sobre formularios, vamos a centrarnos sólo en la pantalla de creación de nuevo contacto. Lo ideal sería hacer un layout molón para toda la aplicación web, definir cabeceras, pies, menús, etc.. Así que sólo usaremos esta ruta: http://127.0.0.1:8000/contact/new
Le vamos a añadir Bootstrap, jQuery y vemos qué tal queda.. Para esto editamos el fichero templates/base.html.twig y lo dejamos así:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{% block title %}Welcome!{% endblock %}</title>
{% block stylesheets %}{% endblock %}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>
</head>
<body class="container">
{% block body %}{% endblock %}
{% block javascripts %}{% endblock %}
</body>
</html>
Marco en negrita lo que he modificado. Lo siguiente es editar la configuración de Twig, para que renderice los formularios usando el tema de Bootstrap. Para esto editamos el fichero config/packages/twig.yaml y le ponemos la siguiente línea marcada en negrita:
twig:
form_themes: ['bootstrap_4_layout.html.twig']
Si todo ha ido bien, ya tenemos que ver por pantalla el siguiente formulario en la dirección http://127.0.0.1:8000/contact/new
Ya tenemos un CRUD completo responsivo, en pocos minutos, en una aplicación web para gestionar nuestra agenda de contactos. Notarás que hay muchos detalles que mejorar, pero también notarás que en unos minutos nos hemos ahorrado, probablemente horas, de haberlo hecho todo esto con HTML, CSS, Javascript y PHP a pelo.
El controlador, la recepción del formulario
Ahora viene mucha de la magia de Symfony en todo esto de los formularios. En este ejemplo hemos usado una entidad como base del formulario. De esta forma que ya hemos visto toda la parte de programación de cliente. Vamos ahora con la parte de programación de servidor.
Abriendo el controlador que hemos generado automáticamente, nos sirve de guia para crear cualquier otro manejo de formularios. Siempre se hace igual, o parecido. Vamos a la función de esta pantalla, que es la de la función new, para crear un nuevo contacto en la agenda. Abrimos el fichero src/Controller/ContactController.php y veremos esto:
/**
* @Route("/new", name="contact_new", methods={"GET","POST"})
*/
public function new(Request $request): Response
{
// Recibe los datos del formulario
// y los carga en un objeto de tipo Contact.
$contact = new Contact();
$form = $this->createForm(ContactType::class, $contact);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// Si el formulario se ha enviado y es válido
// guarda los datos del contacto en la BD.
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($contact);
$entityManager->flush();
// Redirige al listado de contactos.
return $this->redirectToRoute('contact_index');
}
// Te lleva al formulario de nuevo contacto.
return $this->render('contact/new.html.twig', [
'contact' => $contact,
'form' => $form->createView(),
]);
}
Marco en negrita lo que es la recepción del formulario en PHP. Esas tres líneas te generan un objeto de tipo Contact con todos sus datos tal y como los hemos definido.
La definición del formulario
Lo siguiente para ver cómo funcionan los formularios son las clases que los definen. En esta versión de Symfony tendremos nuestros formularios bajo el directorio src/Form/ y todos tendrán la nomenclatura NombreFormularioType.php. Siguiendo el post del ejemplo si abrimos el fichero src/Form/ContactType.php veremos esto:
<?php
namespace App\Form;
use App\Entity\Contact;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ContactType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('email')
->add('phoneNumber')
->add('observations')
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Contact::class,
]);
}
}
Las dos líneas que he marcado en negrita son las que hacen que este formulario cargue o llene una entidad de Doctrine. Sí, así de sencillo. Más bien dicho así de sencillo no, porque esto es el principio. En la función buildForm es donde tenemos la mayoría de las configuraciones que harán muchas cosas en el pintado del formulario.
Configurando los campos de formulario
Esto se puede hacer de dos formas, en la definición del formulario en PHP y/o en la plantilla de Twig. Por ejemplo podríamos definir un campo de la forma:
->add('nombreCampo', ChoiceType::class, [
'label' => 'Etiqueta del campo',
'choices' => [
'Opción 1' => 'valor1',
'Opción 2' => 'valor2',
],
'help' => 'Esto es el texto que sale debajo de la caja.',
])
Marco en negrita la ayuda, que es un pequeño gran detalle nuevo que la verdad que ayuda mucho y en Symfony 2 y 3 no lo tuvimos.
En el Twig, curioseando un poco más la generación del formulario en las plantillas, podríamos ver un formulario definido como el siguiente:
{{ form(form) }}
Sí, con sólo una línea en el Twig, quedaría pintado todo el formulario en la plantilla. Pero si quisiéramos desglosarlo un poco más, podríamos tener un formulario más definido como el siguiente:
{{ form_start(form, {'attr':{'onsubmit': 'saveWithSearchedLocation()'}}) }}
{{ form_row(form.imageFile) }}
{{ form_row(form.publicPhoneNumber, {'attr': {'value' : app.user.publicPhoneNumber}}) }}
{{ form_end(form) }}
Ésto se podría desglosar más aún, de forma que cada row podríamos desglosarla en el Twig usando las siguientes funciones:
{{ form_label(form.publicPhoneNumber) }}
{{ form_errors(form.publicPhoneNumber) }}
{{ form_widget(form.publicPhoneNumber) }}
{{ form_help(form.publicPhoneNumber }}
Los formularios de Symfony son una de las herramientas más potentes, para ser muy productivos en el desarrollo web, que he visto. Así que mejor me remito a la documentación oficial para escudriñar cada campo, y dejo aquí esto como una breve introducción.
Terminando
Ya me estoy extendiendo demasiado en este post, de nuevo. Así que para no aburrirte más, si es que has llegado hasta aquí, me queda citar dos cosas muy interesantes: los asserts y un par de componentes que mejoran los formularios enormemente.
Los asserts son una serie de validaciones que le pones en las entidad asociada a un formulario. Las pones como comentarios en annotations del fichero de la entidad. Es muy potente porque configuras esto y Symfony se encarga también de hacer la validación y mostrar los errores en el frontend al usuario. ¡Una maravilla! Con esto te ahorras también horas y horas.
Los dos componentes que tengo en mente para los que hayan llegado hasta aquí abajo, y tengan ganas de curiosear un poco, son el CKEditor y el VichUploader. Con el CKEditor puedes tener un campo de formulario que sea un área de texto en forma de editor WYSIWYG. El VichUploader es para hacer un campo de formulario que sea un fichero para subir al servidor.
Recapitulando, con el componente de formularios (y algunas vitaminas en forma de módulos extra) te puedes ahorrar horas y horas de árduo trabajo, además de que serás mucho más productivo creando webs con formularios.
Sólo me queda remitirte a la documentación oficial sobre formularios aquí:
https://symfony.com/doc/current/forms.html
..al índice de la serie de tutoriales aquí:
https://jnjsite.com/tutoriales-para-aprender-symfony/
..al siguiente post sobre los emails en Symfony:
https://jnjsite.com/symfony-tutorial-12-los-emails/
..y a los códigos fuentes subidos a GitHub aquí:
https://github.com/jaimenj/symfony-starter-tutorials
Otro día más, aquí que lo dejo y en breve me voy al sobre.. ¡Un saludo!
Buenas
Mira estoy trabajando con formularios generados de la misma forma es decir a traves de una entidad y de forma automática generando un crud, el problema es que necesito que varios input sean de tipo textArea y no text y no me a pasado como a ti que te sale de forma automatico, o al menos eso he entendido, estoy buscando y ponen que tengo que utilizar una clase, lo introduzco y me salen cascazos, alguna sugerencia????
https://symfony.com/doc/current/reference/forms/types/textarea.html
Hola Álvaro!
Para que sea de tipo área de texto necesitas que el campo sea de tipo texto. Por ejemplo, una entity que se llama CoreConfig, su fichero sería src\App\Entity\CoreConfig.php con esta definición de un par de campos:
/**
* @ORM\Column(type=»string», length=255)
*/
private $code;
/**
* @ORM\Column(type=»text»)
*/
private $value;
…generará para el campo $value un área de texto. Si quieres definir en el fichero NombreEntidadType.php el tipo de campo, lo puedes hacer así por ejemplo:
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
class CoreConfigType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(‘code’, TextType::class, [
‘label’ => ‘Código’,
])
->add(‘value’, TextareaType::class, [
‘label’ => ‘Valor’,
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
‘data_class’ => CoreConfig::class,
]);
}
}
Espero que sirva, habría que ver tus códigos para decirte más.
Saludos.
Muchas gracias, funciona perfectamente, pues en blogs comentaban de crear una clase y en form meter mil historias, asi es muy facil, que sepas que tengo este blog en mis favoritos, lo explicas muy bien.
Genial! No hay de qué, muchas gracias a ti por los comentarios.
hola que genialidad un saludo
¡Hola Rossel! Muchas gracias por el comentario.