From decd45201c47767d36b0eb040032c42bcea3909a Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Sun, 11 Oct 2015 09:58:09 +0200 Subject: [PATCH] allow passing a single Expression object to select() and addSelect() fixes #9883 --- framework/CHANGELOG.md | 1 + framework/db/Query.php | 16 +++++++++++----- tests/framework/db/QueryBuilderTest.php | 21 +++++++++++++++++++++ 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 98d57476a1..249a8ddc62 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -22,6 +22,7 @@ Yii Framework 2 Change Log - Bug #9754: Fixed `yii\web\Request` error when path info is empty (dynasource) - Bug #9791: Fixed endless loop on file creation for non-existing device letters on windows (lukos, cebe) - Bug #9874: Fixed outputting exception stacktrace in non-debug mode when `Response::FORMAT_RAW` is used (nainoon) +- Bug #9883: Passing a single `yii\db\Expression` to `Query::select()` or `::addSelect()` was not handled correctly in all cases (cebe) - Bug: Fixed generation of canonical URLs for `ViewAction` pages (samdark) - Enh #7581: Added ability to specify range using anonymous function in `RangeValidator` (RomeroMsk) - Enh #8613: `yii\widgets\FragmentCache` will not store empty content anymore which fixes some problems related to `yii\filters\PageCache` (kidol) diff --git a/framework/db/Query.php b/framework/db/Query.php index 0a044a11e2..cc3ec4ab22 100644 --- a/framework/db/Query.php +++ b/framework/db/Query.php @@ -397,11 +397,12 @@ class Query extends Component implements QueryInterface /** * Sets the SELECT part of the query. - * @param string|array $columns the columns to be selected. + * @param string|array|Expression $columns the columns to be selected. * Columns can be specified in either a string (e.g. "id, name") or an array (e.g. ['id', 'name']). * Columns can be prefixed with table names (e.g. "user.id") and/or contain column aliases (e.g. "user.id AS user_id"). * The method will automatically quote the column names unless a column contains some parenthesis - * (which means the column contains a DB expression). + * (which means the column contains a DB expression). A DB expression may also be passed in form of + * an [[Expression]] object. * * Note that if you are selecting an expression like `CONCAT(first_name, ' ', last_name)`, you should * use an array to specify the columns. Otherwise, the expression may be incorrectly split into several parts. @@ -418,7 +419,9 @@ class Query extends Component implements QueryInterface */ public function select($columns, $option = null) { - if (!is_array($columns)) { + if ($columns instanceof Expression) { + $columns = [$columns]; + } elseif (!is_array($columns)) { $columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY); } $this->select = $columns; @@ -436,13 +439,16 @@ class Query extends Component implements QueryInterface * $query->addSelect(["*", "CONCAT(first_name, ' ', last_name) AS full_name"])->one(); * ``` * - * @param string|array $columns the columns to add to the select. + * @param string|array|Expression $columns the columns to add to the select. See [[select()]] for more + * details about the format of this parameter. * @return $this the query object itself * @see select() */ public function addSelect($columns) { - if (!is_array($columns)) { + if ($columns instanceof Expression) { + $columns = [$columns]; + } elseif (!is_array($columns)) { $columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY); } if ($this->select === null) { diff --git a/tests/framework/db/QueryBuilderTest.php b/tests/framework/db/QueryBuilderTest.php index a026ceb4f7..42eee284c7 100644 --- a/tests/framework/db/QueryBuilderTest.php +++ b/tests/framework/db/QueryBuilderTest.php @@ -505,6 +505,27 @@ class QueryBuilderTest extends DatabaseTestCase $this->assertEmpty($params); } + public function testSelectExpression() + { + $query = (new Query()) + ->select(new Expression("1 AS ab")) + ->from('tablename'); + list ($sql, $params) = $this->getQueryBuilder()->build($query); + $expected = $this->replaceQuotes("SELECT 1 AS ab FROM `tablename`"); + $this->assertEquals($expected, $sql); + $this->assertEmpty($params); + + $query = (new Query()) + ->select(new Expression("1 AS ab")) + ->addSelect(new Expression("2 AS cd")) + ->addSelect(['ef' => new Expression("3")]) + ->from('tablename'); + list ($sql, $params) = $this->getQueryBuilder()->build($query); + $expected = $this->replaceQuotes("SELECT 1 AS ab, 2 AS cd, 3 AS `ef` FROM `tablename`"); + $this->assertEquals($expected, $sql); + $this->assertEmpty($params); + } + public function testCompositeInCondition() { $condition = [