Tuesday, February 5, 2013

Custom Format for Date Validator

The Date validator, when created with no 'format' option, will default to 'yyyy-mm-dd', or as a PHP format string, 'Y-m-d'. If you want to use a custom date format, the Date validator doesn't seem to be quite adequate. It relies on PHP being able to create a valid date with

DateTime::createFromFormat($format, $value)

It will also blindly validate any pure integer inputs, assuming no error is thrown when attempting to create a date with that integer as a timestamp. So, if you want a date to be in the format (mm-dd-yyyy), you would use the format string 'm-d-Y', but there are a lot of invalid dates that will still pass. For example, if someone enters '12-12-99', it will validate. While it is easy for a human to look at that and know that they probably meant 1999, your date parser might not handle it well (what you do with the validated date is up to you). For proper input validation in a case like this, you really need a regex validator (the default format checks against a regex behind the scenes, but not for custom formats).
                'validators'=>array(
                    array(  
                        'name'=>'Date',
                        'break_chain_on_failure'=>true,
                        'options'=>array(
                            'format'=>'m-d-Y',
                            'messages'=>array(
                                'dateFalseFormat'=>'Invalid date format, must be mm-dd-yyy', 
                                'dateInvalidDate'=>'Invalid date, must be mm-dd-yyy'
                            ),
                        ),      
                    ),      
                    array(  
                        'name'=>'Regex',
                        'options'=>array(
                            'messages'=>array('regexNotMatch'=>'Invalid date format, must be mm-dd-yyy'),
                            'pattern'=>'/^\d{1,2}-\d{1,2}-\d{4}$/',
                        ),      
                    ),      
                ),   
This particular regex will work with 1 or 2 digit days and months, because when I parse the date while handling the posted form data, I accept that format as well.
Note that I set a few custom error messages. 'dateInvalidDate' should display when a date like 13-13-1999 is entered, while the other message should show up for anything that doesn't match the specified format. 'break_chain_on_failure' is needed to prevent duplicate errors from displaying when the format is invalid.