Zend: Form validation: value was not found in the haystack error - zend-framework

I have a form with 2 selects. Based on the value of the first select, it updates the values of the second select using AJAX. Doing this makes the form not being valid. So, I made the next change:
$form=$this->getAddTaskForm(); //the form
if(!$form->isValid($_POST)) {
$values=$form->getValues();
//get the options and put them in $options
$assignMilestone=$form->getElement('assignedMilestone');
$assignMilestone->addMultiOptions($options);
}
if($form->isValid($_POST)) {
//save in the database
}else {
//redisplay the form
}
Basically, I check if it is valid and it isn't if the user changed the value of the first select. I get the options that populated the second select and populate the form with them. Then I try to validate it again. However this doesn't work. Anybody can explain why? The same "value was not found in the haystack" is present.

You could try to deactivate the validator:
in your Form.php
$field = $this->createElement('select', 'fieldname');
$field->setLabel('Second SELECT');
$field->setRegisterInArrayValidator(false);
$this->addElement($field);
The third line will deactivate the validator and it should work.

You can also disable the InArray validator using 'disable_inarray_validator' => true:
For example:
$this->add( array(
'name' => 'progressStatus',
'type' => 'DoctrineModule\Form\Element\ObjectSelect',
'options' => array(
'disable_inarray_validator' => true,
),
));

Additionaly you should add you own InArray Validator in order to protect your db etc.
In Zend Framework 1 it looks like this:
$this->addElement('select', $name, array(
'required' => true,
'label' => 'Choose sth:',
'filters' => array('StringTrim', 'StripTags'),
'multiOptions' => $nestedArrayOptions,
'validators' => array(
array(
'InArray', true, array(
'haystack' => $flatArrayOptionsKeys,
'messages' => array(
Zend_Validate_InArray::NOT_IN_ARRAY => "Value not found"
)
)
)
)
));
Where $nestedArrayOptions is you multiOptions and $flatArrayOptionsKeys contains you all keys.

You may also add options to select element before checking for the form validation. This way you are insured the select value is in range.

Related

Symfony form ChoiceType is ignoring the required attribute

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 . '"'));
}
});

zf2 doctrine form int required not working

$inputFilter->add(array(
'name' => 'seatingCapacity',
'required' => TRUE,
'filters' => array(
array('name' => 'Int'),
),
));
In my Doctrine Entity, I have a getInputFilter method which I use for form validation. The above is code snippet for one of the input elements. My problem is the required => true is not working even if I submit an empty form.
After researching I found out, that the Int filter converts the empty input to 0 and submits it and that is why the required validator is not working. I just need reasons why it may not be working.
For reference where I searched
Zend Framework 2 - Integer Form Validation
where he suggests to use Between validator
$inputFilter->add($factory->createInput(array(
'name' => 'zip',
'required' => true,
'filters' => array(
array('name' => 'Int'),
),
'validators' => array(
array(
'name' => 'Between',
'options' => array(
'min' => 1,
'max' => 1000,
)
)
)
)
));
I want to know why I should use Between and why required is failing.
You should only use the Between validator to validate if the given value is Between a min and max value. It has nothing to do with solving your empty value to 0 issue.
You should ask yourself 2 questions:
Is 0 a valid value?
Do I want to automatically cast null empty string ('') and other empty values to this 0 or not?
If you actually want to prevent that the Int filter sets an empty value to 0, maybe then you should not use this filter at all then?
You can instead add an IsInt validator to check if the given value is an integer. Your required => true setting will work as expected and validation will fail on any other (not integer) input so also on null, empty strings etc.
Thank you for your time, energy & effort.
Actually I solved the problem.
I had copy-pasted the code, which I should have been careful while doing so.
What I found out is there is no such filter named 'Int' and actually it's 'Digits'
$inputFilter->add(array(
'name' => 'seatingCapacity',
'required' => TRUE,
'filters' => array(
array('name' => 'Int'),
),
));
shows me error because the filter name should have been 'Digits'.
Only doing so solved my problem and works as per my requirement.
$inputFilter->add(array(
'name' => 'seatingCapacity',
'required' => TRUE,
'filters' => array(
array('name' => 'Digits'),
),
));
This is the right way to do and I would advice you to be careful while referring code from your sources because it's an illogical mistake I did.
Happy coding

zend addElements form onchange select

I try to add dinamically a form input Elemnt on onchange of select element.
I have this code:
$this->addElement('select', 'nationality', array(
'multiOptions' => array('CH' => 'Choose','IT' => 'Italy', 'other' => 'Other'),
'required' => true,
'label' => 'Nation',
'filters' => array('StringTrim'),
'onChange' => '???'
));
I try to paste my new element instead "???"
$this->addElement('select', 'nationality', array(
'multiOptions' => array('CH' => 'Choose','IT' => 'Italy', 'other' => 'Other'),
'required' => true,
'label' => 'Nation',
'filters' => array('StringTrim'),
'onChange' => '$this->addElement(
'text', 'codice_fiscale', array(
'required' => true,
'label' => 'Codice fiscale',
'required' => true
))'
));
I know is not correct, but I dont' found any documentation about it.
How can I add an element onchange select value?
Thanks in advance
I would approach the problem in a different way, if it's possible for you:
javascript functions to call on the onChange. It would be syntax correct (and, as you said, what you wrote is not correct, it's going to be printed out entirely on the onChange attribute, not interpreted through php).
so, i would write
'onChange' => 'addElement()'
and then declare the javascript function which handles new elements. Or, you can prepare the elements before (if you have a fixed number), and show / hide them. It may be convenient if you don't have much elements, but if they're too many, just add through javascript the needed one.
PseudoCode Javascript
function addElement()
{
// add your element here, or show / hide it
}
As far as I saw from my experience and similar cases
(Zend_form_element_select onchange in zend framework,
Zend Form: onchange select load another view content)
you won't escape from Javascript if you want to handle the "onChange"

How do I allow html tags in label for Zend form element using addElement()?

I am brand new to Zend and I've been given a project to make adjustments on. I'd like to add html to the labels for my form elements but I can't seem to get it right.
Here's what I have:
$this->addElement('text', 'school_name', array(
'filters' => array('StringTrim'),
'validators' => array(
array('StringLength', false, array(0, 150)),
),
'required' => true,
'label' => 'Name* :<img src="picture.png">,
'size' => '90',
));
As is, of course, the <img src="picture.png"> text gets escaped and the whole string is displayed.
I've read that I need to use 'escape' => false in some capacity but I can't figure out where/how to use it in my specific case.
Any help would be great. Thanks!
After calling addElement fetch the label's decorator and change the escape setting:
$form->getElement('school_name')->getDecorator('label')->setOption('escape', false);
If you use this type of label a lot, you should consider writing a custom decorator.
You can also use the disable_html_escape in 'label_options' when adding an element to the form:
$this->add(array(
....
'options' => array(
'label' => '<span class="required">Name</span>,
'label_options' => array(
'disable_html_escape' => true,
)
),
...
));
Credit to Théo Bouveret's post 'Button content in ZF2 forms' for the answer.

Remove null values coming from empty collection form item

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