diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index a64e346697..89b7935da7 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -4,6 +4,7 @@ Yii Framework 2 Change Log 2.0.16 under development ------------------------ +- Bug #16022: Fix UniqueValidator for PostgreSQL. Checks the uniqueness of keys in `jsonb` field (lav45) - Bug #16903: Fixed 'yii\validators\NumberValidator' method 'isNotNumber' returns false for true/false value (annechko) - Bug #16648: Html::strtolower() was corrupting UTF-8 strings (Kolyunya) - Bug #13977: Skip validation if file input does not exist (RobinKamps, s1lver) diff --git a/framework/validators/UniqueValidator.php b/framework/validators/UniqueValidator.php index 3f7a6fa075..5634f93652 100644 --- a/framework/validators/UniqueValidator.php +++ b/framework/validators/UniqueValidator.php @@ -178,7 +178,7 @@ class UniqueValidator extends Validator */ private function modelExists($targetClass, $conditions, $model) { - /** @var ActiveRecordInterface $targetClass $query */ + /** @var ActiveRecordInterface|\yii\base\BaseObject $targetClass $query */ $query = $this->prepareQuery($targetClass, $conditions); if (!$model instanceof ActiveRecordInterface || $model->getIsNewRecord() || $model->className() !== $targetClass::className()) { @@ -311,10 +311,12 @@ class UniqueValidator extends Validator $prefixedConditions = []; foreach ($conditions as $columnName => $columnValue) { if (strpos($columnName, '(') === false) { - $prefixedColumn = "{$alias}.[[" . preg_replace( - '/^' . preg_quote($alias) . '\.(.*)$/', - '$1', - $columnName) . ']]'; + $columnName = preg_replace('/^' . preg_quote($alias) . '\.(.*)$/', '$1', $columnName); + if (strpos($columnName, '[[') === 0) { + $prefixedColumn = "{$alias}.{$columnName}"; + } else { + $prefixedColumn = "{$alias}.[[{$columnName}]]"; + } } else { // there is an expression, can't prefix it reliably $prefixedColumn = $columnName; diff --git a/tests/data/ar/Type.php b/tests/data/ar/Type.php index c57db8ae24..68d855720e 100644 --- a/tests/data/ar/Type.php +++ b/tests/data/ar/Type.php @@ -26,6 +26,8 @@ namespace yiiunit\data\ar; */ class Type extends ActiveRecord { + public $name; + /** * {@inheritdoc} */ diff --git a/tests/framework/db/pgsql/UniqueValidatorTest.php b/tests/framework/db/pgsql/UniqueValidatorTest.php index d31a535eef..754297b032 100644 --- a/tests/framework/db/pgsql/UniqueValidatorTest.php +++ b/tests/framework/db/pgsql/UniqueValidatorTest.php @@ -7,6 +7,9 @@ namespace yiiunit\framework\db\pgsql; +use yii\validators\UniqueValidator; +use yiiunit\data\ar\Type; + /** * @group db * @group pgsql @@ -15,4 +18,19 @@ namespace yiiunit\framework\db\pgsql; class UniqueValidatorTest extends \yiiunit\framework\validators\UniqueValidatorTest { public $driverName = 'pgsql'; + + public function testPrepareParams() + { + parent::testPrepareParams(); + + // Add table prefix for column name + $model = new Type; + $model->name = 'Angela'; + + $attribute = 'name'; + $targetAttribute = [$attribute => "[[jsonb_col]]->>'name'"]; + $result = $this->invokeMethod(new UniqueValidator(), 'prepareConditions', [$targetAttribute, $model, $attribute]); + $expected = ['{{' . Type::tableName() . '}}.' . $targetAttribute[$attribute] => $model->name]; + $this->assertEquals($expected, $result); + } }