Crear un formulario de contacto en Symfony

Tutorial de como hacer un sencillo formulario de contacto en Symfony2 sin una clase y con validación

El formulario de contacto es una de las secciones que suele tener cualquier página web. En este artículo explico cómo crear un formulario de contacto en Symfony2 sencillo, sin el uso de una clase y con validación.

Lo primero que vamos a hacer es crear un archivo en nuestro bundle en la carpeta form llamado ContactType.php:

# AppBundle/Form/ContactType.php

namespace AppBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Collection;

class ContactType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('nombre', 'text', array(
                'attr' => array(
                    'placeholder' => 'Dime tu nombre'
                )
            ))
            ->add('email', 'email', array(
                'attr' => array(
                    'placeholder' => 'Email para que pueda responderte'
                )
            ))
            ->add('motivo', 'text', array(
                'attr' => array(
                    'placeholder' => 'El motivo de contactar conmigo'
                )
            ))
            ->add('mensaje', 'textarea', array(
                'attr' => array(
                    'cols' => 90,
                    'rows' => 10,
                    'placeholder' => 'Mensaje que quieres enviarme'
                )
            ))
            ->add('save', 'submit', array('label' => 'Enviar'));
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $collectionConstraint = new Collection(array(
            'nombre' => array(
                new NotBlank(array('message' => 'El nombre no puede estar vacío.')),
                new Length(array('min' => 3))
            ),
            'email' => array(
                new NotBlank(array('message' => 'El email no puede estar vacío.')),
                new Email(array('message' => 'Email inválido.'))
            ),
            'motivo' => array(
                new NotBlank(array('message' => 'El motivo no puede estar vacío.')),
                new Length(array('min' => 3))
            ),
            'mensaje' => array(
                new NotBlank(array('message' => 'El mensaje no puede estar vacío.')),
                new Length(array('min' => 5))
            )
        ));

        $resolver->setDefaults(array(
            'constraints' => $collectionConstraint
        ));
    }

    public function getName()
    {
        return 'contacto';
    }
}

En el método buildForm hemos añadido los 4 campos que se pedirán en el formulario: nombre, email, motivo y mensaje. El placeholder es el mensaje que aparece en cada apartado antes de que empieces a escribir los datos. En el apartado mensaje, se han añadido los atributos cols y rows para especificar el tamaño de la caja textarea.

En el método setDefaultOptions se especifica la validación, junto con los mensajes que aparecen cuando no se cumplen los requisitos. En mi caso he desactivado la validación automática que proporciona HTML5 cuando añades un require en un formulario (lo indico un poco más abajo en las plantillas).

Vamos a crear ahora un método en un controlador, en mi caso en PagesController:

# AppBundle/Controller/PagesController

public function contactAction(Request $query)
    {
        $form = $this->createForm(new ContactType());

        if ($query->isMethod('POST')) {
            $form->handleRequest($query);

            if ($form->isValid()) {
                $mailer = $this->get('mailer');
                $message = $mailer->createMessage()
                    ->setSubject($form->get('motivo')->getData())
                    ->setFrom('envio@ejemplo.com')
                    ->setTo('recibo@ejemplo.com')
                    ->setBody(
                        $this->renderView(
                            'AppBundle:Mail:contact.html.twig',
                            array(
                                'ip' => $query->getClientIp(),
                                'nombre' => $form->get('nombre')->getData(),
                                'email' => $form->get('email')->getData(),
                                'mensaje' => $form->get('mensaje')->getData()
                            )
                        )
                    );

                $mailer->send($message);

                $query->getSession()->getFlashBag()->add('success', 'Tu email ha sido enviado. Gracias');

                return $this->redirect($this->generateUrl('contact_blog'));
            }
        }

        return $this->render('AppBundle:Pages:contact.html.twig', array(
            'form'   => $form->createView()
        ));
    }

De este método voy a destacar dos partes:

  • La plantilla que se mostrará en el email a enviar en AppBundle:Mail:contact.html.twig:
New message from {{ nombre }}
Sent from diego.com.es/contacto
IP: {{ ip }}
Email: {{ email }}

{{ mensaje }}
  • La plantilla desde la que se ejecutará el formulario y mostrará los mensajes de éxito y error en AppBundle:Pages:contact.html.twig:
{% for label, flashes in app.session.flashbag.all %}
    {% for flash in flashes %}
        <div class="alert alert-{{ label }}">
            {{ flash }}
        </div>
    {% endfor %}
{% endfor %}

{{ form_start(form, {'attr': {'novalidate': 'novalidate'}}) }}
{{ form_widget(form) }}
{{ form_end(form) }}

El atributo attr 'novalidate' es el que desactiva la validación de formularios de HTML5. Así mostrará los mensajes de error que hemos personalizado en ContactType.php.

Usar gmail para el formulario de contacto

Para hacer pruebas o en el entorno de desarrollo puedes usar gmail. En el archivo app/config/config_dev.yml tan sólo añade:

swiftmailer:
    transport: gmail
    username:  tuusuariodegmail
    password:  tupassworddegmail

Si usas la Versión Standard de Symfony puedes hacerlo desde parameters.yml:

    mailer_transport: gmail
    mailer_host: ~
    mailer_user: tuusuariodegmail
    mailer_password: tupassworddegmail

Fuentes: courot.com, symfony.com