Required dynamic Zend_Form_Element_Multiselect - php

I've got a <select multiple> populated on start up with some values, but where additional options are added via Javascript. However I'd like now to validate this element, that at least one of the options within has been selected.
I'm using Zend_Form_Element_Multiselect to perform the validation:
$tags = new Zend_Form_Element_Multiselect('cms_tags');
$tags->setRegisterInArrayValidator(false)->setRequired(true);
However, of course, this is not working. How can I do something as simple as checking for not emptiness of the cms_tags array without resorting to overloading isValid function?
PS. Validate_Not_Empty is not working as well.

Fortunately, the solution to my question is my code. Unfortunately, Zend, at least to me, has a bug - the problem with my data was an empty value that appeared at the end of the values array, so cms_tags[]=5, cms_tags[]= was considered invalid for this kind of validator. If this a valid behavior, or not, I'll leave it to Zend folks, but this at least answers my issues.

Try something like this:
public function isValid($data) {
$etat_valid = parent::isValid($data);
if(isset($data['cms_tags'])){
// Add your validators
// for example:
if("" == $data['cms_tags']){
$this->getElement('cms_tags')->addErrors(array('This value is required and can not be empty'));
$etat_valid = false;
}
}
return $etat_valid;
}

Related

What is elegant solution for a PHP function with a lot of parameters?

I need to create a function that would insert user data into a "medical_records" table that has about 30 fields.
So the "classic" solution is writing something like:
function insert_medical_records($param1, $param2,..., $param30) {
// code here
}
But of coarse, such code writing is prone to errors and not elegant at all.
I thought of better solution like creating an array of parameters and passing its values to the function, but I don't quite know a valid syntax for that.
Or maybe there is a better solution then this altogether?
Thank you!
Since php has a soft type control, you can just give your function one input parameter. That parameter will be an array or an object.
In case of an array:
function insert_medical_records($input_array) {
// Here you can use $input_array['param1'], $input_array['param2'],
}
Before calling the function, you need to populate the array, something like:
$input_array['param1'] = "your param 1 value";
$input_array['param2'] = array('a' => 1, 'b' => 2);
insert_medical_records($input_array);
I would also suggest you to check the content of the input variable of the function:
function insert_medical_records($input_array) {
if (!isset($input_array['param1'])) {
// manage your error
return;
}
// Everything is ok. Do your stuff here...
}
Instead of isset, you should also consider using empty, is_array or array_key_exists. This it's up to your specific situation.
The solution using Object instead of Array is really similar. You define attributes such as $input_object->param1.
How about:
class MedicalRecords {
/* code here */
}
function insert_medical_records(MedicalRecords $mr) {
/* more code here */
}
and now you can add logic to do thing like validation on the records to the object itself and better seperate your code's concerns along more logical lines.

Zend Framework 2 Form and InputFilter retuning different values

I have a element(Select) of name,parameter. The problem is that on validation it returns error like this:
The input was not found in the haystack
I know that this is returned by InArray Validator. But, how can this happen when the input is valid. So, I tried to inspect the form element and inputfilter. So, i did:
print_r($form->get('parameter')->getValue()); // returns frequency
print_r($form->getInputFilter()->get('parameter')->getValue()); // returns 0
I just cant understand, why are they returning different values?
Here is the full code:
$postData = $request->getPost()->toArray();
$form->setData($postData);
print_r($form->get('parameter')->getValue());
if ($form->isValid()) {
$alarm->exchangeArray($form->getData());
$this->getAlarmMapper()->save($alarm);
$changesSaved = true;
}
print_r($form->getInputFilter()->get('parameter')->getValue());
As far as I know, if validation fails your filter simply doesn't return a value, that's why it returns 0. So you should probably look inside your validation, why it fails to validate.

Show only one error in Zend form validation

