CUniqueValidator with Criteria


Table attribute_option:

=======================


id

attribute_id

label

value

I want to ensure that ‘value’ is unique based on attribute_id column.

Model AttributeOption:


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

	'condition'=>'attribute_id=:attribute_id',

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

)),

Controller:




$model=new AttributeOption;


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

{

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

			

	$model->attribute_id=2;

			

	if($model->save())

		$this->redirect(array('options', 'id'=>$model->attribute_id));

}

This doesn’t work for me, I can insert duplicate ‘value’ and it goes through.

to solve this problem just setup in your myphpadmin sql table index key that value in table attribute_option is unique,

EDIT: and in your model when you fill your table setup that property in rules to unique

But ‘value’ is only unique based on the attribute_id

So this is all valid:


attribute_id   value

1               1

1               2

2               1

2               2

But this is not valid:


attribute_id   value

1               1

1               1

2               2

2               2

then you have to setup where is unique


array('value', 'unique', 'on'=>'attribute_id'),

EDIT: Sory thats scenario ,

EDIT try this this should be work couse you can setup condition on unique value


array('value', 'unique', 'condition'=>'attribute_id = :attribute_id'),

I already tried that (check my original post)

Anybody got any suggestions?

I have never used that G,

For comparisons I use client checking and onBeforeSave to check for the attributes:




public onBeforeSave(){

   

   if (parent::beforeDelete()){

     if($model->attribute_id == $model->value) 

     {

      // write error to Model

      $model->addError('attribute_id', 'value and attribute_id cannot be the same');

      return false;

     }

     return true;

   }

   return false;

}

  

In phpmyadmin, first remove unique from attribute_id, then tick both attribute_id and value columns, and click make unique icon.

in Yii, try this:


array('value, attribute_id', 'unique')

Cheers Antonio, I might have to do it that way but I don’t know why it doesn’t work in the rule - the ‘criteria’ option is provided so that we can define a criteria for the rule to work with. I must be doing something incorrectly somewhere.

I have just done some testing - in my rule that I have posted at the top, if I hardcode in a value, eg:


'params'=>array(':attribute_id'=>1),

Then the rule works. So it does not seem to be understanding/capturing $this->attribute_id

mmm… that is interesting G, that may have something to do with object lifecycle, that is, the attribute is not yet set.

I look around for my side. I would like to do some research before I post, let me know if you find something as I am interested in this solution.

edit:

After doing some research I am thinking that what you don’t want is that attribute_id is not equal a value right? Then, why don’t you use CCompareValidator instead?




array('attribute_id', 'compare', 'compareAttribute'=>'value', 'operator'=>'!=')



Hi Gstar

$this->attributeId cannot find in the rules of validator, because they are parsed when the object is created.

I always used the validator without condition, and all was working fine.

Can you explain why exactly you need a condition? What is the behavior you are looking for?

Antonio - no that’s not correct.

This is exacttly what I’m trying to acheive:

let me check…

attribute_id operator value

1 = 1 <--------- so if attribute_id = value is correct?

1 != 2 <--------- so if attribute_id != value is correct?

2 != 1 <--------- attribute_id != value is correct?

2 = 2 <---------- attribute_id = value

Please excuse me G, I am a bit confused.

Lol this isn’t as complicated as it seems. attribute_id is just a parent of value. We are not doing a comparison between attribute_id and value. This might be more helpful:

This is all valid:


attribute_id   value 

1               Dog 

1               Cat 

2               Dog 

2               Cat

This is not valid:


attribute_id   value 

1               Dog 

1               Dog 

2               Cat 

2               Cat

Basically the user cannot enter Dog or Cat twice for the same attribute_id.

Duh! :D ok, now I understand…

But G, can’t you do that on the client? I see this is more like the way you print the form to the user and how it is posted.

Let me explain, I know that I have certain Dogs and Cats (lol) that I can select for a Model right? Then when I display the ‘insert new Model’ I just display those not in relation with Model to be updated. I do not know if I explain my self clearly.

I do this constantly and it works very well, on create I show a list box of the VALUES it can select (checkboxes, listboxes, whatever) on create is easy.

Now on update, I display the VALUES that it has and the possible VALUES he can select. This is now pure javascript, If a user removes an attribute that it has, then list box with possible VALUES to select are updated. On submit, relations are re-created before saving.

If I have Cats, then I display Cat as selected VALUE and Dogs as possible addition to the Model.

Maybe it is too complicated -I come with strong JS background, or my english is very poor, but this is how I do it in these cases.

Antonio - there is no predefined list of values. This functionality is just to ensure that the user does not accidentally enter the same value twice, for the same attribute_id.

P.S. Nothing wrong with your English - it’s very good!

Then, and by taking into account zac’s comment on this matter I think that a check onBeforeSave using ADO should be the correct way my friend.

Apologies for not being a better help and for making some Hommer Simpson understanding mistakes dough!

Cheers G

I managed to resolve this by creating my own validation function (not sure why I didn’t think of that before!).

Anyway do you think this is a problem with the CUniqueValidator, or is it never expected to work this way? How I see it is that there is a criteria option provided for this very purpose - all I have done in my custom function is to specify the criteria.

You can simulate that same functionality in MySQL, by setting (attribute_id,value) as your primary key, auto_increment value.

This only works in MySQL’s MyISAM engine, it does not work as expected in InnoDB.


CREATE TABLE `test` (

  `parent_id` int(10) unsigned NOT NULL,

  `child_id` int(10) unsigned NOT NULL AUTO_INCREMENT,

  PRIMARY KEY (`parent_id`,`child_id`)

) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

Hello G, please tell me how u are manage this criteria in your custom validation class.