zend Identical Validator problem when leaving one element empty - php

I'm using the following code:
$form->addElement('password', 'elementOne');
$form->addElement('password', 'elementTwo', array(
'validators' => array(
array('identical', false, array('token' => 'elementOne'))
)
));
If both texts are different I get an error from the validator, but if I leave the second one empty the validation wont fire. why?
(I dont want to put the fields as required because the user should fill them only if he wants to change the password but he could also leave them empty)
What am I doing wrong? should I put the validator on both elements?

The problem was the AllowEmpty flag (when the element is not required this flag is set to true). I set it to false and the validator is now firing as expected.
setAllowEmpty(false)

$form->addElement('password', 'elementOne');
$form->addElement('password', 'elementTwo', array(
'validators' => array(
array('identical', false, array('token' => $_POST['elementOne']))
)
));

Related

CakePHP validation error on an optional field

I'm creating a form in CakePHP, where there is a field that is output only on certain conditions. However, when it is not output, validation invalidates it. I'm not sure where I did wrong?
Validation in Model:
public $validate = array(
'extra_requirement_ok' => array(
'notEmpty' => array(
'rule' => array('comparison', '!=', 0),
//'required' => false,
'message' => 'Must'
),
),
);
The input in the view:
if ($check) {
echo $this->Form->input('extra_requirement_ok');
}
EDITED:
When I check the data that is passed when is submitted, array key for extra_requirement_ok does not exist. But I created a custom validation and check the array that is passed to the custom validation function, it returns extra_requirement_ok = '0'. What gives?
I figured this out.
I set 0 as defined value in the database, as the data is being saved, 0 is generated by default and that triggered validation. Now the database column is set to NULL and it's fine now.

Change validation rules on the fly

I'm working on a form that contains user data, specifically a phone number field. The phone number typically isn't required so the only validation rule in the model is the usphone rule. However, if the user is submitting this form, the phone number becomes necessary. I thought I'd be able to simply add a validate rule on the fly, set the model and call the validates method, but either I'm doing it wrong or it's not working the way I expected.
In my controller:
# Update a few validation rules that are specific to this context
$this->Proposal->Requestor->validate['phone_number']['notempty'] = array(
'rule' => 'notEmpty',
'message' => 'Please enter a phone number so can can contact you with any questions about the work.',
'allowEmpty' => false,
'required' => true,
);
$validationErrors = array();
$this->Proposal->Requestor->set( $this->data['Requestor'] ); # $this->data['Requestor']['phone_number'] only (no other requestor data)
if( !$this->Proposal->Requestor->validates( array( 'fieldList' => array( 'phone_number' ) ) ) ) {
$validationErrors['Requestor'] = $this->Proposal->Requestor->validationErrors;
}
No errors are reported, even if I leave the phone number field empty. In this case, the only information I'm requesting from the user is their phone number, so the rest of the Requestor data is empty, but I've tried merging in the rest of the user data and I get the same result. If I remove the fieldList option, I get an error on a different field, but still nothing on the empty phone number.
Any idea what I'm missing here? I've been monkeying around with this for hours now and I just haven't found the right answer.
Thanks.
The solution ended up being twofold:
I had existing rule on the phone_number field that forced the value to be a US phone number. That rule also set allowEmpty to true and required to false. I wanted to catch an empty value so I could display a particularly precise message.
I had to update the existing rule to flip the allowEmpty and required values and also add a new rule with its last value set to true.
The final change, added in my controller action looks like this:
$this->Proposal->Requestor->validate = Set::merge(
$this->Proposal->Requestor->validate,
array(
'phone_number' => array(
'notempty' => array(
'rule' => 'notEmpty',
'message' => 'Please enter a phone number so can can contact you with any questions about the work.',
'allowEmpty' => false,
'required' => true,
'last' => true,
),
'usphone' => array(
'allowEmpty' => false,
'required' => true,
),
)
)
);
I can't remember whether I verified that the change to the existing usphone rule was strictly necessary given the last value of the new rule, but this combination is working fine.
You could try using the Multivalidatable Behaviour - http://bakery.cakephp.org/articles/dardosordi/2008/07/29/multivalidatablebehavior-using-many-validation-rulesets-per-model

