86

I check some validation in my controller. And I want to add error to specific element of my form on failure. My form:

use Symfony\Component\Form\FormError;

// ...

$config = new Config();
$form = $this->createFormBuilder($config)
        ->add('googleMapKey', 'text', array('label' => 'Google Map key'))
        ->add('locationRadius', 'text', array('label' => 'Location radius (km)'))
        ->getForm();

// ...

$form->addError(new FormError('error message'));

addError() method adds error to form, not to element. How can I add an error to locationRadius element?

Elnur Abdurrakhimov
  • 44,533
  • 10
  • 148
  • 133
Alex Pliutau
  • 21,392
  • 27
  • 113
  • 143

2 Answers2

187

You can do

$form->get('locationRadius')->addError(new FormError('error message'));

As form elements are also of FormInterface type.

Mun Mun Das
  • 14,992
  • 2
  • 44
  • 43
  • @m2mdas, great answer! How would we translate this? because once we create a FormError instance, it won't translate it, am I right? I tried and it doesn't translate it, and I think it makes sense. How would you translate a FormError instance? – Mick Jan 12 '14 at 15:24
  • 2
    Hello @Patt, sorry for late reply. Validator component takes care of translating form constraint violation messages before the error messages are added to the form. For adding custom error you have translate the message same way as you do for other strings e.g, `$this->get('translator')->trans('error message')` – Mun Mun Das Jan 14 '14 at 21:31
  • 1
    @m2mdas But how do you print this error in your view? I tried this, but it doesn't go in the `form_errors(form)` in my twig. – Nat Naydenova Apr 22 '15 at 11:38
  • 1
    @NatNaydenova I know it's been a while but try `form_erros(form.my_field_name)` – TMichel Dec 01 '15 at 17:58
  • 3
    Please note: to get an error to print using form_errors(form), add your error to the form itself e.g. $form->addError(new FormError('error msg'); – beterthanlife Jan 09 '17 at 10:38
  • Perfect. This also sets $form->isValid() to false. – Markus Zeller Feb 28 '18 at 09:50
9

OK guys, I have another way. It is more complex and only for specific cases.

My case:

I have a form and after submit I post data to the API server. And errors I got from the API server as well.

API server error format is:

array(
    'message' => 'Invalid postal code',
    'propertyPath' => 'businessAdress.postalCode',
)

My goal is to get flexible solution. Lets set the error for the corresponding field.

$vm = new ViolationMapper();

// Format should be: children[businessAddress].children[postalCode]
$error['propertyPath'] = 'children['. str_replace('.', '].children[', $error['propertyPath']) .']';

// Convert error to violation.
$constraint = new ConstraintViolation(
    $error['message'], $error['message'], array(), '', $error['propertyPath'], null
);

$vm->mapViolation($constraint, $form);

That's it!

NOTE! addError() method bypasses error_mapping option.


My form (Address form embedded in the Company form):

Company

<?php

namespace Acme\DemoBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints;

class Company extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('companyName', 'text',
                array(
                    'label' => 'Company name',
                    'constraints' => array(
                        new Constraints\NotBlank()
                    ),
                )
            )
            ->add('businessAddress', new Address(),
                array(
                    'label' => 'Business address',
                )
            )
            ->add('update', 'submit', array(
                    'label' => 'Update',
                )
            )
        ;
    }

    public function getName()
    {
        return null;
    }
}

Address

<?php

namespace Acme\DemoBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints;

class Address extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            // ...
            ->add('postalCode', 'text',
                array(
                    'label' => 'Postal code',
                    'constraints' => array(
                        new Constraints\NotBlank()
                    ),
                )
            )
            ->add('town', 'text',
                array(
                    'label' => 'Town',
                    'constraints' => array(
                        new Constraints\NotBlank()
                    ),
                )
            )
            ->add('country', 'choice',
                array(
                    'label' => 'Country',
                    'choices' => $this->getCountries(),
                    'empty_value' => 'Select...',
                    'constraints' => array(
                        new Constraints\NotBlank()
                    ),
                )
            )
        ;
    }

    public function getName()
    {
        return null;
    }
}
Jekis
  • 4,274
  • 2
  • 36
  • 42
  • where do you place these code ? $vm = new ViolationMapper(); – vidy videni Nov 26 '15 at 06:20
  • @vidyvideni, Controller action where form submit will be handled. Also you could adjust this piece of code and move it to a separate method – Jekis Nov 27 '15 at 07:08