Writing your own validators

Yii provides a good set of built-in form validators that cover the most typical of developer's needs and are highly configurable. However, in some cases, the developer may face a need to create a custom validator.

A good example would be the website ownership validation. For a few of their services, Google requires you to upload a file with the name and content specified to your website, and then checks if it is there. We will do the same.

There are two ways to achieve it; you can use a class method as a validator, or the second way is to create a separate class.

Getting ready

Create a new application using yiic webapp as described in the official guide.

How to do it...

  1. We will start with the class method approach. First, we need to implement a form model. So, create protected/models/SiteConfirmation.php as follows:
    <?php
    class SiteConfirmation extends CFormModel {
       public $url;
    
       public function rules()
       {
          return array(
             array('url', 'confirm'),
          );
       }
    
       public function confirm($attribute,$params)
       {
          $ch = curl_init();
          curl_setopt($ch, CURLOPT_URL, $this->url);
          curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
          $output = curl_exec($ch);
          curl_close($ch);
          if(trim($output)!='code here')
             $this->addError('url','Please upload file first.'),
       }
    }
  2. Now, we will use our model from our test controller. Create protected/controllers/TestController.php as follows:
    <?php
    class TestController extends CController
    {
       function actionIndex()
       {
          $confirmation = new SiteConfirmation();
          $confirmation->url = 'http://yiicookbook.org/verify.html';
          if($confirmation->validate())
             echo 'OK';
          else
             echo 'Please upload a file.';
       }
    }
  3. Now, try to run the test controller. You should get OK because there is a file with the code here text available from http://yiicookbook.org/verify.html. If you replace the confirmation URL with another one, then you get Please upload a File as there is no such file uploaded.

How it works...

In the SiteConfirmation model, we define a $url field and add a rules method that defines a single validation rule for this field. As there is no built-in validator named confirm, Yii assumes that we want to describe the validation rule in a method named confirm. In this method we use PHP's standard CURL to get the verify.html file's contents from a remote host and compare its content with the code here string. If the file content is different, then we add an error using the addError method.

Optionally, we can use two validation method arguments: $attribute and $params. For example, we can specify the validation rule in the following way:

array('url', 'confirm', 'param1' => 'value1', 'param2' => 'value3'),

We then get the $attribute value set to url and the $params value set to the following:

array
(
  'param1' => 'value1'
  'param2' => 'value3'
)

There's more...

As we probably want to reuse this kind of validator, we will move its functionality from a model method to a separate class. So, create a file named protected/components/RemoteFileValidator.php as follows:

<?php
class RemoteFileValidator extends CValidator
{
   public $content = '';

   protected function validateAttribute($object,$attribute)
   {
      $value=$object->$attribute;

      $ch = curl_init();
      curl_setopt($ch, CURLOPT_URL, $value);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
      $output = curl_exec($ch);
      curl_close($ch);
      
      if(trim($output)!=$this->content)
         $this->addError($object,$attribute,'Please upload file first.'),
   }
}

The custom validator class should extend CValidator and implement its abstract validateAttribute method. Arguments passed on to it are $object, which is an instance of the validated model, and $attribute, which contains the validated attribute name. Parameters that are passed are assigned to corresponding public properties of the validator class.

That is it. Now, we will use it. In the SiteConfirmation model, we should change the validation rule to the following:

array('url', 'RemoteFileValidator', 'content' => 'code here'),

Here we have used an external validator name. If there is no method with the same name in the model and no built-in validator with same name, Yii will try to find an external validator class with the name or path alias specified.

The rest of the code stays untouched and now you can reuse the validator in other models.

Further reading

For further information, refer to the following URLs:

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.179.119