From b128ec85f4ff105c1ab2f216417e01c670c8870a Mon Sep 17 00:00:00 2001 From: Pavel Ivanov Date: Mon, 31 Dec 2018 13:41:25 +0200 Subject: [PATCH] Fixes #16081: Fixed composite IN using just one column --- framework/CHANGELOG.md | 1 + .../db/conditions/InConditionBuilder.php | 27 ++++++++++++++++--- tests/framework/db/QueryBuilderTest.php | 13 +++++++++ 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 35108afc3b7..be7851cdf82 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -4,6 +4,7 @@ Yii Framework 2 Change Log 2.0.16 under development ------------------------ +- Bug #16081: Fixed composite IN using just one column (rugabarbo) - Bug #16926: Fix shell autocompletion (GHopperMSK) - Bug #15850: check basePath is writable on publish in AssetManager (Groonya) - Bug #16910: Fix messages sorting on extract (Groonya) diff --git a/framework/db/conditions/InConditionBuilder.php b/framework/db/conditions/InConditionBuilder.php index 87e4d8dca27..0424e039ac6 100644 --- a/framework/db/conditions/InConditionBuilder.php +++ b/framework/db/conditions/InConditionBuilder.php @@ -50,12 +50,22 @@ public function build(ExpressionInterface $expression, array &$params = []) // ensure values is an array $values = (array) $values; } - if ($column instanceof \Traversable || ((is_array($column) || $column instanceof \Countable) && count($column) > 1)) { - return $this->buildCompositeInCondition($operator, $column, $values, $params); - } if (is_array($column)) { - $column = reset($column); + if (count($column) > 1) { + return $this->buildCompositeInCondition($operator, $column, $values, $params); + } else { + $column = reset($column); + } + } + + if ($column instanceof \Traversable) { + if (iterator_count($column) > 1) { + return $this->buildCompositeInCondition($operator, $column, $values, $params); + } else { + $column->rewind(); + $column = $column->current(); + } } $sqlValues = $this->buildValues($expression, $values, $params); @@ -88,6 +98,15 @@ protected function buildValues(ConditionInterface $condition, $values, &$params) $sqlValues = []; $column = $condition->getColumn(); + if (is_array($column)) { + $column = reset($column); + } + + if ($column instanceof \Traversable) { + $column->rewind(); + $column = $column->current(); + } + foreach ($values as $i => $value) { if (is_array($value) || $value instanceof \ArrayAccess) { $value = isset($value[$column]) ? $value[$column] : null; diff --git a/tests/framework/db/QueryBuilderTest.php b/tests/framework/db/QueryBuilderTest.php index 154fd51caa9..4cc200caa0c 100644 --- a/tests/framework/db/QueryBuilderTest.php +++ b/tests/framework/db/QueryBuilderTest.php @@ -1130,6 +1130,19 @@ public function conditionProvider() '([[id]], [[name]]) IN ((:qp0, :qp1))', [':qp0' => 1, ':qp1' => 'oy'], ], + 'composite in (just one column)' => [ + ['in', ['id'], [['id' => 1, 'name' => 'Name1'], ['id' => 2, 'name' => 'Name2']]], + '[[id]] IN (:qp0, :qp1)', + [':qp0' => 1, ':qp1' => 2], + ], + 'composite in using array objects (just one column)' => [ + ['in', new TraversableObject(['id']), new TraversableObject([ + ['id' => 1, 'name' => 'Name1'], + ['id' => 2, 'name' => 'Name2'], + ])], + '[[id]] IN (:qp0, :qp1)', + [':qp0' => 1, ':qp1' => 2], + ], // in using array objects. [['id' => new TraversableObject([1, 2])], '[[id]] IN (:qp0, :qp1)', [':qp0' => 1, ':qp1' => 2]],