Browse Source

Fixed ambiguous error sql while using unique validator

tags/2.0.12
vladis84 8 years ago committed by Alexander Makarov
parent
commit
8474927a55
No known key found for this signature in database
GPG Key ID: 3617B79C6A325E4A
  1. 1
      framework/CHANGELOG.md
  2. 107
      framework/helpers/ActiveQueryHelper.php
  3. 12
      framework/validators/UniqueValidator.php
  4. 92
      tests/framework/helpers/ActiveQueryHelperTest.php

1
framework/CHANGELOG.md

@ -9,6 +9,7 @@ Yii Framework 2 Change Log
- Bug #13362: Fixed return value of `yii\caching\MemCache::setValues()` (masterklavi)
- Enh #13963: Added tests for yii\behaviors\TimestampBehavior (vladis84)
- Enh #13994: Refactored `yii\filters\RateLimiter`. Added tests (vladis84)
- Bug #13842: Fixed ambiguous error sql while using unique validator (vladis84)
- Enh #13820: Add new HTTP status code 451 (yyxx9988)
- Bug #13671: Fixed error handler trace to work correctly with XDebug (samdark)
- Bug #13657: Fixed `yii\helpers\StringHelper::truncateHtml()` skip extra tags at the end (sam002)

107
framework/helpers/ActiveQueryHelper.php

@ -0,0 +1,107 @@
<?php
namespace yii\helpers;
use yii\db\ActiveQuery;
use yii\base\InvalidConfigException;
class ActiveQueryHelper
{
/**
* Table names calculate on from.
* @param ActiveQuery $query
* @return string[] table names
*/
public static function getTableNames(ActiveQuery $query)
{
$tableNames = [];
$from = $query->from;
if (empty($from)) {
$tableNames[] = self::getTableNameForModel($query);
} elseif (is_array($from)) {
$tableNames = array_values($from);
} elseif (is_string($from)) {
$tableNames = preg_split('/\s*,\s*/', trim($from), -1, PREG_SPLIT_NO_EMPTY);
} else {
self::generateNotSupportedTypeFrom($from);
}
// Clear table alias.
foreach ($tableNames as &$tableName) {
$tableName = preg_replace('/^(\w+)\s*.*$/', '$1', $tableName);
}
return $tableNames;
}
/**
* Tables alias calculate on from.
* @param ActiveQuery $query
* @return string[] table alias
*/
public static function getTablesAlias(ActiveQuery $query)
{
$tablesAlias = [];
$from = $query->from;
if (empty($from)) {
return [self::getTableNameForModel($query)];
}
if (is_string($from)) {
$tableNames = preg_split('/\s*,\s*/', trim($from), -1, PREG_SPLIT_NO_EMPTY);
} elseif (is_array($from)) {
$tableNames = $from;
} else {
self::generateNotSupportedTypeFrom($from);
}
foreach ($tableNames as $alias => $tableName) {
if (is_string($alias)) {
$tablesAlias[] = $alias;
} else {
$tablesAlias[] = self::getAliasForTableName($tableName);
}
}
return $tablesAlias;
}
/**
* @param string $tableName
* @return string
*/
private static function getAliasForTableName($tableName)
{
$cleanedTableName = preg_replace('/\'|\"|`|as/u', '', trim($tableName));
$alias = preg_replace('/^.+\s+(\w+)$/', '$1', $cleanedTableName);
return $alias;
}
/**
* Table name get Model.
* @param ActiveQuery $query
* @return type
*/
private static function getTableNameForModel(ActiveQuery $query)
{
/* @var $modelClass ActiveRecord */
$modelClass = $query->modelClass;
return $modelClass::tableName();
}
/**
* @param mixed $from
* @throws InvalidConfigException
*/
private static function generateNotSupportedTypeFrom($from)
{
$error = sprintf('Not supported type "$s"', gettype($from));
throw new InvalidConfigException($error);
}
}

