Custom unique validator rule

Hi,

Here is my problem, I have a brand table and a realisation table. Each brand has many realisations. I’ve succeed to make the unique validator for brands like this:


array('name', 'unique', 'className' => 'Brand', 'attributeName' => 'name', 'message' => 'Name already exist'),

But I don’t know for realisations. I’d like that the name of a realisation is unique in a brand. Like you can have

Nike (brand) with shoes and clothes (realisations)

Reebok (brand) with shoes and shorts (realisations)

So I want the unique validator check in a specific brand not in all realisations!

Do you have any idea?

I’ve already tried that but it doesn’t work:


array('name', 'unique', 'criteria'=>array(

		'condition'=>'"secondKey"=:secondKey',

		'params'=>array(

				':secondKey'=>$this->brand_id

				)

)),

Thanks!

Try this

http://www.yiiframework.com/extension/composite-unique-key-validatable/

Dear friend,

Can you please try this in your Realization Model.




array('name', 'checkMyUniqunessInBrand')


public function checkMyUniqunessInBrand($attribute,$params)

 {

  if(Realisation:model()->count('name=:name AND brand_id=:brand_id',

      array(':name'=>$this->name,':brand_id'=>$this->brand_id)) > 0) 

       return false;

  else return true;

 }



OR




array('name', 'unique', 'criteria'=>array(

                'condition'=>'name=:name AND brand_id=:brand_id',

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

)),



This won’t work because custom function validators are not supposed to return any value. Instead they should just set errors:




array('name', 'checkMyUniqunessInBrand')


public function checkMyUniqunessInBrand($attribute,$params) {

    if(Realisation:model()->count('name=:name AND brand_id=:brand_id',

        array(':name'=>$this->name,':brand_id'=>$this->brand_id)) > 0) {

        $this->addError( $attribute, "$attribute must be unique in brand scope!" );

    }

}



Thanks it works!

The only problem now is for update a realization. You can’t save, it says that it must be unique. Is there a way

to check if the name changed? Such as we save the name before update and check if it has changed? Because I need this check for the

update in case the user change the realization name by a name already used.

Thank you guys for all the help!

I really thank redguy for his inputs.

Dear iDams

Can you please try this.




array('name', 'checkMyUniqunessInBrand')


public function checkMyUniqunessInBrand($attribute,$params) {

    if($this->getIsNewRecord()  &&  Realisation:model()->count('name=:name AND brand_id=:brand_id',

        array(':name'=>$this->name,':brand_id'=>$this->brand_id)) > 0) {

        $this->addError( $attribute, "$attribute must be unique in brand scope!" );

    }

}



seenivasan,

It works but now during the update I can put a name that already exists so it’s not good!

read this topic: http://www.yiiframework.com/forum/index.php/topic/34179-unique-multiple-columns-validate-with-ajaxvalidation-wont-work/page__p__164516__fromsearch__1#entry164516

I posted there snippet how to call CUniqueValidator with additional filter condition from custom function. This should do the trick.

Thank you but I don’t really understand what validate is doing. But like you said in this other topic secondKey give me the new attribute. So,

I’m almost done, I just want to know the current one before assignment. But I can’t find it. I’ve looked at $attribute and $params variables, but

it’s not. Do you know how to get this value?

With it, I could compare with the new one et know if it has changed or not.

Thanks redguy!

to track changes in model you should use "afterFind":




class MyModel extends CActiveRecord {


private $_previousAttributeValue = null;


public function afterFind() {

  parent::afterFind();

  $this->_previousAttributeValue = $this->attribute;

}


public function isAttributeChanged() {

  return $this->_previousAttributeValue !== null && $this->_previousAttributeValue !== $this->attribute;

}



Dear redGuy

could you please tell me the following code serves the same purpose?




public function actionSomething($id)

	{

		$model=$this->loadModel($id);

                $oldOne=$model->someAttribute;


		if(isset($_POST['Model']))

		{

			$model->attributes=$_POST['Model'];

                        $newOne=$model->someAttribute;


			if($oldOne==$newOne)

			   {

                            //Do some logic...

                           }

		}


		

	}



Regards.

Yes it does pretty same. The only difference is in conceptions of fat-controller vs fat-model (meaning: where you put your business logic) :)

Thank you redguy, it works great! ;)