ZF-6457: Zend_Validate_Date doesn't validate a value filtered by Zend_Filter_LocalizedToNormalized

Description

When filtering a value using the new Zend_Filter_LocalizedToNormalized, Zend_Validate_Date doesn't recognize the normalized date array. Zend_Validate_Date::isValid($value) just convert $value parameter to array. Or maybe Zend_Filter_LocalizedToNormalized could return a Zend_Date object, then Zend_Validate_Date should recognize a Zend_Date object. It's necessary, specially, when using Zend_Filter_Input to make batch filtering and validation. If it isn't solved, how could we use Zend_Filter_Input to convert and validate dates?

Actually, i think there is another questions about dates filtering and validations. Like, for example, it should be possible using Zend_Validate_GreaterThan, Between, Identical and LessThan to make aditional dates validations.

Comments

Why would you want to validate a normalized date with a localized validator ?

Zend_Filter_LocalizedToNormalized will not return a localized date object. A normalized date is, when the date object is splitted into it's date parts. That's the reason why you get a array. A string is always localized due to dayname, monthname timezone and so on... A normalized date is no longer a Zend_Date object, that's the difference.

Additional you should note that a validator does never change content. A validator does only return true or false.

In my eyes this is not a bug but a discussable feature enhancement.

Regarding the other filters... you should not that these filters check only numbers. There are already proposals for date validators but they have not been approved for incubator until now. But as said... also this is a new feature and not a bug.

Ok. Let's make the things clear. A normal register process works the following way: 1 - The user types his name and date of birth in a form. Let's suppose the date field is in format "d/m/Y". 2 - The user clicks on the submit button. Then i use Zend_Filter_Input to make data processing. The problem is: how could i use Zend_Filter_Input to filter and validate this date?

First: Validate the input and look if it conforms your needs. Second: Filter the validated and correct value for further processing for your application.

The thing is: It would make no sense to filter/change the input when it's not valid.

So, did you mean i can't use Zend_Filter_Input? Because Zend_Filter_Input filters, then validates. And you suggested the inverse order.

In addition, using Zend_Filter_Input in only one execution have some problems. If you say the correct order is validate the input, then filter the validated and correct value, we have a problem here. For example, if a user enter with the value (1,500.00) of a number field and click submit , we can have the following validation rules to apply in Zend_Filter_Input:

$validation = array( 'salary' => array('Float', array('Between', 0, 99999999.99) );

But, making validation before filtering, Float validation will pass (because 1.8 supports locale), but the Between validation will fail. I'm not sure about the best solution to make these things with only one instance of Zend_Filter_Input, maybe we could define a chain combining filters and validations, something like:

$chain = array( 'filters' => array( 'name' => 'StringTrim', 'biografy' => 'StringTrim', 'StripTags' ), 'validators' => array( 'name' => 'notEmpty', 'Alnum', array('StringLength', 1, 100), 'biografy' => array('StringLength', 0, 1000), 'salary' => 'Float' ), 'filter' => array( 'salary' => new Zend_Filter_LocalizedToNormalized(array('precision' => 2)) ), 'validators' => array( 'salary' => array('Between', 0, 99999999.99) ) );

And use a new class Zend_Filter_Input_Chain:

$input = Zend_Filter_Input_Chain($chain, $data, $options);

Just correcting the array:

$chain = array( 'filters' => array( 'name' => 'StringTrim', 'biografy' => array('StringTrim', 'StripTags') ), 'validators' => array( 'name' => array('notEmpty', 'Alnum', array('StringLength', 1, 100)), 'biografy' => array(array('StringLength', 0, 1000)), 'salary' => 'Float' ), 'filter' => array( 'salary' => new Zend_Filter_LocalizedToNormalized(array('precision' => 2)) ), 'validators' => array( 'salary' => array(array('Between', 0, 99999999.99)) ) );

An for date processing, we could have:

$chain = array( 'validators' => array( 'birth_date' => 'Date', 'another_field' => 'AnotherValidator' ), 'filters' => array( 'birth_date' => 'DateFormat', // For converting a string date to Zend_Date ), 'validators' => array( 'birth_date' => array( 'DateGreaterThan', $date ) // Zend_Date objects validations ) );

Just complementing the idea:

$chain = array( ... 'filters' => array( 'birth_date' => 'DateObjectToDb' // For converting a Zend_Date to database format ) );

Well, that's my idea. It's really a bit immature yet. But the idea is that we could have as many as possible data filtering and processing using Zend_Filter_Input.

Please note that this issue is about Zend_Validate_Date. Zend_Filter_Input improvements are not part of this issue.

As said before: When you propose a improvement for a component then please fill in a new issue for this particular component.

Ok, i will open a improvement issue for Zend_Filter_Input.

Thomas, i agree that the issue is about Zend_Validate_Date, but it's related to Zend_Filter_Input too. So, i would like you answer me the following question:

You said:

"First: Validate the input and look if it conforms your needs. Second: Filter the validated and correct value for further processing for your application.

The thing is: It would make no sense to filter/change the input when it's not valid."

The question is: processing order of Zend_Filter_Input is filter, then validate. So, how do you explain your comment? Are you suggesting i can't use Zend_Filter_Input? In addition, would we use only simple filters with Zend_Filter_Input, like StringTrim or HtmlEntities because "it would make no sense to filter/change the input when it's not valid", as you said? If not, i think my new issue #ZF-6478 could be the solution.

I don't know Zend_Filter_Input, but the mentioned filter and the validator to which you wrote your issue are by me so I know how they work.

Zend_Validate_Date allows it to validate localized dates. As you already know the format as you mentioned before simply give this format to Zend_Validate_Date.

There is no reason to change the date to a normalized array just for that. you would need a normalization of dates when you want to store them into a database for example or do something else like only have the year or do some further processing.

A normalized date input is no longer a date object. As mentioned a date object is always localized. So the main question is: Why would you have a need to normalize a date in your case ? According to your point 1 you already know the format you expect and when your user does not input his date in the proper format, Zend_Validate_Date will return false. No need to normalize this date.

When you need the date in a different format then there is actually no filter available as you want to change from one localized format to another one. This is actually not supported.

I could imagine one way... add a LocalizeToNormalize and additionally as imediately next filter a NormalizedToLocalized filter with the format you want to have, and then give this format to ValidateDate when the validator is processed AFTER the filter.

Your problem is that the date looks differently before and after filtering. You need to know which of the dates you want to validate... the date before or the date after.

This is untested but it could work.

So, due to your answer, let's agree that sometimes it makes sense filter/change the value before validating, right? But this is due to the current behavior of Zend_Filter_Input, because, if we can pass a chain of operations in Zend_Filter_Input, as i suggested in #ZF-6478, so we could validate a date string, then convert it to database format. And, in future, when additional date validators are available, we can validate a date string, convert it to Zend_Date, make date operations validation (GreaterThan, Between and etc) and, finally, convert it to database format, to store the register.

I like to make filtering and validating in the model, because i have models saved from anothers models, so, for example, sometimes the programmers can define values that doen'st come from user input, so when a child model is saved from it's parent model _postInsert method, for example, i can avoid that programmers set wrong values to the row objects and, consequentially, a database, like mysql, set a default value like '0000-00-00' to a date column. Therefore, pass a operations chain to Zend_Filter_Input, would be great.

Fixed with r17695