12
framework/validators/UniqueValidator.php

@ -14,6 +14,7 @@ use yii\db\ActiveRecord;
use yii\db\ActiveQueryInterface;
use yii\db\ActiveRecordInterface;
use yii\helpers\Inflector;
use yii\helpers\ActiveQueryHelper;
/**
* UniqueValidator validates that the attribute value is unique in the specified database table.
@ -249,14 +250,15 @@ class UniqueValidator extends Validator
// Add table prefix for column
$targetClass = $this->getTargetClass($model);
$tableName = $targetClass::tableName();
$conditionsWithTableName = [];
$query = $targetClass::find();
$tableAlias = ActiveQueryHelper::getTablesAlias($query)[0];
$prefixedConditions = [];
foreach ($conditions as $columnName => $columnValue) {
$prefixedColumnName = "{$tableName}.$columnName";
$conditionsWithTableName[$prefixedColumnName] = $columnValue;
$prefixedColumn = "{$tableAlias}.{$columnName}";
$prefixedConditions[$prefixedColumn] = $columnValue;
}
return $conditionsWithTableName;
return $prefixedConditions;
}
/**

92
tests/framework/helpers/ActiveQueryHelperTest.php

@ -0,0 +1,92 @@
<?php
namespace yii\helpers;
use yiiunit\TestCase;
use yii\db\ActiveQuery;
use yii\helpers\ActiveQueryHelper;
use yiiunit\data\ar\Profile;
/**
* Generated by PHPUnit_SkeletonGenerator on 2017-03-25 at 03:32:13.
*/
class ActiveQueryHelperTest extends TestCase
{
public function testGetTableNames_notFilledFrom()
{
$query = new ActiveQuery(Profile::className());
$tableNames = ActiveQueryHelper::getTableNames($query);
$this->assertEquals([Profile::tableName()], $tableNames);
}
public function testGetTableNames_isFromArray()
{
$query = new ActiveQuery(null);
$query->from = ['prf' => 'profile', 'usr' => 'user'];
$tableNames = ActiveQueryHelper::getTableNames($query);
$this->assertEquals(['profile', 'user'], $tableNames);
}
public function testGetTableNames_isFromString()
{
$query = new ActiveQuery(null);
$query->from = 'profile AS \'prf\', user "usr", `order`, "customer"';
$tableNames = ActiveQueryHelper::getTableNames($query);
$this->assertEquals(['profile', 'user', '`order`', '"customer"'], $tableNames);
}
public function testGetTableNames_isFromObject_generateException()
{
$query = new ActiveQuery(null);
$query->from = new \stdClass;
$this->setExpectedException('\yii\base\InvalidConfigException');
ActiveQueryHelper::getTableNames($query);
}
public function testGetTablesAlias_notFilledFrom()
{
$query = new ActiveQuery(Profile::className());
$tablesAlias = ActiveQueryHelper::getTablesAlias($query);
$this->assertEquals([Profile::tableName()], $tablesAlias);
}
public function testGetTablesAlias_isFromArray()
{
$query = new ActiveQuery(null);
$query->from = ['prf' => 'profile', 'usr' => 'user'];
$tablesAlias = ActiveQueryHelper::getTablesAlias($query);
$this->assertEquals(['prf', 'usr'], $tablesAlias);
}
public function testGetTablesAlias_isFromString()
{
$query = new ActiveQuery(null);
$query->from = 'profile AS \'prf\', user "usr", service srv, order';
$tablesAlias = ActiveQueryHelper::getTablesAlias($query);
$this->assertEquals(['prf', 'usr', 'srv', 'order'], $tablesAlias);
}
public function testGetTablesAlias_isFromObject_generateException()
{
$query = new ActiveQuery(null);
$query->from = new \stdClass;
$this->setExpectedException('\yii\base\InvalidConfigException');
ActiveQueryHelper::getTablesAlias($query);
}
}
Loading…
Cancel
Save