I'm looking to set a single error message for a form, but still validate each field.
The form is a survey with 10 questions. Each of them validates the same way (->setRequired(true)). So basically, I just to validate that each questions has an answer and display one message at the top of the form if one of them is not answered.
I've tried several solutions and gotten the same result. My error is added to the form, but also, all of the individual errors show as well.
This is my latest shot at it:
public function isValid($data)
{
$errors = 0;
parent::isValid($data);
foreach ($this->getElements() as $element) {
if ($element->hasErrors()) {
$element->clearErrorMessages();
$element->setErrors(array());
$errors++;
}
}
if (count($errors) > 0) {
$this->setErrorMessages(array('Please answer all questions before proceeding.'));
return false;
}
return true;
}
Can anyone shed some light on why this isn't working as I'd expect? There has to be a more elegant way of doing this.
EDIT:
This is what I ended up with. Probably a little different than most since my form elements are dynamically populated based on an array of questions, but the general idea should apply. Normally, you could just count the number of radio elements, but in my case, rather than looping through the elements and checking the type, it was just easier to count my array of questions.
public function isValid($data)
{
$valid_values = 0;
parent::isValid($data);
foreach ($this->getValues() as $value) {
if ($value >= 1 && $value <= 10) {
$valid_values++;
}
}
if ($valid_values <> count($this->_questions)) {
$this->setErrorMessages(array('Please answer all questions before proceeding.'));
return false;
}
return true;
}
Still not sure this is the most elegant way, but it works for my particular case.
The way I see it, if you really have only that one validator one each field, why don't manage that in the controller, instead of overriding isValid ?
if ($form->isValid($_POST))
{ /* success */ }
else
{ /* error as at least one field is missing */ }
You can remove the error elements by removing the 'Error' decorator from the form elements while creating it. This will validate all the elements but will not produce any error messages. But you have to cannot show errors in the form element. You have to find someother way to feedback the errors.
You could remove the Error decorator from each element (so those errors don't display). Then add a custom decorator to the form (!) that checks $form->isValid() (though in the decorator itself, it will be $this->getElement()->isValid(); kind of confusing that getElement() returns the entity to which the decorator is attached) and then renders your single message (probably above your form, using default placement PREPEND).
It sounds like you have the second part handled (rendering your single message at the form-level), so simply removing the Error decorator from the elements themselves should do the job for you.

need some help figuring out how to approach this validation

I am using codeigniter for my form validation. I have two select fields named parent_male and parent_female. I would like to have a validation callback to check both the parent_male and parent_female in my database to see if it exists. I already have a previous callback function that does just that, but with only one field. I would like to check the two field values against the database, except I am not sure how to approach this idea. Any help/ideas are greatly appreciate! Thank you.
-Rich
You can define your callback as:
function isparent($parent) {
$result = FALSE;
/* do your stuff to check $parent is a valid parent and then ... */
return $result;
}
and the rules can be set as
$this->form_validation->set_rules('parent_male', 'Male parent', 'callback_isparent');
$this->form_validation->set_rules('parent_female', 'Female parent', 'callback_isparent');
In that way you use the same callback for both fields.

Zend_Form: remove default filter from one element

I extended Zend_Form with my own class and let inherit all my forms from that. My base-class applies a default filter to all form elements that strips out double whitespaces, basically:
return trim(preg_replace('/\s+/', ' ', $value));
While usually i want this on every element, there are some occasions where it breaks stuff, for example on textareas (newlines get removed aswell) so i'm looking for a way to disable that default filter on certain elements.
I tried this (unsuccessfully):
$element->clearFilters();
however within the forms init() method that filter is not yet set ($element->getFilters() returns an empty array), only when calling methods like __toString() or isValid() it gets applied, but I'd rather not overwrite those methods just to get rid of the filter. There must be a better way?!
The cleanest solution would probably be to opt-in that filter and not apply by default - but I'd rather keep it default and find a way to exclude certain elements.
skooli, the OP, already self-answered the question:
Quote:
Resolved!
The setElementFilters() method will run over all elements currently added to the form and apply the filter, so now I've just overwritten that method to work like this:
public function setElementFilters(array $filters) {
foreach ($this->getElements() as $element) {
if(!($element instanceof Zend_Form_Element_Textarea)) {
$element->setFilters($filters);
}
}
return $this;
}
While this will work with all textareas I cant exclude arbitrary fields of other types. Should I need that I'll probably create a dummy filter that does nothing but can be used to determine whether the fixWhitespaces filter should be omitted.
Note: It's absolutely OK to self-answer your own question. Please just post it as an real answer, but not in a question or comment. Posting as real answer helps to keep the "Unanswered" list more clear (avoids making other people wasting their time).

Categories