I'm stumbling upon a really simple question and I can't find out what I'm doing wrong :
I have an entity Post which can have a type, in my class declaration :
/**
* #ORM\Column(name="type", type="text", nullable=true)
*/
private $type;
Then I want a form to create Posts :
In my PostType::buildForm() function :
$builder->add('type', 'choice', array(
'empty_data' => null,
'empty_value' => 'No type',
'multiple' => false,
'expanded' => true,
'choices' => \MyBundle\Entity\Application\Post::getTypes(), /* returns array('TYPE1' => 'TYPE_1', 'TYPE2' => 'TYPE_2', ...) */
'required' => true,))
The plan is to have a radio list with :
Type 1
Type 2
Type 3
No type
But it seems like if I choose the option 'No type', the form won't validate, without giving any explicit error. Same thing happens with 'required' => false, with 'placeholder' instead of 'empty_value', ...
Can you spot my mistake ?
What am I doing wrong ?
Thanks :)
My mistake didn't come from the Type or the Entity, it came from the twig widgets overloading.
I was not displaying the value="" if {{ value }} was empty.
Make sure value="" is inside your "None" input radio tag, and in your other input radio tags aswell, of course !
Hope it helps someone ;)
You can't have an empty value on a choice field type and have it required.
You are saying it must exist but may be empty, a contradiction.
It will work if you drop the 'required' => true
Related
I have a classic form, with a few 'entity' type fields and one collection type fields. Those aren't causing any issue.
When I put data in all the field, except the description field, as I want it to be null or empty, and submit, my form is processed but the new entity not added to the database, as if the description field needed to be field.
Then I'm redirected to the same form with all data entered gone, as if it had been added in the database.
I've checked the field mapping, which is set to nullable :
/**
* #var string
*
* #ORM\Column(name="description_activite", type="text", nullable=true)
*/
private $descriptionActivite;
public function getDescriptionActivite(){return $this->descriptionActivite;}
public function setDescriptionActivite($value){$this->descriptionActivite=$value;return $this;}
And the field description in the formType file :
->add('descriptionActivite', 'textarea', array(
'label' => 'Description',
'attr' => array(
'class' => 'form-control',
// 'required' => false
)
))
I've also checked the database just in case, the field is created as a may be null field, I really don't know where that problem is coming from. Anyone ran into this already? Thanks
For those who meet the same problem, I solved it by :
Checking database if field may be null (was not the issue but would have been later)
Checking annotation, see if the field is set as nullable
AND LAST
->add('descriptionActivite', 'textarea', array(
'label' => 'Description',
'required' => false,
'attr' => array(
'class' => 'form-control',
)
))
the required option was place in the 'attr' array(), when it should not have, my bad.
On a form I add a field like this
$builder->add('cse',
ChoiceType::class,
array(
'label' => '',
'required' => true,
'translation_domain' => 'messages',
'choices' => array(
'I agree' => true
),
'expanded' => true,
'multiple' => true,
'data' => null,
'attr' => array( 'class' => 'form_f' ),
)
)
While all other fields added to the form that have 'required' set to 'true' will prevent the form from being send the required attribute for this field is ignored (the form is sent anyways no matter if checked or not).
Do I have to handle this with Assert statements? If yes - still: why is required not working here?
Yes, use Assert.
Because multiple=true print checkbox. Html validator can test radio, but no checkbox.
Always use Assert for all forms, because html validator isn't safe :)
In my case, I cannot use the asserts, and since was not possible to handle this in user side (unless you use javascript), I made the checks in server side, in the FormEvents::PRE_SUBMIT hook:
$builder->addEventListener(
FormEvents::PRE_SUBMIT,
function (FormEvent $event) {
if ($field->required && !isset($event->getData()[$field->name])) {
$event->getForm()->addError(new FormError('One option must be chosen on "' . $field->label . '"'));
}
});
I get something strange with Symfony2 forms. I create a form with a propel entity, values are fine except the "select" (choices) field, that have no selected value.
I tried few tricks like:
$params['choices'] = array('N/A'=> 'N/A');
$params['data'] = array('N/A');
$params['preferred_choices'] = array('N/A');
Even with this, there is no preselected value. What's wrong ?
You can use data attribute for default selected item.
$param['data'] = 'N/A'
This is part of the Abstract "field" type ?
Fore example form,
$form = $this->createFormBuilder()
->add('category', 'choice', array(
'choices' => array(
0 => 'Books',
1 => 'Electronics',
2 => 'Hardware`
),
'data' => 1
))
->getForm();
In this example when the form loads the option Electronics should be selected as default
'empty_value' => 'Select Choice',
$builder->add('gender', 'choice', array(
'choices' => array('m' => 'Male', 'f' => 'Female')
'empty_value' => 'Select Choice',
));
I finally solved my problem. There were 2 things:
* reloading with Firefox, the previously selected value seems to be kept, so I coulnd't really test the changes until I closed the current tab and reopened one;
* I passed a single dimension array as values for the "choice" field, so Symfony2 re-indexed it with integer and my entity string value couldn't be hydrated to the symfony2 integer value of the field.
I'm trying to implement a ManyToMany relation in a form between 2 entities (say, Product and Category to make simpe) and use the method described in the docs with prototype and javascript (http://symfony.com/doc/current/cookbook/form/form_collections.html).
Here is the line from ProductType that create the category collection :
$builder->add('categories', 'collection', array(
'type' => 'entity',
'options' => array(
'class' => 'AppBundle:Category',
'property'=>'name',
'empty_value' => 'Select a category',
'required' => false),
'allow_add' => true,
'allow_delete' => true,
));
When I had a new item, a new select appear set to the empty value 'Select a category'. The problem is that if I don't change the empty value, it is sent to the server and after a $form->bind() my Product object get some null values in the $category ArrayCollection.
I first though to test the value in the setter in Product entity, and add 'by_reference'=>false in the ProductType, but in this case I get an exception stating that null is not an instance of Category.
How can I make sure the empty values are ignored ?
Citing the documentation on 'delete_empty':
If you want to explicitly remove entirely empty collection entries from your form you have to set this option to true
$builder->add('categories', 'collection', array(
'type' => 'entity',
'options' => array(
'class' => 'AppBundle:Category',
'property'=>'name',
'empty_value' => 'Select a category'),
'allow_add' => true,
'allow_delete' => true,
'delete_empty' => true
));
Since you use embedded forms, you could run in some issues such as Warning: spl_object_hash() expects parameter 1 to be object, null given when passing empty collections.
Removing required=>false as explained on this answer did not work for me.
A similar issue is referenced here on github and resolved by the PR 9773
I finally found a way to handle that with Event listeners.
This discussion give the meaning of all FormEvents.
In this case, PRE_BIND (replaced by PRE_SUBMIT in 2.1 and later) will allow us to modify the data before it is bind to the Entity.
Looking at the implementation of Form in Symfony source is the only source of information I found on how to use those Events. For PRE_BIND, we see that the form data will be updated by the event data, so we can alter it with $event->setData(...). The following snippet will loop through the data, unset all null values and set it back.
$builder->addEventListener(FormEvents::PRE_BIND, function(FormEvent $event){
$data = $event->getData();
if(isset($data["categories"])) {
foreach($data as $key=>$value) {
if(!isset($value) || $value == "")
unset($data[$key]);
}
$event->setData($data);
});
Hope this can help others !
Since Symfony 3.4 you can pass a closure to delete_empty:
$builder
->add('authors', CollectionType::class, [
'delete_empty' => function ($author) {
return empty($author['firstName']);
},
]);
https://github.com/symfony/symfony/commit/c0d99d13c023f9a5c87338581c2a4a674b78f85f
I am building a form class in Symfony2. In my class, I have a choice field. I built a function to return my choice array:
public function getCardTypes() {
return array('visa' => 'Visa', 'mc' => 'MasterCard', 'amex' => 'American Express');
}
Later, I add a choice field to my form with this array:
$builder->add('PaymentCCType', 'choice', array('choices' => $this->getCardTypes()));
And then in getDefaultOptions function I have a choice constraint for this field:
'PaymentCCType' => new Choice(array('choices' => $this->getCardTypes())),
I seem to be having a problem with this validator. When I submit this form, I get the following error underneath my select box: "The value you selected is not a valid choice". Of course, I am using one of the choices in my array.
What am I doing wrong?
/* edit */
I have noticed that of the 4 fields I have like this, I only get the error on 3 of them. the one where the choice is month (simple 1-12), validation works.
/* edit 2 */
the issue appears to occur when the array key does not match the value. i switched my array to array('Visa' => 'Visa', 'MasterCard' => 'MasterCard', 'American Express' => 'American Express') and now it works.
Is there any way around this? I feel like I can't be the only one with this issue. it occurs even when you have a regular (non-associative) array like array('Visa', 'MasterCard', 'American Express')
IMHO you should do it in different way, create class with ChoiceListInterface with methods:
public function getChoices()
{
return self::$choices;
}
public static function getTypeChoicesKeys()
{
return array_keys(self::$choices);
}
in form class:
$builder->add('type', 'choice',
array(
'expanded' => true,
'multiple' => false,
'choice_list' => new TypeChoices(),
'required' => true,
)
)
in validation.yml
type:
- NotNull: ~
- Choice: { callback: [TypeChoices, getTypeChoicesKeys] }
edit
In response to my issue, the Symfony team pointed out the choice validator accepts an array of possible values (not possible choices like the choice field). the easiest way to do this is to use the array_keys function:
'PaymentCCType' => new Choice(array('choices' => array_keys($this->getCardTypes()))),