I already postet an article about custom validation rules some time ago here.
In this post I introduce some of my custom rules which come in handy quite often.
For being able to use it in different projects I do not use the app model for it but a plugin lib.
My app model then extends this lib (/libs/my_model.php):
App::import(‘Lib’, ‘PluginName.MyModel’) and AppModel extends MyModel.
I do not want to post the methods here in the blog because they might change over time. You can find the current source code at my github rep (test case).
Lets get started.
The following code fragments are part of the $validate array of the specific model you want to validate.
Validating urls
The core rule does not validate “deep” – meaning it cannot check if the url is actually accessible/correct.
My custom rule works like this:
'field' => array( 'validateUrl' => array( 'rule' => array('validateUrl', array('autoComplete'=>true)), 'message' => 'Not a valid url', ), ),
By default, it will check deep and make sure the url actually exists.
With the autoComplete param you can be more flexible with urls that are missing “http://” etc (note/todo: it would be even better if it would save the autocompleted string). Especially in combination with strict=>true.
If we want to allow only links on the same domain we could say
'field' => array( 'validate' => array( 'rule' => array('validate', array('autoComplete'=>true, 'sameDomain'=>true)), 'message' => 'Please provide a valid url on the same domain', ), ),
Now /some/link as well as http://samedomain.com/some/link works.
With deep=>false we can disable the deep check for availability.
Validating dates and times
The main improvements are the before/after params:
'end_date' => array( 'validate' => array( 'rule' => array('validateDatetime', array('after'=>'start_date')), 'message' => 'Please provide a valid date later than the start date', ), ),
There are also date and time only versions like
'time' => array( 'validate' => array( 'rule' => array('validateTime', array('allowEmpty'=>true)), 'message' => 'Please provide a valid time or leave the field empty', ), ),
I also had to hack around problems regarding empty strings or partially invalid dates. thats why this method is quite long compared to others.
Validating keys (primary/foreign)
'id' => array( 'validate' => array( 'rule' => array('validateKey'), 'message' => 'Invalid primary key', ), ), 'foreign_id' => array( 'validate' => array( 'rule' => array('validateKey', array('allowEmpty'=>true)), 'message' => 'Invalid foreign key', ), ),
The id can be either aiid (int10) or uuid (char36), the method will always validate correctly.
Same goes for foreign_id. But due to the allowEmpty it can also be left empty (or 0 for aiids).
Validating enums
Sometimes the enums are “dynamically” generated. You cannot use the build in “inList” validation rule then.
If you have a method set up, you can call this from within the rule:
'field' => array( 'validate' => array( 'rule' => array('validateEnum', 'methodX'), 'message' => 'Invalid value', ), ),
Somewhere in the model define your custom enum value generator:
function methodX() { return array(...); }
Validating uniqueness
With this enhanced method we can check on other fields – dependent uniqueness so to speak.
'field' => array( 'validate' => array( 'rule' => array('validateUnique', array('user_id')), 'message' => 'You already have an entry', ), ),
In this case the field will only invalidate if this specific user has already an entry.
Two users can have the same field content without interfering each other.
TODO: test cases with fixtures etc in order to simulate DB content to validate against…
Validating identical
'email_confirm' => array( 'validate' => array( 'rule' => array('validateIdentical', 'email'), 'message' => 'The two fields do not match', ), ),
As you can see this rule comes in handy if you need to confirm a string to another in the post data. Simply pass the field name along as second param.
Last Words
Hopefully many other cake developers find those enhanced rules useful and maybe they set the core team thinking about implementing some of the features in the future versions of cake.
Please note:
Some of the internal methods, constants etc used might be not available without stuff from my tools plugin.
Those validation methods above might have to be adjusted to your application. Same goes for the test case which uses some of my own methods/libs to work with.
