CakePHP provides a handful of validation rules out of the box, which together covers the need for most applications. The following table lists the built-in validation rules (found in CakePHP's Validation
class.)
Rule |
Purpose |
---|---|
|
Checks that the value contains only integers or letters. |
|
Checks that the string length of the value is within the specified range. |
|
Succeeds if the value is empty, or consists of only spaces (whitespaces, tabs, newlines, and so on). |
|
Checks if value can be interpreted as a Boolean. |
|
Validates a credit card number. |
|
Compares the value to a given value, using the specified operator. |
|
Validates the value using a custom regular expression. |
|
Validates the value as a date, using the given format or regular expression. |
|
Succeeds if value is a valid decimal number. |
|
Validates an e-mail address. |
|
Succeeds if the value is equal to the given value. |
|
Interprets the value as a file name and checks for the given extension. |
|
Checks that the value is within a list of allowed values. |
|
Validates an IP address. |
|
Checks that the length of the string value does not exceed a certain number of characters. |
|
Similar to maxLength, but ensures that the string value has at least the given number of characters. |
|
Checks that the value is a valid monetary amount. |
|
Validates a multiple select against a set of options. |
|
Succeeds if the value is numeric. |
|
Checks a phone number. |
|
Validates a postal code. |
|
Succeeds if the value is within a numeric range. |
|
Checks a social security/national identity number. |
|
Validates the value as a time (24 hours format). |
|
Validates the value as a UUID. |
|
Succeeds if the value is a valid URL. |
However, there are times where we require a custom validation, or where we need to change the way an existing validation works.
In this recipe, we will learn how to create our custom validation rule to check the validity of a given twitter user name.
We need some sample models to work with. Follow the Getting ready section of the recipe Adding multiple validation rules.
Edit the Profile
model by opening your app/models/profile.php
file and make the following changes:
class Profile extends AppModel { public $validate = array( 'email' => array('rule' => 'notEmpty'), 'name' => array('rule' => 'notEmpty'), 'twitter' => array( 'rule' => 'validateTwitter', 'allowEmpty' => true, 'message' => 'This twitter account is not valid' ) ); protected static $httpSocket; protected function validateTwitter($data) { if (!isset(self::$httpSocket)) { App::import('Core', 'HttpSocket'), self::$httpSocket = new HttpSocket(); } $value = current($data); self::$httpSocket->get('http://twitter.com/status/user_timeline/' . $value . '.json?count=1'), return (self::$httpSocket->response['status']['code'] != 404); } }
If we now browse to http://localhost/profiles/add
and click the Create
button after entering a Nonexistent Twitter account, we should see the error message for the twitter
field shown in the following screenshot:
If we instead specify a valid account, or leave it empty, there will be no error message displayed for the twitter
field.
When we set the rule
validate option to the name of a method that is available in the model (validateTwitter()
in our example), CakePHP calls that method when the field needs to be validated.
The method validateTwitter()
, like any custom validation method, receives an array in its first argument. This array is indexed by the field name, and the value is set to the value entered by the user. In the example shown in the previous screenshot, the data
argument comes in as:
array('twitter' => 'nonexistingtwitteraccount')
The validation method needs to return a Boolean value to indicate success: true
if the validation succeeded, false
if it failed. If we don't set the allowEmpty
option to true
, then the validation method will also be called when the field value is empty.
If the custom validation method returns a string, the field is marked to have failed validation, and the returned string is used as the error message.
The method validateTwitter()
first checks to see if an instance of the CakePHP HttpSocket
class is already set. We use a static instance to make sure the class is initialized only once, thus avoiding unnecessary processing if the method is called several times for the same process.
Once we have the HttpSocket
instance, we get the value to be validated (first value set in the array, as shown above), and we use it to fetch the contents of a twitter URL.
We could have used an http://twitter.com/$account URL, which returns the HTML containing the user latest tweets. However we chose to use a JSON
request, and limit the number of tweets to 1
, to reduce bandwidth usage from our server
This publicly available Twitter URL is used to get the timeline for a Twitter account, which returns an HTTP status of 404
when the account is not registered with Twitter. If the status is indeed 404
, we consider the Twitter account to be nonexistent, thus failing validation. Any other status code will result in a successful validation.
Some custom validation methods need more than just the value to be validated to be able to tell if validation succeeded. Fortunately, CakePHP not only sends us an array of options utilized to perform the validation in the second argument, but also provides an easy way to add parameters to our validation methods. Using our example, we now want to be able to provide a different URL to use when checking the Twitter account.
To utilize the array of options, edit the Profile
model by opening your app/models/profile.php
file and make the following changes:
class Profile extends AppModel { public $validate = array( 'email' => array('rule' => 'notEmpty'), 'name' => array('rule' => 'notEmpty'), 'twitter' => array( 'rule' => 'validateTwitter', 'allowEmpty' => true, 'url' => 'http://twitter.com/%TWITTER%' ) ); protected function validateTwitter($data, $options) { static $httpSocket; if (!isset($httpSocket)) { App::import('Core', 'HttpSocket'), $httpSocket = new HttpSocket(); } $options = array_merge(array( 'url' => 'http://twitter.com/status/user_timeline/%TWITTER%.json?count=1' ), $options); $value = current($data); $httpSocket->get(str_ireplace('%TWITTER%', $value, $options['url'])); return ($httpSocket->response['status']['code'] != 404); } }
If instead of utilizing the array of options, we want to utilize the ability to use extra parameters, we simply add arguments to our validation method, and pass those argument values as elements of the validate
definition. To do so, edit the Profile
model by opening your app/models/profile.php
file and make the following changes:
class Profile extends AppModel { public $validate = array( 'email' => array('rule' => 'notEmpty'), 'name' => array('rule' => 'notEmpty'), 'twitter' => array( 'rule' => array( 'validateTwitter', 'http://twitter.com/%TWITTER%' ), 'allowEmpty' => true ) ); protected static $httpSocket; protected function validateTwitter($data, $url = 'http://twitter.com/status/user_timeline/%TWITTER%.json?count=1') { if (!isset(self::$httpSocket)) { App::import('Core', 'HttpSocket'), self::$httpSocket = new HttpSocket(); } $value = current($data); self::$httpSocket->get(str_ireplace('%TWITTER%', $value, $url)); return (self::$httpSocket->response['status']['code'] != 404); } }
18.222.155.187