How can I customise Zend_Form regex error messages?

I have the following code:
$postcode = $form->createElement('text', 'postcode');
$postcode->setLabel('Post code:');
$postcode->addValidator('regex', false,
array('/^[a-z]{1,3}[0-9]{1,3} ?[0-9]{1,3}[a-z]{1,3}$/i'));
$postcode->addFilters(array('StringToUpper'));
$postcode->setRequired(true);
It creates an input field in a form and sets a regex validation rule and works just fine.
The problem is that the error message it displays when a user enters an invalid postcode is this:
'POSTCODE' does not match against pattern
'/^[a-z]{1,3}[0-9]{1,3} ?[0-9]{1,3}[a-z]{1,3}$/i'
(where input was POSTCODE)
How can I change this message to be a little more friendly?
I think to remember, you can set the error message in the Validator:
$postcode = $form->createElement('text', 'postcode');
$postcode->setLabel('Post code:');
$postcode->addValidator('regex', false, array(
'pattern' => '/^[a-z]{1,3}[0-9]{1,3} ?[0-9]{1,3}[a-z]{1,3}$/i')
'messages' => array(
'regexInvalid' => "Invalid type given, value should be string, integer or float",
'regexNotMatch' => "'%value%' does not match against pattern '%pattern%'",
'regexErrorous' => "There was an internal error while using the pattern '%pattern%'"
)
);
$postcode->addFilters(array('StringToUpper'));
$postcode->setRequired(true);
If that doesn't work, try
setErrorMessages(array $messages): add multiple error messages to display on form validation errors, overwriting all previously set error messages.
If you define your validator as external variable use setMessage():
$validator = new Zend_Validate_Alnum();
$validator->setMessage('My custom error message for given validation rule',
Zend_Validate_Alnum::INVALID);
$formElement->addValidator($validator);
As you see in example above validator for form doesn't differ from any other kind of Zend_Validate_* instances.
Setting up validation messages involves looking into API Docs and finding out message constant for a given validation error (as I did in case of Zend_Validate_Alnum::INVALID). Of course if your IDE provides good context auto-completion just typing the validator class can be enough - as message constants are really self-explanatory in most cases.
Another way would be to use Zend_Form's magic methods, and simply passing 'messages' key, as a parameter to your validator:
$formElement->addValidator(array(
'alnum', false, array('messages' => array(
Zend_Validate_Alnum::INVALID => 'my message'
))
));
This would internally trigger the setMessages() method defined in Zend_Validate_Abstract, and in essence just a short-cut/time-saver defined for Zend_Form's.
NB: There's a dedicated section in ZF Manual regarding validation messages.
You could use the original Zend postcode validator
$user->addElement('text', 'postcode', array('label' => 'Postcode *',
'required' => true,
'class' => 'postcode_anywhere',
"validators" => array(
array("NotEmpty", false, array("messages" => array("isEmpty" => "Required *"),)),
array('PostCode', false, array('locale' => 'en_GB')
)
),
'filters' => array(array('StringToUpper')),
'class' => 'text'
)
);

Access custom error messages for InArray validator when using Zend_Form_Element_Select

