Yes, that's a known problem. I can't think of a good way to solve it because CUniqueValidator doesn't know the original PK value. FYI, you can set 'on' option so that this rule only applies when inserting a record.
the idea is to search only in records which not have the id of the object we want to check.
Here a short example to explain it better.
Assume a Table with 3 Colums
Id => as PK
Title => string and should be unique.
Content => string
Now lets say we want to change the content-column of record to 'other content' with starting values like this:
Id=5
Title='title1'
content='some content'
The validator runs on update and tries to find records with the condition like "Title=title1".
This will be true because the validator will find our record with id 5.
The update will fail here.
My idea is to extend the condition to somethink like this "Title ='title1' AND Id!=5".
So the validator will not found the same record which we want to check.
I improved my last code to check also if the object to check is new, because the validator will then fail on inserts. because of the condition like "Title='title1' and Id!=Null"…
What about multiple uniqueValidators? Only dirty attributes should be validated on update. I guess one possible but less than optimal solution is to add a dirty flag to every attribute. Or probably a better way: pass the pk (hidden) to the view and back again for comparison with the original record. (Assuming the view displays multiple records).
/Tommy
Edit: Thinking error. I guess we already pass the pk with an update request.
I see. I was thinking about PK change and couldn't find out a good solution.
Dirty flag would mean performance degradation. I think in case PK uniqueness is needed, users can always write a custom validation method to accomplish the task (with the help of keeping previous PK value).
Regarding the change about multiple columns, although your approach works, it has side effects (conflict with the newly implemented scenario-based massive assignment) and also requires new syntax.
I think uniqueness based on multiple columns is not widely needed. So maybe it should leave to developers to implement it in either a method-based validator or an individual extension (make the columns to be validated as a property).
Validating multiple columns for uniqueness might be useful when a user can create objects with a name and the name has to be unique per user. Therefore the uniqueness of the user-objectName has to be checked.
I took me23’s code and packaged it a Validation Extention. one question though…
While CValidator::addError() takes a single attribute, is there a way to add s single error message that references multiple model attributes?
I use compound keys so validating uniqueness across multiple fields is very important. I think if there was even a way to late bind the values passed to ‘params’ in the ‘criteria’ array that would be sufficient. Granted writing a custom validation method will work, but it is a little painful considering this built in validator almost does the job. I’m glad I found this thread so that I now know what I need to do to get my code to work.
What if the ‘attributeName’ option could accept a string column name or an array of string column names? The validation could still be triggered off of one column, but ‘attributeName’ would allow more than one column to be checked for uniqueness.