Fixes #13704: Fixed yii\validators\UniqueValidator to prefix attribute name with model's database table name

This commit is contained in:
vladis84
2017-03-14 20:37:52 +05:00
committed by Alexander Makarov
parent b00cd65ef3
commit 3c1f3e20cf
3 changed files with 52 additions and 3 deletions

View File

@ -50,6 +50,7 @@ Yii Framework 2 Change Log
- Bug #4408: Add support for unicode word characters and `+` character in attribute names (sammousa, kmindi)
- Bug #10372: Fixed console controller including complex typed arguments in help (sammousa)
- Bug #13738: Fixed `getQueryParams()` method in `yii.js` to correctly parse URL with question mark and no query parameters (vladdnepr)
- Bug #13704: Fixed `yii\validators\UniqueValidator` to prefix attribute name with model's database table name (vladis84)
2.0.11.2 February 08, 2017
--------------------------

View File

@ -10,9 +10,9 @@ namespace yii\validators;
use Yii;
use yii\base\Model;
use yii\db\ActiveQuery;
use yii\db\ActiveRecord;
use yii\db\ActiveQueryInterface;
use yii\db\ActiveRecordInterface;
use yii\db\Query;
use yii\helpers\Inflector;
/**
@ -119,7 +119,7 @@ class UniqueValidator extends Validator
public function validateAttribute($model, $attribute)
{
/* @var $targetClass ActiveRecordInterface */
$targetClass = $this->targetClass === null ? get_class($model) : $this->targetClass;
$targetClass = $this->getTargetClass($model);
$targetAttribute = $this->targetAttribute === null ? $attribute : $this->targetAttribute;
$rawConditions = $this->prepareConditions($targetAttribute, $model, $attribute);
$conditions[] = $this->targetAttributeJunction === 'or' ? 'or' : 'and';
@ -141,6 +141,15 @@ class UniqueValidator extends Validator
}
}
/**
* @param Model $model the data model to be validated
* @return string Target class name
*/
private function getTargetClass($model)
{
return $this->targetClass === null ? get_class($model) : $this->targetClass;
}
/**
* Checks whether the $model exists in the database.
*
@ -234,9 +243,22 @@ class UniqueValidator extends Validator
$conditions = [$targetAttribute => $model->$attribute];
}
if (!$model instanceof ActiveRecord) {
return $conditions;
}
// Add table prefix for column
$targetClass = $this->getTargetClass($model);
$tableName = $targetClass::tableName();
$conditionsWithTableName = [];
foreach ($conditions as $columnName => $columnValue) {
$prefixedColumnName = "{$tableName}.$columnName";
$conditionsWithTableName[$prefixedColumnName] = $columnValue;
}
return $conditionsWithTableName;
}
/**
* Builds and adds [[comboNotUnique]] error message to the specified model attribute.
* @param \yii\base\Model $model the data model.

View File

@ -331,6 +331,32 @@ abstract class UniqueValidatorTest extends DatabaseTestCase
$result = $this->invokeMethod(new UniqueValidator(), 'prepareConditions', [$targetAttribute, $model, $attribute]);
$expected = ['val_attr_b' => 'test value b', 'val_attr_c' => 'test value a'];
$this->assertEquals($expected, $result);
// Add table prefix for column name
$model = Profile::findOne(1);
$attribute = 'id';
$targetAttribute = 'id';
$result = $this->invokeMethod(new UniqueValidator(), 'prepareConditions', [$targetAttribute, $model, $attribute]);
$expected = [Profile::tableName() . '.' . $attribute => $model->id];
$this->assertEquals($expected, $result);
}
public function testGetTargetClassWithFilledTargetClassProperty()
{
$validator = new UniqueValidator(['targetClass' => Profile::className()]);
$model = new FakedValidationModel();
$actualTargetClass = $this->invokeMethod($validator, 'getTargetClass', [$model]);
$this->assertEquals(Profile::className(), $actualTargetClass);
}
public function testGetTargetClassWithNotFilledTargetClassProperty()
{
$validator = new UniqueValidator();
$model = new FakedValidationModel();
$actualTargetClass = $this->invokeMethod($validator, 'getTargetClass', [$model]);
$this->assertEquals(FakedValidationModel::className(), $actualTargetClass);
}
public function testPrepareQuery()