make UniqueValidator compatible with ActiveRecordInterface again

fixes #13485
This commit is contained in:
Carsten Brandt
2017-02-01 13:27:03 +01:00
parent 0df8020dd0
commit 1eec5c17bc

View File

@ -120,7 +120,7 @@ class UniqueValidator extends Validator
$targetClass = $this->targetClass === null ? get_class($model) : $this->targetClass; $targetClass = $this->targetClass === null ? get_class($model) : $this->targetClass;
$targetAttribute = $this->targetAttribute === null ? $attribute : $this->targetAttribute; $targetAttribute = $this->targetAttribute === null ? $attribute : $this->targetAttribute;
$rawConditions = $this->prepareConditions($targetAttribute, $model, $attribute); $rawConditions = $this->prepareConditions($targetAttribute, $model, $attribute);
$conditions[] = $this->targetAttributeJunction == 'or' ? 'or' : 'and'; $conditions[] = $this->targetAttributeJunction === 'or' ? 'or' : 'and';
foreach ($rawConditions as $key => $value) { foreach ($rawConditions as $key => $value) {
if (is_array($value)) { if (is_array($value)) {
@ -159,26 +159,24 @@ class UniqueValidator extends Validator
// also there's no need to run check based on primary keys, when $targetClass is not the same as $model's class // also there's no need to run check based on primary keys, when $targetClass is not the same as $model's class
$exists = $query->exists(); $exists = $query->exists();
} else { } else {
// if current $model is in the dat1abase already we can't use exists() // if current $model is in the database already we can't use exists()
if ($query instanceof \yii\db\ActiveQuery) { if ($query instanceof \yii\db\ActiveQuery) {
$models = $query->select($targetClass::primaryKey())->limit(2)->asArray()->all(); // only select primary key to optimize query
} else { $query->select($targetClass::primaryKey());
$models = $query->limit(2)->asArray()->all();
} }
$models = $query->limit(2)->asArray()->all();
$n = count($models); $n = count($models);
if ($n === 1) { if ($n === 1) {
$keys = array_keys($conditions); // if there is one record, check if it is the currently validated model
$dbModel = reset($models);
$pks = $targetClass::primaryKey(); $pks = $targetClass::primaryKey();
sort($keys); $pk = [];
sort($pks); foreach($pks as $pkAttribute) {
if ($keys === $pks) { $pk[$pkAttribute] = $dbModel[$pkAttribute];
// primary key is modified and not unique
$exists = $model->getOldPrimaryKey() != $model->getPrimaryKey();
} else {
// non-primary key, need to exclude the current record based on PK
$exists = $models[0] != $model->getOldPrimaryKey(true);
} }
$exists = ($pk != $model->getOldPrimaryKey(true));
} else { } else {
// if there is more than one record, the value is not unique
$exists = $n > 1; $exists = $n > 1;
} }
} }