yii: как сделать уникальное правило для двух атрибутов

У меня есть такой стол: (id, имя, версия, текст). (имя, версия) является уникальным ключом, как я могу сделать правило для проверки этого.

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.14rc, но вот (еще одно) решение. Кстати, этот код использует то же самое "attributeName" в правилах, которые платформа Yii будет использовать в следующем официальном выпуске.

защищенный/модели/Mymodel.в PHP

    public function rules()
    {
        return array(
            array('name', 'uniqueValidator','attributeName'=>array(
              'name', 'phone_number','email') 
        ),
...
  • 'name' в начале правила является атрибутом, к которому будет прикреплена ошибка проверки, а затем выводится в вашей форме.
  • 'attributeName' (array) содержит массив ключей, которые вы хотели бы проверить вместе как комбинированный ключ.

protected / компоненты / валидаторы / 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. Проверка выполняется с помощью "exists".

protected / config / main.в PHP

'application.components.validators.*',

возможно, Вам придется добавить эту строку, чтобы ваша конфигурация в массиве "импорт" так, что uniqueValidator.php будет найден приложением Yii.

положительные отзывы и изменения очень приветствуются!


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


В Коде С 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;
}

Это очень легко. В массиве включите параметр, созданный в классе extensions.

следующий код находится внутри модели.

array('name', 'ext.ValidateNames', 'with'=>'lastname')

следующий код из класса ValidateNames в папку extensions.

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')
);