Custom validation rule does not trigger if 'required' rule is set

I got an interesting behavior in my CFormModel. I have a form with two input text fields. Let’s say firstname and lastname. The lastname field is required. The firstname is not required but I want to do some custom validation if it is not empty. My rules array looks as follows:


public function rules()

	{

		return array(

			array('lastname', 'required', 'message' =>'Some error message...'),

			array('firstname', 'customValidation'),

			array('firstname', 'safe'),

		);

	}

My customValidation looks like:


public function customValidation($attribute,$params)

	{

    	$this->addError($attribute,'error message');

	}

Now, if I submit the form the customValidation will never trigger.

It only works if I remove the required validator!

This seems very strange to me and I am wondering what I am doing wrong here…

I removed the ‘safe’ declaration but the custom validation will still not work if the ‘required’ validator is active.

Please let me know what you think.

[s]


public function customValidation($attribute,$params)

{

    $this->addError($attribute,'error message');

    return false; // this line is missing

}

[/s]

That doesn’t change anything. Sorry.

True, but the validation is still not getting triggered.

I replaced the ‘required’ validator with a different one to see the behavior. Even if I check the custom validation rule does not work.


array('lastname', 'length', 'min' => 2),

Again, if I use the custom validation only, then it works.

As soon as there is another validation rule it appears that my custom one gets overwritten.

Any thoughts?

You do not need to specify first name as ‘safe’ if it is referenced by another rule.

With that removed, this looks correct to me:


public function rules()

{

   return array(

      array('lastname', 'required', 'message' =>'Some error message...'),

      array('firstname', 'customValidation'),

   );

}


public function customValidation($attribute,$params)

{

   if (!empty($this->$attribute))

   {

      // Checks for only when there is a value


      // @todo Add additional error checking here

      $this->addError($attribute, 'You supplied a value but there was an error.');


   }

}

How are you getting the errors for your form model? You should be getting two distinct errors when you have filled in the "first name", above.

Thanks, this is what I usually do but I wasn’t sure since this case really bugs me. So I am trying all scenarios I can think off :)

I created a fresh, clean yii application to check if there is something wrong in the application I have been using so far.

So I simply modified the ContactForm model rules to the following:


public function rules()

	{

		return array(

			// name, email, subject and body are required

			array('name, subject, body', 'required'),

			// email has to be a valid email address

			array('email', 'customValidation'),

			// verifyCode needs to be entered correctly

			array('verifyCode', 'captcha', 'allowEmpty'=>!CCaptcha::checkRequirements()),

		);

	}

All I modified here is the email validation to test the custom validation rule. I then added the code for the the customValidation:


public function customValidation($attribute,$params)

	{

		$this->addError('email','error');

	}

And again, I do not get any error messages for the email field.

Can someone please confirm this behavior?

What am I doing wrong trying to use a custom validation rule?

Yes, I’ve just tried it on the contact form, and I confirm the behavior you describe.

Anyway, the code below works.

If [font=“Courier New”]enableClientValidation[/font] and [font=“Courier New”]validateOnSubmit[/font] are both set to true in your form, you won’t see the error unless the other rules are cleared, and only upon submit. (Leave the ‘name’ rule commented, try it, and then uncomment it to see what I mean.

[list=1]

[*]Model


public function rules()

{

    return array(

        // After you work with email alone, uncomment this rule

        // array('name', 'required'),

        array('email', 'customValidation'),

    );

}


public function customValidation($attribute,$params)

{

    $this->addError($attribute,'bla');

}

[*]View


<?php $form=$this->beginWidget('CActiveForm', array(

    'id'=>'contact-form',

    /* When true, breaks everything */

    'enableAjaxValidation'=>false,

    /* When false, the rules are run at the same time */

    /* When true at the same time than validateOnSubmit,

        custom rules run after all the standard ones are cleared */

    'enableClientValidation'=>true,

    'clientOptions'=>array(

        /* When false, the rules are run at the same time */

        /* When true at the same time than enableClientValidation,

            custom rules run after all the standard ones are cleared */

        'validateOnSubmit'=>true,

    ),

)); ?>

[/list]

Another thing, I’ve checked some models in working webapps I’ve developped, and for a ‘normal’ model, it can work as well for client validation if [font=“Courier New”]enableAjaxValidation[/font] is set to true. (you cannot perform Ajax validation on a contact form I guess)

I wasn’t aware you were trying to use your custom validator for client validation (which inherently does not do server validation until client validation passes).

Either turn off enableClientValidation in your CActiveForm widget instantiation, or follow this documentation to create a client validation handler for your model with the same logic as your customValidation() validator:

http://www.yiiframework.com/wiki/168/create-your-own-validation-rule/#hh3

Thank you both very much for your help!! :)

Greatly appreciate it!!