diff --git a/docs/guide/db-query-builder.md b/docs/guide/db-query-builder.md index 696ae05a27..7a9db3087f 100644 --- a/docs/guide/db-query-builder.md +++ b/docs/guide/db-query-builder.md @@ -716,6 +716,8 @@ $query = (new \yii\db\Query()) ->all(); ``` +The column name passed into [[yii\db\Query::indexBy()|indexBy()]] method has to be a part of the `SELECT` fragment of a SQL statement. If [[yii\db\Query::select()|select()]] is not used, all columns are selected and therefore the condition is met. If [[yii\db\Query::select()|select()]] is used with an array in its parameter, Yii handles adding that required SQL fragment for you. This applies when using [[yii\db\Query::indexBy()|indexBy()]] with [[yii\db\Query::all()|all()]] or [[yii\db\Query::column()|column()]]. In other cases, like the following example with an anonymous function, is up to users themselves to take care of it. + To index by expression values, pass an anonymous function to the [[yii\db\Query::indexBy()|indexBy()]] method: ```php diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index b1eb85af19..e1233c84f1 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -4,6 +4,7 @@ Yii Framework 2 Change Log 2.0.41 under development ------------------------ +- Enh #18499: When using `yii\db\Query::all()` and `yii\db\Query::$indexBy`, the `yii\db\Query::$indexBy` is auto inserted into `yii\db\Query::$select` - the same as in `yii\db\Query::column()` (OndrejVasicek, samdark, bizley) - Enh #18483: Add `yii\log\Logger::$dbEventNames` that allows specifying event names used to get statistical results (profiling) of DB queries (atiline) - Enh #18455: Add ability to use separate attributes for data model and filter model of `yii\grid\GridView` in `yii\grid\DataColumn` (PowerGamer1) - Enh #18447: Do not use `getLastInsertID` to get PK from insert query to lower collision probability for concurrent inserts (darkdef) diff --git a/framework/db/ActiveQueryInterface.php b/framework/db/ActiveQueryInterface.php index 9150e8bc2e..8c708072c5 100644 --- a/framework/db/ActiveQueryInterface.php +++ b/framework/db/ActiveQueryInterface.php @@ -53,6 +53,8 @@ interface ActiveQueryInterface extends QueryInterface * // return the index value corresponding to $model * } * ``` + * The column has to be a part of the `SELECT` fragment of a SQL statement. + * If [[yii\db\Query::select()|select()]] is used with an array in its parameter, Yii handles adding that required SQL fragment for you. * * @return $this the query object itself */ diff --git a/framework/db/Query.php b/framework/db/Query.php index ba0a103b8e..f569339ba5 100644 --- a/framework/db/Query.php +++ b/framework/db/Query.php @@ -245,7 +245,16 @@ class Query extends Component implements QueryInterface, ExpressionInterface if ($this->emulateExecution) { return []; } + + if (is_string($this->indexBy) && $this->indexBy && is_array($this->select) && !in_array($this->indexBy, $this->select)) { + if (strpos($this->indexBy, '.') === false && count($tables = $this->getTablesUsedInFrom()) > 0) { + $this->select[] = key($tables) . '.' . $this->indexBy; + } else { + $this->select[] = $this->indexBy; + } + } $rows = $this->createCommand($db)->queryAll(); + return $this->populate($rows); } diff --git a/framework/db/QueryInterface.php b/framework/db/QueryInterface.php index df57ad3838..30df4e52ae 100644 --- a/framework/db/QueryInterface.php +++ b/framework/db/QueryInterface.php @@ -68,6 +68,8 @@ interface QueryInterface * // return the index value corresponding to $row * } * ``` + * The column has to be a part of the `SELECT` fragment of a SQL statement. + * If [[yii\db\Query::select()|select()]] is used with an array in its parameter, Yii handles adding that required SQL fragment for you. * * @return $this the query object itself */ diff --git a/framework/db/QueryTrait.php b/framework/db/QueryTrait.php index 46527dc9f1..277fd05c27 100644 --- a/framework/db/QueryTrait.php +++ b/framework/db/QueryTrait.php @@ -71,6 +71,8 @@ trait QueryTrait * // return the index value corresponding to $row * } * ``` + * The column has to be a part of the `SELECT` fragment of a SQL statement. + * If [[yii\db\Query::select()|select()]] is used with an array in its parameter, Yii handles adding that required SQL fragment for you. * * @return $this the query object itself */ diff --git a/tests/framework/db/QueryTest.php b/tests/framework/db/QueryTest.php index 18179085e4..81eb2af40d 100644 --- a/tests/framework/db/QueryTest.php +++ b/tests/framework/db/QueryTest.php @@ -795,4 +795,23 @@ abstract class QueryTest extends DatabaseTestCase $newQuery->withQueries ); } + + /** + * @see https://github.com/yiisoft/yii2/issues/18499 + */ + public function testAllWithAutomaticallyAddedIndexedByColumn() + { + $db = $this->getConnection(); + + $result = (new Query())->from('customer') + ->select('name') + ->orderBy(['id' => SORT_DESC]) + ->indexBy('id') + ->all($db); + $this->assertEquals([ + 3 => ['name' => 'user3', 'id' => 3], + 2 => ['name' => 'user2', 'id' => 2], + 1 => ['name' => 'user1', 'id' => 1] + ], $result); + } }