yii: как создать уникальное правило для двух атрибутов
У меня есть таблица, как это: (идентификатор, имя, версия, текст). (имя, версия) является уникальным ключом, как я могу сделать правило для проверки этого.
8 ответов
Это может сделать сам Yii, вам не нужно расширение для него. Однако расширение может помочь очистить rules()
метод, как описано здесь:
http://www.yiiframework.com/extension/unique-attributes-validator/
Это код (скопированный с этого сайта), который будет работать без использования расширения:
public function rules() {
return array(
array('firstKey', 'unique', 'criteria'=>array(
'condition'=>'`secondKey`=:secondKey',
'params'=>array(
':secondKey'=>$this->secondKey
)
)),
);
}
В случае, если значение $this->secondKey
недоступен внутри rules()
-метод вы можете добавить валидатор в CActiveRecords beforeValidate()
-метод, как это:
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;
}
Вам не нужно сложное содержание метода rules() или сторонних расширений. Просто создайте свой собственный метод проверки. Гораздо проще сделать это самостоятельно.
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
Они добавили поддержку уникальных составных ключей в следующем выпуске кандидата Yii1.14rc, но есть (еще одно) решение. Кстати, этот код использует то же самое "attributeName" в правилах, которые будет использоваться в Yii Framework в следующем официальном выпуске.
защищенная / модель /Mymodel.php
public function rules()
{
return array(
array('name', 'uniqueValidator','attributeName'=>array(
'name', 'phone_number','email')
),
...
- "name" в начале правила - это атрибут, к которому будет прикреплена ошибка проверки, а затем выведена в форму.
- "attributeName" (массив) содержит массив ключей, которые вы хотели бы проверить вместе как комбинированный ключ.
защищенные / компоненты / валидаторов /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.');
}
}
}
Вы можете использовать столько атрибутов, сколько захотите, и это будет работать для всех ваших CModels. Проверка выполняется с помощью "существует".
защищенный / конфигурации /main.php
'application.components.validators.*',
Возможно, вам придется добавить вышеуказанную строку в вашу конфигурацию в массиве 'import', чтобы приложение UniqueValidator.php было найдено приложением Yii.
Положительные отзывы и изменения приветствуются!
В Yii2:
public function rules() {
return [
[['name'], 'unique', 'targetAttribute' => ['name', 'version']],
];
}
Основываясь на функции выше, вот одна функция, которую вы можете добавить в свою модель ActiveRecord
Вы бы использовали это так,
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;
}
Это очень просто. В ваш массив включите параметр, созданный в вашем классе расширений.
Следующий код находится внутри модели.
array('name', 'ext.ValidateNames', 'with'=>'lastname')
Следующий код из класса ValidateNames
в папку расширений.
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);
}
}
Может быть, вы можете добавить это rules
на ваш код
return array(
array('name', 'unique', 'className'=>'MyModel', 'attributeName'=>'myName'),
array('version', 'unique', 'className'=>'MyModel', 'attributeName'=>'myVersion')
);