I’m using Zend_Filter_Input to validate form data and want to customize the error messages, if a user does not enter a value. It is important that each field gets a different error message.
With Zend Framework 1.8.0 I used the following array for the “validator” parameter of Zend_Filter_Input:
$validators = array(
'salutation' => array(
new Zend_Validate_NotEmpty(),
Zend_Filter_Input::MESSAGES => array(
Zend_Validate_NotEmpty::IS_EMPTY => "Please enter a salutation"
)
),
/* ... */
);
Since I’ve upgraded to ZF 1.8.4, I always get the default message for empty fields (“You must give a non-empty value for field '%field%'”). Obviously Zend_Filter_Input does not call the Zend_Validate_NotEmpty validator anymore, if the field is empty.
Is there a way to change this behavior or another way to get customized “empty” messages for each field?
It seems that Zend_Filter_Input changed its behaviour when handling empty fields. Empty fields are never processed by rule validators. If a field is empty and allowEmpty is set to true, none of your validators are used. If the field is empty and allowEmpty is set to false, then the default message for empty values is set. Currently there is no way to customize this message for a specific field.
The behavior has not changed. This is a bug (http://framework.zend.com/issues/browse/ZF-7394)
try this:
$validators = array(
'salutation' => array('NotEmpty', Zend_Filter_Input::MESSAGES => 'Please enter a salutation')
);
I don't know why, but seems they changed the constant "isEmpty" with "NotEmpty" (without including it in the Zend_Validate_NotEmpty class).
Sometimes I just go nuts with Zend. :)
Related
I got stuck with this stupid error messages in Zend Framework 2. Spent two hours and nothing, I still got two different error messages with NotEmpty validator.
$nameNotEmptyMessage = 'Pole wymagane';
$inputFilter->add(array(
'name' => 'name',
'required' => true,
'filters' => array(
new Filter\StringTrim()
),
'validators' => array(
new Validator\NotEmpty(array(
'messages' => array(
Validator\NotEmpty::INVALID => $nameNotEmptyMessage,
Validator\NotEmpty::IS_EMPTY => $nameNotEmptyMessage
)
))
)
));
And what? It works pretty cool when I send form with "name" element inside it. When it's empty, I've got my message. But, when I send form without the "name" element inside it, the message is still "Value is required and can't be empty"! Why?
I need to have in both cases the same message because sometimes the form won't have "name" element.
Thank you guys very much!
Thanks for replying to the comment to clarify the problem. First I must say, I feel your pain on this one. After having not used ZF2 for over a year and spending some time figuring this out, it highlights yet another painful thing in ZF2.
That said, here is my simple solution. Not necessary correct, or the best way to go about it but it solves your problem with the least amount of code. In your controller where you instantiate and validate the form, add this code before you call new Form:
if (!isset($_POST['name'])) {
$this->getRequest()
->setPost(
new \Zend\Stdlib\Parameters(
array('name' => '')
)
);
}
This seemed the simplest route rather than setting up a default validation translator and adding a duplicate message. It is just checking to see if the name field was not present, and if so sets it with any empty value.
Now the reason why we have to do this:
This happens because of how \Zend\InputFilter\Input works. When the InputFilter runs, it sees the element is missing. It then checks the required property, sees it's true but the input has no value. No value being different than empty.
When the filter is required but has no input, \Zend\InputFilter\Input::prepareRequiredValidationFailureMessage is called. If you look at the source of that function, you'll see:
protected function prepareRequiredValidationFailureMessage()
{
$notEmpty = new NotEmpty();
$templates = $notEmpty->getOption('messageTemplates');
return [
NotEmpty::IS_EMPTY => $templates[NotEmpty::IS_EMPTY],
];
}
Notice how it creates a new NotEmpty validator and fetches its default message, thus bypassing the translation you set within the InputFilter.
The alternative:
One alternative, which may be more correct, but also requires more code and could arguably be more confusing looking back later would be to create a new class implementing \Zend\Validator\Translator\TranslatorInterface and set an array with the translation for that message and then calling \Zend\Validator\AbstractValidator::setDefaultTranslator passing that so the default translator will be used on that message.
This is just difficult because there is no short way of setting up that object because of how the classes are inherited and I wasn't able to find a quick solution to set up the default translator with just that message. Also, if you have another translator in place, it might interfere with it.
So it seems the simplest thing is to just check for the absence of that form field and populate it with any empty value if it's missing.
Hope that helps!
Other more simple way to fix this is to overwrite the Form setData($data) and to check if $data['name'] is set. Something like this:
public function setData($data)
{
if(!isset($data['name'])){
$data['name'] = '';
}
return parent::setData($data);
}
There's any way to do something like this using Phalcon's validation feature:
$validation->add('telephone', new PresenceOf( [
'message' => 'The telephone is required',
'onFail' => //Validate this,
'onSuccess' => //Validate that
]));
EDIT:
Well, I asking for this because I have some validations that should run only if 2 or 3 conditions are matched in any order, so the cancelOnFail property wouldn't help me that much here.
Maybe if I create a custom validation group like $validation->add('stuff', new ComplexValidation()) but the order still a problem. The way that this validation system works is quite linear. Taking theses considerations, how can I implement more complex validations with Phalcon?
Yes. Phalcon has a validation system which works similarly. The following code would be used to ensure the 'telephone' field is supplied:
$this->validate(new PresenceOf(
array(
"field" => "telephone",
"message" => "The telephone is required"
)
));
This validator is called on the model in the validation() function. According to the documentation, the PresenceOf validator is automatically added for fields marked as ‘not null’ in the model’s table. If I understand this correctly, you actually do not need to insert this code if your field is ‘not null’, though you can do so if you want to override the default ‘validation failed’ message for this specific form. You can modify the default validation message (and supply translations) by overriding the getMessages() function in your model. There’s additional information on Phalcon's validation message system here.
The failure message is aggregated with other messages from other field validations (such as Uniqueness, for example). For each failed validation, you can access the message, field, type (and originating model). The following code would output all the information contained in the message, for each failed validation:
if ($form->save() == false) {
foreach ($form->getMessages() as $message) {
echo "Message: ", $message->getMessage();
echo "Field: ", $message->getField();
echo "Type: ", $message->getType();
echo "Model: ", $message->getModel();
}
}
I’ve noticed two different approaches to informing users of validation messages: placed together before the form (as shown here) or placed near the form input itself. If you want to output the message close to the input, you may need to iterate over each message (from getMessages()) and check for the field name which matches your input, then echo the message using getMessage().
I’m very new to Phalcon myself, so I haven’t explored all the functionality of validators, yet. There is an event system that you can use to insert code beforeValidation and afterValidation. That may be one place to look for outputting a successful validation message.
I was investigating CakePHP (2.3.4) Model::save method to insert new records and ran into a little snag:
//Two fields provided, email field intended to fail validation
$data = array('Member' => array(
'username' => 'hello',
'email' => 'world'
));
$this->Member->create();
var_dump($this->Member->save($data, true));
The above save() will return false and no data will be written to the database. However if I change the data to:
//One field provided, intended to pass validation
$data = array('Member' => array(
'username' => 'hello'
));
then save() will attempt to write a new record to database with a blank email field. I realize that skipping validation for unspecified fields might be a useful behavior during updates, but is there a CakePHP recommended way to handle partially empty data sets when creating new records? Thanks a lot.
Edit:
Thanks to Sam Delaney for the tip. In case anybody else gets stumped, this did the trick: CakePHP Data Validation: field 'required' key
This key accepts either a boolean, or create or update. Setting this key to true will make the field always required. While setting it to create or update will make the field required only for update or create operations. If ‘required’ is evaluated to true, the field must be present in the data array. For example, if the validation rule has been defined as follows:
I had originally baked the model and forgotten that required => true was left out of the validation rule. Setting it to true or 'create' would've avoided me blank records getting inserted due to gibberish data array.
IMHO what you've experienced is the desired behavior. Consider that you have the same two fields within a form and the user provides a value for only username. Both username and email field are submitted even though email is empty. Then on the server, you try to save the record only to find out that it has failed validation which you feedback to the user. On the other hand, perhaps in your system it is perfectly possible to create a user without requiring an email (for example root access account), CakePHP's validation implementation allows both of these scenarios.
If this flexibility isn't what you desire, just set the required attribute for your validation rule as true:
public $validate = array(
'email' => array(
'rule' => 'email',
'required' => true
)
);
This will satisfy your all or nothing requirement.
I have a pretty simple form with some fields from a doctrine model.
$this->widgetSchema['fields'] = new sfWidgetFormDoctrineChoice(array(
'model' => 'FieldModel',
'expanded' => true,
'multiple' => true,));
$this->validatorSchema['fields'] = new sfValidatorDoctrineChoice(array(
'model' => 'FieldModel',
'multiple' => true,));
The fields are rendered in the form as checkboxes and I'm able to check and save correctly. This 'fields'-field is converted to a json-structure and saved to the database as text. So far so good.
NOTE: The field 'fields' is stored as TEXT in the database, but the user should be able to select values from a list of checkboxes.
The problem arise when I want to have some of the checkboxes checked by default.
I tried to do:
$this->setDefault('fields', array('key1','key2','key3'));
Where 'keyX' correspond to the actual value of the primary key (string) for Field in the database.
If I do a
$this->getDefault('fields');
I get back exactly what I put in previously.
However, symfony is not outputing any of the checkboxes as checked. I have even tried to remove both the 'expanded' and 'multiple' options to the choice-widget so I get a simple SELECT-box and the provide only one value as default selected.
Setting default values for other widgets (text-inputs, choice, etc) work.
Btw; The Field-model is i18n. Don't know if that matters here, since both storing / retrieving works as expected.
Also; the form is rendered as part of another form by means of include_partial(). Can that sabotage anything? In the 'parent' form class:
$this->embedRelation('TheRelationThatBugsMe');
And then in the _form.php for the 'parent':
include_partial('the_relation_that_bugs_me/form', array('form' => $form['TheRelationThatBugsMe']));
Does anyone have an idea where I might have gone wrong, or at least can give me some pointers as to where I should start digging?
[UPDATE]
If I create a new field in the form 'fields2' (that does not exist as a field in the database) and use the exact same code to create widget, validator and set defaults, then the defaults are rendered correctly. How come it doesn't work setting defaults for a field mapped to a column in the database?
If you're calling setDefault before updateDefaultFromObject gets called in sfDoctrineForm, then the object's values will override form defaults if the object exists. updateDefaultsFromObject contains the relevant logic. You'll have to call setDefault later, or override the method.
When using a Zend_Form, the only way to validate that an input is not left blank is to do
$element->setRequired(true);
If this is not set and the element is blank, it appears to me that validation is not run on the element.
If I do use setRequired(), the element is automatically given the standard NotEmpty validator. The thing is that the error message with this validator sucks, "Value is empty, but a non-empty value is required". I want to change this message. At the moment I have done this by changing the Zend_Validate_NotEmpty class, but this is a bit hacky.
I would ideally like to be able to use my own class (derived from Zend_Validate_NotEmpty) to perform the not empty check.
I did it this way (ZF 1.5):
$name = new Zend_Form_Element_Text('name');
$name->setLabel('Full Name: ')
->setRequired(true)
->addFilter('StripTags')
->addFilter('StringTrim')
->addValidator($MyNotEmpty);
so, the addValidator() is the interesting part. The Message is set in an "Errormessage File" (to bundle all custom messages in one file):
$MyNotEmpty = new Zend_Validate_NotEmpty();
$MyNotEmpty->setMessage($trans->translate('err.IS_EMPTY'),Zend_Validate_NotEmpty::IS_EMPTY);
hope this helps...
By default, setRequired(true) tells isValid() to add a NonEmpty validation if one doesn't already exist. Since this validation doesn't exist until isValid() is called, you can't set the message.
The easiest solution is to simply manually add a NonEmpty validation before isValid() is called and set it's message accordingly.
$username = new Zend_Form_Element_Text('username');
$username->setRequired(true)
->addValidator('NotEmpty', true, array('messages' => array('isEmpty' => 'Empty!')));
Add a NotEmpty validator, and add your own message:
// In the form class:
$username = $this->createElement('text', 'username');
$username->setRequired(); // Note that this seems to be required!
$username->addValidator('NotEmpty', true, array(
'messages' => array(
'isEmpty' => 'my localized err msg')));
Note that the NotEmpty validator doesn't seem to be triggered unless you've also called setRequired() on the element.
In the controller (or wherever), call $form->setTranslator($yourTranslator) to localize the error message when it's printed to the page.
Change the error message.
As far as I can see Changing the error message has no way of changing the message of a specific error. Plus the manual makes it look like like this is a function belonging to Zend_Form, but I get method not found when using it on an instance of Zend_Form.
And example of the useage would be really great.