From 39667aa6b7705b04656fe33314806016bb3f3243 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Wed, 26 Mar 2014 15:51:10 -0400 Subject: [PATCH] Fixed activequery select issue. --- framework/db/QueryBuilder.php | 51 +++++++++++++++++++++------- framework/db/oci/QueryBuilder.php | 7 ++-- tests/unit/framework/db/ActiveRecordTest.php | 2 +- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/framework/db/QueryBuilder.php b/framework/db/QueryBuilder.php index a974a22..b9b5e4c 100644 --- a/framework/db/QueryBuilder.php +++ b/framework/db/QueryBuilder.php @@ -65,18 +65,7 @@ class QueryBuilder extends \yii\base\Object public function build($query, $params = []) { $params = empty($params) ? $query->params : array_merge($params, $query->params); - - $select = $query->select; - $from = $query->from; - if ($from === null && $query instanceof ActiveQuery) { - /** @var ActiveRecord $modelClass */ - $modelClass = $query->modelClass; - $tableName = $modelClass::tableName(); - $from = [$tableName]; - if ($select === null && !empty($query->join)) { - $select = ["$tableName.*"]; - } - } + list ($select, $from) = $this->adjustSelectFrom($query); $clauses = [ $this->buildSelect($select, $params, $query->distinct, $query->selectOption), @@ -100,6 +89,44 @@ class QueryBuilder extends \yii\base\Object } /** + * Adjusts the select and from parts of the query when it is an ActiveQuery. + * When ActiveQuery does not specify "from", or if it is a join query without explicit "select", + * certain adjustments need to be made. This method is put here so that QueryBuilder can + * support sub-queries. + * @param Query $query + * @return array the select and from parts. + */ + protected function adjustSelectFrom($query) + { + $select = $query->select; + $from = $query->from; + if ($query instanceof ActiveQuery && (empty($select) || empty($from))) { + /** @var ActiveRecord $modelClass */ + $modelClass = $query->modelClass; + $tableName = $modelClass::tableName(); + if (empty($from)) { + $from = [$tableName]; + } + if (empty($select) && !empty($query->join)) { + foreach ((array)$from as $alias => $table) { + if (is_string($alias)) { + $select = ["$alias.*"]; + } elseif (is_string($table)) { + if (preg_match('/^(.*?)\s+({{\w+}}|\w+)$/', $table, $matches)) { + $alias = $matches[2]; + } else { + $alias = $tableName; + } + $select = ["$alias.*"]; + } + break; + } + } + } + return [$select, $from]; + } + + /** * Creates an INSERT SQL statement. * For example, * diff --git a/framework/db/oci/QueryBuilder.php b/framework/db/oci/QueryBuilder.php index f9b14fd..a27d919 100644 --- a/framework/db/oci/QueryBuilder.php +++ b/framework/db/oci/QueryBuilder.php @@ -8,6 +8,8 @@ namespace yii\db\oci; use yii\base\InvalidParamException; +use yii\db\ActiveQuery; +use yii\db\ActiveRecord; /** * QueryBuilder is the query builder for Oracle databases. @@ -26,10 +28,11 @@ class QueryBuilder extends \yii\db\QueryBuilder public function build($query, $params = []) { $params = empty($params) ? $query->params : array_merge($params, $query->params); + list ($select, $from) = $this->adjustSelectFrom($query); $clauses = [ - $this->buildSelect($query->select, $params, $query->distinct, $query->selectOption), - $this->buildFrom($query->from, $params), + $this->buildSelect($select, $params, $query->distinct, $query->selectOption), + $this->buildFrom($from, $params), $this->buildJoin($query->join, $params), $this->buildWhere($query->where, $params), $this->buildGroupBy($query->groupBy), diff --git a/tests/unit/framework/db/ActiveRecordTest.php b/tests/unit/framework/db/ActiveRecordTest.php index ba4eae1..5c7f1a8 100644 --- a/tests/unit/framework/db/ActiveRecordTest.php +++ b/tests/unit/framework/db/ActiveRecordTest.php @@ -413,7 +413,7 @@ class ActiveRecordTest extends DatabaseTestCase 'items' => function ($q) { $q->from(['items' => 'tbl_item']); }, - ])->one(); + ])->orderBy('tbl_order.id')->one(); } public function testJoinWithAndScope()