Formulario de Contacto

Índice

2.0 ¿Qué aprenderemos?

  • A conectar con una base de datos
  • A generar entidades y repositorios
  • A generar formularios
  • A guardar los datos del formulario en la base de datos
  • A realizar validaciones en los campos
  • A personalizar los campos de los formularios

2.1 Base de datos

En esta parte del curso vamos a crear el formulario para que se puedan enviar mensajes.

image-20220316180158448

2.1.1 Conexión con la base de datos

Para crear la base de datos, hemos de modificar el archivo .env introduciendo los datos de conexión apropiados. En el caso de MySql es la siguiente:

1
DATABASE_URL="mysql://db_user:db_password@127.0.0.1:3306/blog?serverVersion=5.7&charset=utf8mb4"

Sustituyendo db_user y db_password por los valores apropiados y blog es el nombre de la base de datos.

Por ejemplo,

1
DATABASE_URL="mysql://root:sa@127.0.0.1:3306/blog?serverVersion=5.7&charset=utf8mb4"

Para crearla se usa el comando:

1
php bin/console doctrine:database:create

2.1.2 Creación de la entidad Contact

El primer paso para trabajar con la Base de Datos es definir la entidad en la que debemos almacenar los datos. En principio, una entidad equivale a una tabla en la base de datos. Para crearla usamos el siguiente comando:

1
php bin/console make:entity

Nos pedirá los nombres y atributos de los campos de la entidad:

Ahora ya sólo nos queda crear la tabla asociada en la base de datos mediante los siguientes comandos

1
php bin/console make:migration

Y por último aplicar la migración:

1
php bin/console doctrine:migrations:migrate

2.1.3 Clases Contact y ContactRepository

Al ejecutar el comando php bin/console make:entity Symfony ha creados dos archivos. Uno llamado App\Entity\Contact.php que almacena la definición de la entidad-tabla y otro llamado App\Repository\ContactRepository.php que es la clase encargada de realizar las tareas de base de datos relacionadas con la entidad Contact.

2.2 Formulario

Una vez hemos definido la entidad que va a almacenar los datos introducidos, vamos a crear el formulario. Symfony posee un comando que, automáticamente, crea un formulario a partir de la entidad subyacente.

1
php bin/console make:form ContactForm Contact

El código generado en Form\ContactFormType.php es el siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php

namespace App\Form;

use App\Entity\Contact;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class ContactFormType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('firstName')
            ->add('lastName')
            ->add('email')
            ->add('subject')
            ->add('message');

    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => Contact::class,
        ]);
    }
}

Y falta añadirle el botón submit

1
2
3
4
5
...
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
...
->add('message')
->add('Send', SubmitType::class, array('label' => 'Send'));

Ya solo queda renderizarlos. Para ello, ve a la plantilla page/contact.html.twig y localiza el formulario. Sustitúyelo por el siguiente código:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{{ form_start(form, {'attr': {'class':'form-horizontal'}}) }}
{{ form_errors(form) }}
	<div class="form-group">
		<div class="col-xs-6">
			{{ form_row(form.firstName, {'attr': {'class':'form-control'}}) }}
		</div>
		<div class="col-xs-6">
			{{ form_row(form.lastName, {'attr': {'class':'form-control'}}) }}
		</div>
	</div>
	<div class="form-group">
		<div class="col-xs-12">
			{{ form_row(form.email, {'attr': {'class':'form-control'}}) }}
		</div>
	</div>
	<div class="form-group">
		<div class="col-xs-12">
			{{ form_row(form.subject, {'attr': {'class':'form-control'}}) }}
		</div>
	</div>
	<div class="form-group">
		<div class="col-xs-12">
			{{ form_row(form.message, {'attr': {'class':'form-control'}}) }}
			{{ form_row(form.Send, {'attr': {'class':'pull-right btn btn-lg sr-button'}}) }}
		</div>
	</div>
{{ form_end(form) }}

Hemos cambiado el tag

1
<form>

por

1
2
{{ form_start(form, {'attr': {'class':'form-horizontal'}}) }}
{{ form_errors(form) }}

y

1
</form>

por

1
{{ form_end(form) }}

Además, cada uno de los campos los hemos cambiado por su etiqueta twig equivalente. Por ejemplo

1
2
<label class="label-control">First Name</label>
<input class="form-control" type="text">

por

1
{{ form_row(form.firstName, {'attr': {'class':'form-control'}}) }}

2.2.1 Personalizar campos

Ahora mismo el campo Email es de tipo text. Vamos a modificar el formulario para que renderice un campo de tipo email. Modifica la clase ContactFormType :

1
2
3
4
...
use Symfony\Component\Form\Extension\Core\Type\EmailType;
...
->add('email', EmailType::class)

Ya sólo nos queda añadir el formulario en el controlador:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
use Doctrine\Persistence\ManagerRegistry;
use App\Entity\Contact;
...
#[Route('/contact', name: 'contact')]
public function contact(ManagerRegistry $doctrine, Request $request): Response
{
    $contact = new Contact();
    $form = $this->createForm(ContactFormType::class, $contact);
    $form->handleRequest($request);
    if ($form->isSubmitted() && $form->isValid()) {
        $contacto = $form->getData();    
        $entityManager = $doctrine->getManager();    
        $entityManager->persist($contacto);
        $entityManager->flush();
        return $this->redirectToRoute('index', []);
    }
    return $this->render('page/contact.html.twig', array(
        'form' => $form->createView()    
    ));
}

2.2.2 Validar campos

En este momento hay campos en la parte del cliente que tienen el atributo required por lo que no se puede enviar el formulario si no se han rellenado. Pero esta restricción se puede saltar con las herramientas del desarrollador del navegador.

Por ejemplo, vamos a eliminar el atributo required del campo First Name mediante la herramienta Firebug de Firefox.

Ahora al enviar el formulario se producirá el siguiente error:

Esto es así porque el campo first_name no puede ser nulo.

Para que esto no pase, vamos a modificar la entidad Contact para añadirle aserciones. Por ejemplo vamos a obligar a que el campo firstName no pueda estar vacío:

1
2
3
4
5
6
...
use Symfony\Component\Validator\Constraints as Assert;
...
#[ORM\Column(length: 255)]
#[Assert\NotBlank(message: "Field `First Name` is mandatory")]
private $firstName;

De esta forma ahora se mostrará un mensaje de error al no enviar dicho dato. Realiza el mismo cambio para el resto de campos obligatorios.

Para el email también podemos obligarlo a que tenga un correo válido:

1
2
3
4
#[ORM\Column(length: 255)]
#[Assert\NotBlank(message: "Field `email` is mandatory")]
#[Assert\Email(message:"{{ value }} is not a valid email")]
private $email;

2.2.3 Reto - Página thankyou

Ahora mismo cuando se envía un Mensaje, se redirecciona al usuario a la ruta index. Modifica el controlador contact para que redirija a la ruta thankyou. Puedes usar un Jumbotron de Bootstrap para el diseño.

Deberás crear una nueva ruta, un controlador y una plantilla.