I have a table like this: (id, name, version, text). (name, version) is unique key, how can i make a rule to validate this.
This can be done by Yii itself, you do not need an extension for it.
However an extension can help cleaning up the rules()
method as described here:
http://www.yiiframework.com/extension/unique-attributes-validator/
This is the code (copied from that site) which will work without using the extension:
public function rules() {
return array(
array('firstKey', 'unique', 'criteria'=>array(
'condition'=>'`secondKey`=:secondKey',
'params'=>array(
':secondKey'=>$this->secondKey
)
)),
);
}
In case the value of $this->secondKey
is not available inside rules()
-method you can add the validator in CActiveRecords beforeValidate()
-method like this:
public function beforeValidate()
{
if (parent::beforeValidate()) {
$validator = CValidator::createValidator('unique', $this, 'firstKey', array(
'criteria' => array(
'condition'=>'`secondKey`=:secondKey',
'params'=>array(
':secondKey'=>$this->secondKey
)
)
));
$this->getValidatorList()->insertAt(0, $validator);
return true;
}
return false;
}
You do not need complicated content of rules() method nor 3rd party extensions. Just create your own validation method. It's much easier to do it on your own.
public function rules()
{
return array(
array('firstField', 'myTestUniqueMethod'),
);
}
public function myTestUniqueMethod($attribute,$params)
{
//... and here your own pure SQL or ActiveRecord test ..
// usage:
// $this->firstField;
// $this->secondField;
// SELECT * FROM myTable WHERE firstField = $this->firstField AND secondField = $this->secondField ...
// If result not empty ... error
if (!$isUnique)
{
$this->addError('firstField', "Text of error");
$this->addError('secondField', "Text of error");
}
}
Yii1 :
http://www.yiiframework.com/extension/composite-unique-key-validatable/
Yii2 :
// a1 needs to be unique
['a1', 'unique']
// a1 needs to be unique, but column a2 will be used to check the uniqueness of the a1 value
['a1', 'unique', 'targetAttribute' => 'a2']
// a1 and a2 need to be unique together, and they both will receive error message
[['a1', 'a2'], 'unique', 'targetAttribute' => ['a1', 'a2']]
// a1 and a2 need to be unique together, only a1 will receive error message
['a1', 'unique', 'targetAttribute' => ['a1', 'a2']]
// a1 needs to be unique by checking the uniqueness of both a2 and a3 (using a1 value)
['a1', 'unique', 'targetAttribute' => ['a2', 'a1' => 'a3']]
http://www.yiiframework.com/doc-2.0/yii-validators-uniquevalidator.html
In Yii2:
public function rules() {
return [
[['name'], 'unique', 'targetAttribute' => ['name', 'version']],
];
}
They've added support for unique composite keys in the next release candidate of Yii1.14rc, but here's (yet another) solution. BTW, this code uses the same 'attributeName' in the rules that the Yii framework will use in the next official release.
protected/models/Mymodel.php
public function rules()
{
return array(
array('name', 'uniqueValidator','attributeName'=>array(
'name', 'phone_number','email')
),
...
- 'name' in the beginning of the rule is the attribute the validation error will be attached to and later output on your form.
- 'attributeName' (array) contains an array of keys that you would like to validate together as a combined key.
protected/components/validators/uniqueValidator.php
class uniqueValidator extends CValidator
{
public $attributeName;
public $quiet = false; //future bool for quiet validation error -->not complete
/**
* Validates the attribute of the object.
* If there is any error, the error message is added to the object.
* @param CModel $object the object being validated
* @param string $attribute the attribute being validated
*/
protected function validateAttribute($object,$attribute)
{
// build criteria from attribute(s) using Yii CDbCriteria
$criteria=new CDbCriteria();
foreach ( $this->attributeName as $name )
$criteria->addSearchCondition( $name, $object->$name, false );
// use exists with $criteria to check if the supplied keys combined are unique
if ( $object->exists( $criteria ) ) {
$this->addError($object,$attribute, $object->label() .' ' .
$attribute .' "'. $object->$attribute . '" has already been taken.');
}
}
}
You can use as many attributes as you like and this will work for all of your CModels. The check is done with "exists".
protected/config/main.php
'application.components.validators.*',
You may have to add the above line to your config in the 'import' array so that uniqueValidator.php will be found by the Yii application.
Positive feedback and changes are very welcome!
Based on the function above, here is one function you can add onto your ActiveRecord Model
You would use it like so,
array( array('productname,productversion'), 'ValidateUniqueColumns', 'Product already contains that version'),
/*
* Validates the uniqueness of the attributes, multiple attributes
*/
public function ValidateUniqueColumns($attributes, $params)
{
$columns = explode(",", $attributes);
//Create the SQL Statement
$select_criteria = "";
$column_count = count($columns);
$lastcolumn = "";
for($index=0; $index<$column_count; $index++)
{
$lastcolumn = $columns[$index];
$value = Yii::app()->db->quoteValue( $this->getAttribute($columns[$index]) );
$column_equals = "`".$columns[$index]."` = ".$value."";
$select_criteria = $select_criteria.$column_equals;
$select_criteria = $select_criteria." ";
if($index + 1 < $column_count)
{
$select_criteria = $select_criteria." AND ";
}
}
$select_criteria = $select_criteria." AND `".$this->getTableSchema()->primaryKey."` <> ".Yii::app()->db->quoteValue($this->getAttribute( $this->getTableSchema()->primaryKey ))."";
$SQL = " SELECT COUNT(`".$this->getTableSchema()->primaryKey."`) AS COUNT_ FROM `".$this->tableName()."` WHERE ".$select_criteria;
$list = Yii::app()->db->createCommand($SQL)->queryAll();
$total = intval( $list[0]["COUNT_"] );
if($total > 0)
{
$this->addError($lastcolumn, $params[0]);
return false;
}
return true;
}
It's very easy. In your array, include a param created in your extensions class.
Next code is inside Model.
array('name', 'ext.ValidateNames', 'with'=>'lastname')
Next code is from class ValidateNames
into the extensions folder.
class ValidateNames extends CValidator
{
public $with=""; /*my parameter*/
public function validateAttribute($object, $attribute)
{
$temp = $this->with;
$lastname = $object->$temp;
$name = $object->$attribute;
$this->addError($object,$attribute, $usuario." hola ".$lastname);
}
}
May be you can add this rules
onto your code
return array(
array('name', 'unique', 'className'=>'MyModel', 'attributeName'=>'myName'),
array('version', 'unique', 'className'=>'MyModel', 'attributeName'=>'myVersion')
);
来源:https://stackoverflow.com/questions/9670992/yii-how-to-make-a-unique-rule-for-two-attributes