Symfony 3: Forms

The code-snippets in this article are obtained from: https://symfony.com/doc/current/forms.html

1) Installation

composer require symfony/form

2) Building form in controller

<?php
// src/Entity/Task.php
namespace App\Entity;

class Task
{
    protected $task;
    protected $dueDate;

    public function getTask()
    {
        return $this->task;
    }

    public function setTask($task)
    {
        $this->task = $task;
    }

    public function getDueDate()
    {
        return $this->dueDate;
    }

    public function setDueDate(\DateTime $dueDate = null)
    {
        $this->dueDate = $dueDate;
    }
}
<?php
// src/Controller/DefaultController.php
namespace App\Controller;

use App\Entity\Task;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;

class DefaultController extends Controller
{
    public function new(Request $request)
    {
        // creates a task and gives it some dummy data for this example
        $task = new Task();
        $task->setTask('Write a blog post');
        $task->setDueDate(new \DateTime('tomorrow'));

        $form = $this->createFormBuilder($task)
            ->add('task', TextType::class)
            ->add('dueDate', DateType::class)
            ->add('save', SubmitType::class, array('label' => 'Create Task'))
            ->getForm();

        $form->handleRequest($request);

        if ($form->isSubmitted() &amp;&amp; $form->isValid()) {
            // $form->getData() holds the submitted values
            // but, the original `$task` variable has also been updated
            $task = $form->getData();

            // ... perform some action, such as saving the task to the database
            // for example, if Task is a Doctrine entity, save it!
            // $entityManager = $this->getDoctrine()->getManager();
            // $entityManager->persist($task);
            // $entityManager->flush();

            return $this->redirectToRoute('task_success');
        }

        return $this->render('default/new.html.twig', array('form' => $form->createView(),));
    }
}
{# templates/default/new.html.twig #}
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}

{# 
form_start - renders the start tag of the form, with enctype
form_widget - fields, validation errors
form_end - eng tag of the form + automatic CSRF protection
#}
<!-- templates/default/new.html.php -->
<?php echo $view['form']->start($form) ?>
<?php echo $view['form']->widget($form) ?>
<?php echo $view['form']->end($form) ?>
{% endraw %}

3) Validation

composer require symfony/validator

Annotation is used for validation

<?php

// src/Entity/Task.php 

namespace App\Entity;

use Symfony\Component\Validator\Constraints as Assert;


/**
 * Class Task
 * @property string $task
 * @property \DateTime $dueDate
 * @package App\Entity
 */
class Task
{
    /**
     * @Assert\NotBlank()
     */
    protected $task;

        /**
     * @Assert\NotBlank()
     * @Assert\Type("\DateTime")
     */
    protected $dueDate;

    /**
     * @return string
     */
    public function getTask(): string
    {
        return $this->task;
    }

    /**
     * @param string $task
     */
    public function setTask($task): void
    {
        $this->task = $task;
    }


    /**
     * @return \DateTime
     */
    public function getDueDate(): \DateTime
    {
        return $this->dueDate;
    }

    /**
     * @param \DateTime $dueDate
     */
    public function setDueDate(\DateTime $dueDate): void
    {
        $this->dueDate = $dueDate;
    }
}
{# templates/default/new.html.twig #}
{{ form_start(form, {'attr': {'novalidate': 'novalidate'}}) }} 
{{ form_widget(form) }} 
{{ form_end(form) }}

Symfony Field Types

https://symfony.com/doc/current/reference/forms/types.html

Passing options to Fields

->add('dueDate', DateType::class, array(
    'widget' => 'single_text',
    'required' => true // applies client-side validation if enabled,
    'label' => 'Due Date',
))
->add('task', null, array('attr' => array('maxlength' => 4)))

Creating Form Class

<?php
// src/Form/TaskType.php

namespace App\Form;

use App\Entity\Task;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class TaskType extends AbstractType
{

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('task')
            ->add('dueDate', null, ['widget' => 'single_text'])
            ->add('agreeTerms', CheckboxType::class, ['mapped' => false])
            ->add('save', SubmitType::class);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        // indicates the type of class which holds data
        $resolver->setDefaults([
            'data_class' => Task::class
        ]);
    }
}
<?php

// src/Controller/TaskController.php

namespace App\Controller;


use App\Form\TaskType;
use Symfony\Component\Routing\Annotation\Route;
use App\Entity\Task;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\HttpFoundation\Request;

class TaskController extends Controller
{
    /**
     * @Route("/task/new2")
     */
    public function newFromFormClass(Request $request)
    {
        $task = new Task();
        $task->setTask("Here is the new task");
        $task->setDueDate(new \DateTime('tomorrow'));

        $form = $this->createForm(TaskType::class, $task);

        $form->handleRequest($request);
        if ($form->isSubmitted() &amp;&amp; $form->isValid()) {
            $task = $form->getData();

            echo $form->get('agreeTerms')->getData();

            return $this->redirectToRoute('task_success');
        }

        return $this->render('task/new.html.twig', [
            'form' => $form->createView()
        ]);
    }
}