mirror of
https://github.com/yiisoft/yii2.git
synced 2025-08-14 14:28:27 +08:00
Refactored solution to be contained within ActiveQuery instead of helper
This commit is contained in:
@ -5,6 +5,7 @@ Yii Framework 2 Change Log
|
||||
--------------------------
|
||||
|
||||
- Bug #13694: `yii\widgets\Pjax` now sends `X-Pjax-Url` header with response to fix redirect (wleona3, Faryshta)
|
||||
- Bug #13842: Fixed ambiguous table SQL error while using unique validator (vladis84, samdark)
|
||||
- Bug #14012: `yii\db\pgsql\Schema::findViewNames()` was skipping materialized views (insolita)
|
||||
- Bug #13362: Fixed return value of `yii\caching\MemCache::setValues()` (masterklavi)
|
||||
- Enh #13963: Added tests for yii\behaviors\TimestampBehavior (vladis84)
|
||||
|
@ -148,10 +148,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface
|
||||
}
|
||||
|
||||
if (empty($this->from)) {
|
||||
/* @var $modelClass ActiveRecord */
|
||||
$modelClass = $this->modelClass;
|
||||
$tableName = $modelClass::tableName();
|
||||
$this->from = [$tableName];
|
||||
$this->from = [$this->getPrimaryTableName()];
|
||||
}
|
||||
|
||||
if (empty($this->select) && !empty($this->join)) {
|
||||
@ -559,9 +556,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface
|
||||
private function getTableNameAndAlias()
|
||||
{
|
||||
if (empty($this->from)) {
|
||||
/* @var $modelClass ActiveRecord */
|
||||
$modelClass = $this->modelClass;
|
||||
$tableName = $modelClass::tableName();
|
||||
$tableName = $this->getPrimaryTableName();
|
||||
} else {
|
||||
$tableName = '';
|
||||
foreach ($this->from as $alias => $tableName) {
|
||||
@ -783,9 +778,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface
|
||||
list($tableName, ) = $this->getTableNameAndAlias();
|
||||
$this->from = [$alias => $tableName];
|
||||
} else {
|
||||
/* @var $modelClass ActiveRecord */
|
||||
$modelClass = $this->modelClass;
|
||||
$tableName = $modelClass::tableName();
|
||||
$tableName = $this->getPrimaryTableName();
|
||||
|
||||
foreach ($this->from as $key => $table) {
|
||||
if ($table === $tableName) {
|
||||
@ -796,4 +789,89 @@ class ActiveQuery extends Query implements ActiveQueryInterface
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Table names based on from
|
||||
* @return string[] table names
|
||||
* @throws \yii\base\InvalidConfigException
|
||||
* @since 2.0.12
|
||||
*/
|
||||
public function getFromTableNames()
|
||||
{
|
||||
$tableNames = [];
|
||||
|
||||
if (empty($this->from)) {
|
||||
$tableNames[] = $this->getPrimaryTableName();
|
||||
} elseif (is_array($this->from)) {
|
||||
$tableNames = array_values($this->from);
|
||||
} elseif (is_string($this->from)) {
|
||||
$tableNames = preg_split('/\s*,\s*/', trim($this->from), -1, PREG_SPLIT_NO_EMPTY);
|
||||
} else {
|
||||
throw new InvalidConfigException(gettype($this->from). ' in $from is not supported.');
|
||||
}
|
||||
|
||||
// Clean up table names
|
||||
foreach ($tableNames as &$tableName) {
|
||||
$tableName = preg_replace('/^(\w+)\s*.*$/', '$1', $tableName);
|
||||
}
|
||||
|
||||
return $tableNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[] table aliases based on from
|
||||
* @throws \yii\base\InvalidConfigException
|
||||
* @since 2.0.12
|
||||
*/
|
||||
public function getFromAliases()
|
||||
{
|
||||
$tablesAlias = [];
|
||||
|
||||
if (empty($this->from)) {
|
||||
return [$this->getPrimaryTableName()];
|
||||
}
|
||||
|
||||
if (is_string($this->from)) {
|
||||
$tableNames = preg_split('/\s*,\s*/', trim($this->from), -1, PREG_SPLIT_NO_EMPTY);
|
||||
} elseif (is_array($this->from)) {
|
||||
$tableNames = $this->from;
|
||||
} else {
|
||||
throw new InvalidConfigException(gettype($this->from). ' in $from is not supported.');
|
||||
}
|
||||
|
||||
foreach ($tableNames as $alias => $tableName) {
|
||||
if (is_string($alias)) {
|
||||
$tablesAlias[] = $alias;
|
||||
} else {
|
||||
$tablesAlias[] = $this->getAliasFromTableName($tableName);
|
||||
}
|
||||
}
|
||||
|
||||
return $tablesAlias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getting alias from table name
|
||||
* Input string may contain alias already specified
|
||||
*
|
||||
* @param string $tableName
|
||||
* @return string
|
||||
* @since 2.0.12
|
||||
*/
|
||||
private function getAliasFromTableName($tableName)
|
||||
{
|
||||
$cleanedUpTableName = preg_replace('/\'|\"|`|as/u', '', trim($tableName));
|
||||
return preg_replace('/^.+\s+(\w+)$/', '$1', $cleanedUpTableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string primary table name
|
||||
* @since 2.0.12
|
||||
*/
|
||||
protected function getPrimaryTableName()
|
||||
{
|
||||
/* @var $modelClass ActiveRecord */
|
||||
$modelClass = $this->modelClass;
|
||||
return $modelClass::tableName();
|
||||
}
|
||||
}
|
||||
|
@ -1,107 +0,0 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
@ -250,11 +250,14 @@ class UniqueValidator extends Validator
|
||||
|
||||
// Add table prefix for column
|
||||
$targetClass = $this->getTargetClass($model);
|
||||
|
||||
/** @var ActiveRecord $targetClass */
|
||||
$query = $targetClass::find();
|
||||
$tableAlias = ActiveQueryHelper::getTablesAlias($query)[0];
|
||||
$tableAliases = $query->getFromAliases();
|
||||
$primaryTableAlias = $tableAliases[0];
|
||||
$prefixedConditions = [];
|
||||
foreach ($conditions as $columnName => $columnValue) {
|
||||
$prefixedColumn = "{$tableAlias}.{$columnName}";
|
||||
$prefixedColumn = "{$primaryTableAlias}.{$columnName}";
|
||||
$prefixedConditions[$prefixedColumn] = $columnValue;
|
||||
}
|
||||
|
||||
|
@ -231,4 +231,82 @@ abstract class ActiveQueryTest extends DatabaseTestCase
|
||||
$this->assertInstanceOf('yii\db\ActiveQuery', $result);
|
||||
$this->assertEquals(['alias' => 'old'], $result->from);
|
||||
}
|
||||
|
||||
public function testGetTableNames_notFilledFrom()
|
||||
{
|
||||
$query = new ActiveQuery(Profile::className());
|
||||
|
||||
$tableNames = $query->getFromTableNames();
|
||||
|
||||
$this->assertEquals([Profile::tableName()], $tableNames);
|
||||
}
|
||||
|
||||
public function testGetTableNames_isFromArray()
|
||||
{
|
||||
$query = new ActiveQuery(null);
|
||||
$query->from = ['prf' => 'profile', 'usr' => 'user'];
|
||||
|
||||
$tableNames = $query->getFromTableNames();
|
||||
|
||||
$this->assertEquals(['profile', 'user'], $tableNames);
|
||||
}
|
||||
|
||||
public function testGetTableNames_isFromString()
|
||||
{
|
||||
$query = new ActiveQuery(null);
|
||||
$query->from = 'profile AS \'prf\', user "usr", `order`, "customer"';
|
||||
|
||||
$tableNames = $query->getFromTableNames();
|
||||
|
||||
$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');
|
||||
|
||||
$query->getFromTableNames();
|
||||
}
|
||||
|
||||
public function testGetTablesAlias_notFilledFrom()
|
||||
{
|
||||
$query = new ActiveQuery(Profile::className());
|
||||
|
||||
$tablesAlias = $query->getFromAliases();
|
||||
|
||||
$this->assertEquals([Profile::tableName()], $tablesAlias);
|
||||
}
|
||||
|
||||
public function testGetTablesAlias_isFromArray()
|
||||
{
|
||||
$query = new ActiveQuery(null);
|
||||
$query->from = ['prf' => 'profile', 'usr' => 'user'];
|
||||
|
||||
$tablesAlias = $query->getFromAliases();
|
||||
|
||||
$this->assertEquals(['prf', 'usr'], $tablesAlias);
|
||||
}
|
||||
|
||||
public function testGetTablesAlias_isFromString()
|
||||
{
|
||||
$query = new ActiveQuery(null);
|
||||
$query->from = 'profile AS \'prf\', user "usr", service srv, order';
|
||||
|
||||
$tablesAlias = $query->getFromAliases();
|
||||
|
||||
$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');
|
||||
|
||||
$query->getFromAliases();
|
||||
}
|
||||
}
|
||||
|
@ -1,92 +0,0 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user