I am using symfony 2 and I have a form on which I put @Assert\NotBlank() annotations. I am volontarily filling the fields, my form does not pass the isValid and isSubmitted test and after those lines I get a non-null value for exit(var_dump($recipeForm->getErrors()));
private 'errors' =>
array (size=4)
0 =>
object(Symfony\Component\Form\FormError)[4119]
private 'message' => string 'Cette valeur doit être vide.' (length=29)
protected 'messageTemplate' => string 'This value should be blank.' (length=27)
protected 'messageParameters' =>
array (size=1)
...
protected 'messagePluralization' => null
private 'cause' =>
object(Symfony\Component\Validator\ConstraintViolation)[4062]
...
private 'origin' => null
In my twig template I render the form with a simple form(form). form_errors(form) or form_errors(form.field) won't render the errors. Why? Why could I do to further understand where the issue comes from?
I have a pretty complicated type. for some other forms of my website, the errors are correctly displayed. My type:
<?php
//src/AppBundle/Form/FoodAnalytics/RecipeType.php
namespace AppBundle\Form\FoodAnalytics;
use AppBundle\Form\Core\MediaType;
use AppBundle\Repository\FoodAnalytics\UnitRepository;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class RecipeType extends AbstractType
{
protected $recipeIngredientQueryBuilder;
protected $recipeSubrecipeQueryBuilder;
protected $unitRepository;
protected $action;
/**
* @return string
*/
public function getName()
{
return 'appbundle_foodanalytics_recipe' . $this->action;
}
public function __construct(UnitRepository $unitRepository, $recipeIngredientQueryBuilder=null, $recipeSubrecipeQueryBuilder=null, $action = null)
{
$this->recipeIngredientQueryBuilder = $recipeIngredientQueryBuilder;
$this->recipeSubrecipeQueryBuilder = $recipeSubrecipeQueryBuilder;
$this->unitRepository = $unitRepository;
$this->action = $action == null ? null : '_' . $action;
}
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('recipeCategories', 'genemu_jqueryselect2_entity',array(
'multiple' => true,
'class' => 'AppBundle:FoodAnalytics\RecipeCategory',
'label' => 'Catégories',
'required' => false,
'by_reference' => false,
'attr'=>array(
'data-toggle'=>"tooltip",
'data-placement'=>"top",
'title'=>"Indiquez les catégories dans lesquelles enregistrer la recette pour un recherche future plus facile",
)))
->add('isProduct', null, array(
'label'=>'Correspond à un produit fini',
'required'=>false,
'attr'=>array(
'data-toggle'=>"tooltip",
'data-placement'=>"top",
'title'=>"La recette correspond-elle à un produit fini qui peut être mis en vente ?",
)))
->add('name', null, array(
'label'=>'Nom détaillé',
'attr'=>array(
'data-toggle'=>"tooltip",
'data-placement'=>"top",
'title'=>"Indiquez le nom détaillé de la recette. Par exemple : 'millefeuilles praliné ganache vanille sur feuilletage inversé'",
)))
->add('nickName', null, array(
'label'=>'Nom raccourci',
'attr'=>array(
'data-toggle'=>"tooltip",
'data-placement'=>"top",
'title'=>"Indiquez un nom raccourci pour la recette. Par exemple : 'millefeuilles'",
)))
->add('recipeIngredients', 'collection', array(
'type' => new RecipeIngredientType($this->unitRepository, $this->recipeIngredientQueryBuilder),
'by_reference' => false,
'label'=>'Ingrédient',
'allow_add' => true,
'allow_delete' => true,
'cascade_validation' => true,
))
->add('subrecipes', 'collection', array(
'type' => new RecipeSubrecipeType($this->unitRepository, $this->recipeSubrecipeQueryBuilder),
'by_reference' => false,
'label'=>'Sous-recette',
'allow_add' => true,
'allow_delete' => true
))
->add('recipeSteps', 'collection', array(
'type' => new RecipeStepType(),
'by_reference' => false,
'label'=>'Etape de production',
'allow_add' => true,
'allow_delete' => true
))
->add('portions', null, array(
'label'=>'Nombre de parts / de pièces',
'required' => false,
'attr'=>array(
'data-toggle'=>"tooltip",
'data-placement'=>"top",
'title'=>"Indiquez le nombre d'éléments disponibles dans la recette. Cela peut permettre d'utiliser l'unité 'U' dans les recettes parentes qui l'utiliseront",
)))
->add('shortDescription', null, array(
'label'=>'Description courte',
'required'=>false,
'attr'=>array(
'data-toggle'=>"tooltip",
'data-placement'=>"top",
'title'=>"Décrivez succinctement la recette",
)))
->add('medias', 'collection', array(
'type' => new MediaType(),
'by_reference' => false,
'label'=>'Medias',
'allow_add' => true,
'allow_delete' => true,
'required' => false,
'attr'=>array(
'data-toggle'=>"tooltip",
'data-placement'=>"top",
'title'=>"Ajoutez des images ou vidéos pour décrire la recette",
)))
->add('content', 'textarea', array(
'label'=>'Instructions générales',
'required'=>false,
'attr' => array(
'data-toggle'=>"tooltip",
'data-placement'=>"top",
'class' => 'summernote',
'title'=>"Ajoutez du contenu supplémentaire pour détailler la recette",
)))
->add('workingDuration', 'timepicker', array(
'label'=>'Temps total de travail',
'required' => false,
'attr'=>array
(
'class' => 'timepicker',
'data-toggle'=>"tooltip",
'data-placement'=>"top",
'title'=>"Indiquez le temps total de travail consacré à la recette si il diffère du temps de travail cumulé des étapes de production",
)))
->add('sleepDuration', 'timepicker', array(
'label'=>'Temps total de repos',
'required' => false,
'attr'=>array
(
'data-toggle'=>"tooltip",
'class'=>'timepicker',
'data-placement'=>"top",
'title'=>"Indiquez le temps total de repos consacré à la recette si il diffère du temps de repos cumulé des étapes de production",
)))
;
}
/**
* @param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\FoodAnalytics\Recipe',
// 'cascade_validation' => true,
));
}
}
EDIT: keeping only one simple field of this form does not change anything, the error won't get shown
Normally, field errors are rendered in Twig by calling form_errors on each individual field: The form_row function calls form_errors internally. Just like in the controller, the errors are attached to the individual fields themselves.
In this case, we'll show how to get and display the errors of forms in Symfony 3. To list all the errors of a form in a twig view, you'll need to check first if it has errors checking for form.vars.valid property. Then, loop through every form children and print all the errors on it.
Renders the "row" of a given field, which is the combination of the field's label, errors, help and widget. The second argument to form_row () is an array of variables. The templates provided in Symfony only allow to override the label as shown in the example above.
Hopefully it make sense now why form_errors (form) renders global errors and form_errors (form.name) renders the errors attached to the name field. Once you're in Twig, each field (e.g. form, form.name) is an instance of :symfonyclass: Symfony\Component\Form\FormView.
Take a look at how errors are rendered here: http://symfony.com/doc/current/cookbook/form/form_customization.html#customizing-error-output
The problem with using {{ form_errors(form) }}
is that it displays global form errors, not individual fields, whereas getErrorsAsString()
will drill-down through all of the fields. If you want all of the individual field errors to be accessible via {{ form_errors(form) }}
, then you need to edit every single field in your form and add the option error_bubbling => true
.
If you don't set the error bubbling to true on all of our fields, then you will need to render each field's error individually - for example: {{ form_errors(form.name) }}
, or just using {{ form_row(form.name) }}
which renders the label, form element, and errors all in one shot.
Ah my god!
I'm sorry i made people lose time with this! The issue was I was passing as a response an array $response = array(form->createView())
but this array response was generated before I handle the request. Hence why I could see it in the vardump and not in twig.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With