Passing parameters to CUniqueValidator 's criteria property

I am trying to create an "edit user" page and want to ensure that the email address posted back is unique. Unique in this case means that it will exist in the database but only for the user whose details I am editing. No other user must have the same email address. I have this in validation rule in my UserForm (extends CFormModel):


array('email_address', 'unique',

	'allowEmpty' => false,

	'className' => 'User',

	'caseSensitive' => false,

	'message' => 'Another user has already registered with this email address.',

	'criteria' => array(

		'condition' => 'id != :id',

		'params' => array(':id' => $this->id),

	)

)

This does not work. It always takes $this->id as NULL. What am I doing wrong? Or is there another way to do this?

This won’t work because validator is instantiated BEFORE id is set. This is because rules() are needed to perform massive assignments (to determine safe attributes, etc) not only to validate already assigned values. You have to create your own validator which extends standard CUniqueValidator and sets proper criteria before caling parent validation method. This way you will have access to object being validated and its attributes (validation method is called when values are already set).

Thanks for your reply. I created my own validator and it worked.

@Husain

post it

Here you go:


class UniqueEmailValidator extends CUniqueValidator

{

	protected function validateAttribute($object, $attribute)

	{

		$this->criteria = array(

			'condition' => 't.id != :id',

			'params' => array(':id' => $object->id)

		);


		return parent::validateAttribute($object, $attribute);

	}

}

It is very basic but works for me. Feedback will be appreciated.

[s]Do you really need it?

I guess you are worrying about the situation when you have left “email_address” unchanged when you are updating an existing record, aren’t you?

If so, then try and check it. CUniqueValidator is clever enough and will not complain about it.

[/s]

[UPDATE]

Sorry. Please forget it.

I have misunderstood the situation. Yours is a CFormModel, not a CActiveRecord.

So if my model extended from CActiveRecord I wouldn’t need to create my own validator! I am new to Yii and I am learning new things every day :)

Yes, that’s what I wanted to point, but …

To be honest, I myself didn’t have a clear understanding how CUniqueValidator behaves differently for CActiveRecord and for CFormModel until I peeked into the source code. :-[




if(!$object instanceof CActiveRecord || $object->isNewRecord || $object->tableName()!==$finder->tableName())

    $exists=$finder->exists($criteria);

else

{

    ...



http://www.yiiframework.com/doc/api/1.1/CUniqueValidator/#validateAttribute-detail

Hello husain please tell me how to call this validator from model rules.,for me the $object->id returning empty value.,

To validate on your custom validator, you just use its alias path in the model rules. So if you have your custom validator class in /protected/components/validate/MyValidator.php, you would do this in your rules


public function rules() {

    return array(

        array('my_field', 'application.components.validate.MyValidator'),

    );

}