I'm using Zend Framework 1.62 (becuase we are deploying the finished product to a Red Hat instance, which doesn't have a hgih enough PHP version to support > ZF1.62).
When creating a Form using Zend Form, I add a select element, add some multi options.
I use the Zend Form as an in-object validation layer, passing an objects values through it and using the isValid method to determine if all the values fall within normal parameters.
Zend_Form_Element_Select works exactly as expected, showing invalid if any other value is input other than one of the multi select options I added.
The problem comes when I want to display the form at some point, I cant edit the error message created by the pre registered 'InArray' validator added automatically by ZF. I know I can disable this behaviour, but it works great apart from the error messages. I've tryed the following:
$this->getElement('country')->getValidator('InArray')->setMessage('The country is not in the approved lists of countries');
// Doesn't work at all.
$this->getElement('country')->setErrorMessage('The country is not in the approved lists of countries');
// Causes a conflict elswhere in the application and doesnt allow granular control of error messages.
Anyone have any ideas?
Ben
I usually set validators as per my example below:
$this->addElement('text', 'employee_email', array(
'filters' => array('StringTrim'),
'validators' => array(
array('Db_NoRecordExists', false, array(
'employees',
'employee_email',
'messages' => array(Zend_Validate_Db_Abstract::ERROR_RECORD_FOUND => 'A user with email address %value% already exists')
))
),
'label' => 'Email address',
'required' => true,
));
The validators array in the element options can take a validator name (string) or an array.
When an array is passed, the first value is the name, and the third is an array of options for the validator. You can specify a key messages with custom messages for your element in this array of options.
If your using Zend_Form_Element_Select (or any of the Multi subclasses), on validation the InArray validator will only be automatically added if there is not one present.
You can set a validator as so:
$options = array(...);
$this->addElement('select', 'agree', array(
'validators' => array(
array('InArray', true, array(
'messages' => array(
Zend_Validate_InArray::NOT_IN_ARRAY => 'Custom message here',
),
'haystack' => array_keys($options),
)),
'multiOptions' => $options,
));
and then your validator will be used instead of the automatically attached one.
$el = $this->addElement($name, $label, $require, 'select');
$validator = new Zend_Validate_InArray(array_keys(AZend_Geo::getStatesList()));
$validator->setMessage('Invalid US State.');
$el
->setMultiOptions(AZend_Geo::getStatesList())
->setRegisterInArrayValidator(false)
->addValidator($validator)
->addFilter(new Zend_Filter_StringToUpper())
->addFilter(new T3LeadBody_Filter_SetNull())
->setDescription('US State. 2 char.');

Zend Form Edit and Zend_Validate_Db_NoRecordExists

I am slowly building up my Zend skills by building some utility websites for my own use. I have been using Zend Forms and Form validation and so far have been happy that I have been understanding the Zend way of doing things. However I am a bit confused with how to use Zend_Validate_Db_NoRecordExists() in the context of an edit form and a field that maps to database column that has to be unique.
For example using this simple table
TABLE Test
(
ID INT AUTO_INCREMENT,
Data INT UNIQUE
);
If I was simply adding a new row to the Table Test, I could add a validator to the Zend Form element for the Data field as such:
$data = new Zend_Form_Element_Text('Data');
$data->addValidator( new Zend_Validate_Db_NoRecordExists('Test', 'Data') )
At form validation this validator will check that the contents of the Data element does not already exist in the table. Thus the insert into Test can go ahead without violating the Data fields UNIQUE qualifier.
However the situation is different when editing an existing row of the Test table. In that case the validator needs to check that the element value meets one of two mutually exclusive conditions conditions:
The user has changed the element value, and the new value does not currently
exist in the table.
The user has Not changed the element value. Thus the value does currently exist in the table (and this is OK).
The Zend Validation Docs talk about adding a parameter to the NoRecordExists() validator for the purpose of excluding records from the validation process. The idea being to "validate the table looking for any matching rows, but ignore any hits where the a field has this specific value". Such a use case is what is needed for the validating the element when editing a table. The pseudo code to do this in 1.9 is like so (actually I got this from the 1.9 source code - I think the current docs may be wrong):
$data = new Zend_Form_Element_Text('Data');
$data->addValidator( new Zend_Validate_Db_NoRecordExists('Test', 'Data',
array ('field'=>'Data', 'Value'=> $Value) );
The problem is that the value that is to be excluded ($Value) is bound to the validator at the time it is instantiated (also when the form is instantiated). But when the form is editing a record, that value needs to be bound to the contents of the $data field when the form was initially populated with data - IE the Data value initially read from the Test table row. But in typical Zend patterns a form is instantiated and populated in two separate steps which precludes binding the exclude value to the desired element value.
The following Zend psuedo code marks where I would like the binding of $Value to the NoRecordExists() validator to occur (and note that this is a common Zend controller pattern):
$form = new Form()
if (is Post) {
$formData = GetPostData()
if ($form->isValid($formData)) {
Update Table with $formData
Redirect out of here
} else {
$form->populate($formData)
}
} else {
$RowData = Get Data from Table
$form->populate($RowData) <=== This is where I want ('value' => $Value) bound
}
I could sub-class Zend_Form and override the populate() method to do a one-shot insertion of the NoRecordExists() validator on initial form population, but that seems like a huge hack to me. So I wanted to know what other people think and is there some pattern already written down that solves this problem?
Edit 2009-02-04
I've been thinking that the only decent solution to this problem is to write a custom validator and forget about the Zend version. My form has the record ID as hidden field, so that given the table and column names I could craft some SQL to test for uniqueness and exclude the row with an ID of such an such. Of course this started me thinking about how I would be tying the form to the dB layer that the Model is supposed to hide!
This is how it's done:
I your FORM, you add this validator (for example email field):
$email->addValidator('Db_NoRecordExists', true, array('table' => 'user', 'field' => 'email'));
Don't add custom error message for this since after that it didn't work for me, e.g.:
$email->getValidator('Db_NoRecordExists')->setMessage('This email is already registered.');
In your Controller add this:
/* Don't check for Db_NoRecordExists if editing the same field */
$form->getElement('email')
->addValidator('Db_NoRecordExists',
false,
array('table' => 'user',
'field' => 'email',
'exclude' => array ('field' => 'id', 'value' => $this->request->get('id'))));
And after this you do verifications, e.g.:
if ($this->getRequest()->isPost())
{
if($form->isValid($this->getRequest()->getPost()))
{
....
That's it!
This will also work :
$this->addElement('text', 'email', array(
'label' => 'Your email address:',
'required' => true,
'filters' => array('StringTrim'),
'validators' => array(
'EmailAddress',
array('Db_NoRecordExists', true, array(
'table' => 'guestbook',
'field' => 'email',
'messages' => array(
'recordFound' => 'Email already taken'
)
)
)
)
));
After reviewing the overwhelming response I've decided that I'm going with a custom validator
Look at this one:
Answer raised by me and well-solved by Dickie
private $_id;
public function setId($id=null)
{
$this->_id=$id;
}
public function init()
{
.....
if(isset($this->_id)){
$email->addValidator('Db_NoRecordExists', false, array('table' => 'user', 'field' => 'email','exclude' => array ('field' => 'id', 'value' => $this->_id) ));
$email->getValidator('Db_NoRecordExists')->setMessage('This email is already registered.');
}
Now u can use:
$form = new Form_Test(array('id'=>$id));
You could just call $form->getElement('input')->removeValidator('Zend_Validator_Db_NoRecordExists'); instead of supplying the exclusion.
I have just tried this example for email address uniqueness and it works perfectly with below stuffs :
1] In my form:
// Add an email element
$this->addElement('text', 'email', array(
'label' => 'Email :',
'required' => true,
'filters' => array('StringTrim'),
'validators' => array(
'EmailAddress',
)
));
Here's something special that I needed to add for unique email address to work:
$email = new Zend_Form_Element_Text('email');
$email->addValidator('Db_NoRecordExists', true, array('table' => 'guestbook', 'field' => 'email'));
2] In my controller:
$form->getElement('email')
->addValidator('Db_NoRecordExists',
false,
array('table' => 'guestbook',
'field' => 'email',
'exclude' => array ('field' => 'id', 'value' => $request->get('id'))));
if ($this->getRequest()->isPost()) {
if ($form->isValid($request->getPost())) {
Hope it helps you people !
Thanks

Categories