UniqueValidator checks if the value being validated is unique in the table column specified by
the ActiveRecord class [[targetClass]] and the attribute [[targetAttribute]].
The following are examples of validation rules using this validator:
php
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']]
public function uniqueCheck() { if ($this->owner instanceof ActiveRecordInterface) { /** @var Model $model */ $model = clone $this->owner; $uniqueValidator = new UniqueValidator(); $uniqueValidator->validateAttribute($model, $this->slugAttributeName); return !$model->hasErrors($this->slugAttributeName); } throw new Exception('Can\'t check if the slug is unique.'); }
/** * Initializes the object. * This method is invoked at the end of the constructor after the object is initialized with the * given configuration. */ public function init() { parent::init(); if ($this->uniqueValidatorClassName === null) { $this->uniqueValidatorClassName = UniqueValidator::className(); } }
/** * Checks if given slug value is unique. * @param string $slug slug value * @return boolean whether slug is unique. */ protected function validateSlug($slug) { /* @var $validator UniqueValidator */ /* @var $model BaseActiveRecord */ $validator = Yii::createObject(array_merge(['class' => UniqueValidator::className()], $this->uniqueValidator)); $model = clone $this->owner; $model->clearErrors(); $model->{$this->slugAttribute} = $slug; $validator->validateAttribute($model, $this->slugAttribute); return !$model->hasErrors(); }
/** * @inheritdoc */ public function addError($model, $attribute, $message, $params = []) { if (is_array($this->targetAttribute) && count($this->targetAttribute) > 1) { foreach ($this->targetAttribute as $key => $value) { $keyAttribute = is_int($key) ? $value : $key; parent::addError($model, $keyAttribute, $message, $params); } } else { parent::addError($model, $attribute, $message, $params); } }
public function testValidateCompositeKeys() { $val = new UniqueValidator(['targetClass' => OrderItem::className(), 'targetAttribute' => ['order_id', 'item_id']]); // validate old record $m = OrderItem::findOne(['order_id' => 1, 'item_id' => 2]); $val->validateAttribute($m, 'order_id'); $this->assertFalse($m->hasErrors('order_id')); $m->item_id = 1; $val->validateAttribute($m, 'order_id'); $this->assertTrue($m->hasErrors('order_id')); // validate new record $m = new OrderItem(['order_id' => 1, 'item_id' => 2]); $val->validateAttribute($m, 'order_id'); $this->assertTrue($m->hasErrors('order_id')); $m = new OrderItem(['order_id' => 10, 'item_id' => 2]); $val->validateAttribute($m, 'order_id'); $this->assertFalse($m->hasErrors('order_id')); $val = new UniqueValidator(['targetClass' => OrderItem::className(), 'targetAttribute' => ['id' => 'order_id']]); // validate old record $m = Order::findOne(1); $val->validateAttribute($m, 'id'); $this->assertTrue($m->hasErrors('id')); $m = Order::findOne(1); $m->id = 2; $val->validateAttribute($m, 'id'); $this->assertTrue($m->hasErrors('id')); $m = Order::findOne(1); $m->id = 10; $val->validateAttribute($m, 'id'); $this->assertFalse($m->hasErrors('id')); $m = new Order(['id' => 1]); $val->validateAttribute($m, 'id'); $this->assertTrue($m->hasErrors('id')); $m = new Order(['id' => 10]); $val->validateAttribute($m, 'id'); $this->assertFalse($m->hasErrors('id')); }
/** * Validate SEO URL and ensure its uniqueness. */ private function _validateUrlField() { if (empty($this->urlField)) { // If do not need to work with SEO:url, then skip further work return; } $model = $this->owner; // Add UNIQUE validator for SEO:url field $validator = Validator::createValidator(UniqueValidator::className(), $model, $this->urlField, ['filter' => $this->uniqueUrlFilter]); // If SEO: url is not filled by the user, then generate its value $urlFieldVal = trim((string) $model->{$this->urlField}); if ($urlFieldVal === '') { $urlFieldVal = $this->_getProduceValue($this->urlProduceField); } // Transliterated string and remove from it the extra characters $seoUrl = $this->_getSeoName($urlFieldVal, $this->maxUrlLength, $this->toLowerSeoUrl); // If there is a match with banned names, then add to the url underbar // to the end while (in_array($seoUrl, $this->stopNames)) { $seoUrl .= '_'; } $model->{$this->urlField} = $seoUrl; // Start the first unique validation $validator->validateAttribute($model, $this->urlField); // Run the validation of up to 50 times, until there is a unique SEO:url // name $i = 0; while ($model->hasErrors($this->urlField)) { // Remove the error message received in the last validation $model->clearErrors($this->urlField); // If failed 50 times, then something went wrong... if (++$i > 50) { // We establish SEO: url to a random hash $model->{$this->urlField} = md5(uniqid()); // Finish "infinite" loop break; } // Add "_" at the end of SEO:url $newSeoUrl = $model->{$this->urlField} . '_'; $model->{$this->urlField} = $newSeoUrl; // Run the validator again, because in the previous line, we changed // the value of adding a suffix $validator->validateAttribute($model, $this->urlField); } }