diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 9a7718ddfe..e8b43695fd 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -8,7 +8,7 @@ Yii Framework 2 Change Log - Bug #14157: Add support for loading default value `CURRENT_TIMESTAMP` of MySQL `datetime` field (rossoneri) - Bug #15046: Throw an `yii\web\HeadersAlreadySentException` if headers were sent before web response (dmirogin) - Enh #3087: Added `yii\helpers\BaseHtml::error()` "errorMethod" option to be able to customize errors display (yanggs07, developeruz) -- Bug #15355: Fixed `yii\db\Query::from()` does not work with `yii\db\Expression` (vladis84) +- Bug #15355: Fixed `yii\db\Query::from()` does not work with `yii\db\Expression` (vladis84, silverfire, samdark) - Bug #8983: Only truncate the original log file for rotation (matthewyang, developeruz) - Bug #14276: Fixed I18N format with dotted parameters (developeruz) - Bug #14484: Fixed `yii\validators\UniqueValidator` for target classes with a default scope (laszlovl, developeruz) diff --git a/framework/db/Query.php b/framework/db/Query.php index 13aa8bee7f..88be4171ce 100644 --- a/framework/db/Query.php +++ b/framework/db/Query.php @@ -10,6 +10,7 @@ namespace yii\db; use Yii; use yii\base\Component; use yii\base\InvalidConfigException; +use yii\base\InvalidParamException; /** * Query represents a SELECT SQL statement in a way that is independent of DBMS. @@ -481,60 +482,57 @@ class Query extends Component implements QueryInterface // Clean up table names and aliases $cleanedUpTableNames = []; foreach ($tableNames as $alias => $tableName) { - $tableNameString = null; - if (is_string($tableName)) { - $tableNameString = $tableName; - } elseif ($tableName instanceof Expression) { - $tableNameString = $tableName->expression; - } - - if (!is_string($alias) && $tableNameString !== null) { + if (is_string($tableName) && !is_string($alias)) { $pattern = <<ensureNameQuoted($alias)] = $tableNameString; + if (!is_string($alias)) { + throw new InvalidParamException('To use Expression in from() method, pass it in array format with alias.'); + } + $cleanedUpTableNames[$this->ensureNameQuoted($alias)] = $tableName; } elseif ($tableName instanceof self) { $cleanedUpTableNames[$this->ensureNameQuoted($alias)] = $tableName; } else { - $cleanedUpTableNames[$this->ensureNameQuoted($alias)] = $this->ensureNameQuoted($tableNameString); + $cleanedUpTableNames[$this->ensureNameQuoted($alias)] = $this->ensureNameQuoted($tableName); } } diff --git a/tests/framework/db/GetTablesAliasTestTrait.php b/tests/framework/db/GetTablesAliasTestTrait.php index 424ad3a115..dc03e5ef40 100644 --- a/tests/framework/db/GetTablesAliasTestTrait.php +++ b/tests/framework/db/GetTablesAliasTestTrait.php @@ -129,13 +129,14 @@ trait GetTablesAliasTestTrait public function testGetTableNames_isFromAliasedExpression() { $query = $this->createQuery(); - $query->from = new \yii\db\Expression('(SELECT id FROM user) x'); + $expression = new \yii\db\Expression('(SELECT id FROM user)'); + $query->from = $expression; + $this->expectException('yii\base\InvalidParamException'); + $this->expectExceptionMessage('To use Expression in from() method, pass it in array format with alias.'); $tables = $query->getTablesUsedInFrom(); - $this->assertEquals([ - '{{x}}' => '(SELECT id FROM user)', - ], $tables); + $this->assertEquals(['{{x}}' => $expression], $tables); } public function testGetTableNames_isFromAliasedArrayWithExpression()