Skip to content

Commit

Permalink
Fix #18821: Allow yii\db\ExpressionInterface as column in `yii\db\c…
Browse files Browse the repository at this point in the history
…onditions\InBuilder`
  • Loading branch information
ntesic committed Feb 8, 2022
1 parent 71e810c commit 730f0e5
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 0 deletions.
1 change: 1 addition & 0 deletions framework/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Yii Framework 2 Change Log
2.0.45 under development
------------------------

- Enh #18821: Allow `yii\db\ExpressionInterface` as column in `yii\db\conditions\InBuilder` (ntesic)
- Bug #19182: RBAC Migration failed when use oracle with oci8 (Murolike)
- Bug #19138: Allow digits in language code (ntesic)
- Bug #19148: Fix undefined array key errors in `yii\db\ActiveRelationTrait` (stevekr)
Expand Down
20 changes: 20 additions & 0 deletions framework/db/conditions/InConditionBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ public function build(ExpressionInterface $expression, array &$params = [])
$column = $column->current();
}

if ($column instanceof ExpressionInterface) {
$column = $column->expression;
}

if (is_array($values)) {
$rawValues = $values;
} elseif ($values instanceof \Traversable) {
Expand Down Expand Up @@ -124,6 +128,10 @@ protected function buildValues(ConditionInterface $condition, $values, &$params)
$column = $column->current();
}

if ($column instanceof ExpressionInterface) {
$column = $column->expression;
}

foreach ($values as $i => $value) {
if (is_array($value) || $value instanceof \ArrayAccess) {
$value = isset($value[$column]) ? $value[$column] : null;
Expand Down Expand Up @@ -155,6 +163,9 @@ protected function buildSubqueryInCondition($operator, $columns, $values, &$para

if (is_array($columns)) {
foreach ($columns as $i => $col) {
if ($col instanceof ExpressionInterface) {
$col = $col->expression;
}
if (strpos($col, '(') === false) {
$columns[$i] = $this->queryBuilder->db->quoteColumnName($col);
}
Expand All @@ -163,6 +174,9 @@ protected function buildSubqueryInCondition($operator, $columns, $values, &$para
return '(' . implode(', ', $columns) . ") $operator $sql";
}

if ($columns instanceof ExpressionInterface) {
$columns = $columns->expression;
}
if (strpos($columns, '(') === false) {
$columns = $this->queryBuilder->db->quoteColumnName($columns);
}
Expand All @@ -185,6 +199,9 @@ protected function buildCompositeInCondition($operator, $columns, $values, &$par
foreach ($values as $value) {
$vs = [];
foreach ($columns as $column) {
if ($column instanceof ExpressionInterface) {
$column = $column->expression;
}
if (isset($value[$column])) {
$vs[] = $this->queryBuilder->bindParam($value[$column], $params);
} else {
Expand All @@ -200,6 +217,9 @@ protected function buildCompositeInCondition($operator, $columns, $values, &$par

$sqlColumns = [];
foreach ($columns as $i => $column) {
if ($column instanceof ExpressionInterface) {
$column = $column->expression;
}
$sqlColumns[] = strpos($column, '(') === false ? $this->queryBuilder->db->quoteColumnName($column) : $column;
}

Expand Down
7 changes: 7 additions & 0 deletions framework/db/mssql/conditions/InConditionBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
namespace yii\db\mssql\conditions;

use yii\base\NotSupportedException;
use yii\db\ExpressionInterface;

/**
* {@inheritdoc}
Expand Down Expand Up @@ -37,12 +38,18 @@ protected function buildCompositeInCondition($operator, $columns, $values, &$par
{
$quotedColumns = [];
foreach ($columns as $i => $column) {
if ($column instanceof ExpressionInterface) {
$column = $column->expression;
}
$quotedColumns[$i] = strpos($column, '(') === false ? $this->queryBuilder->db->quoteColumnName($column) : $column;
}
$vss = [];
foreach ($values as $value) {
$vs = [];
foreach ($columns as $i => $column) {
if ($column instanceof ExpressionInterface) {
$column = $column->expression;
}
if (isset($value[$column])) {
$phName = $this->queryBuilder->bindParam($value[$column], $params);
$vs[] = $quotedColumns[$i] . ($operator === 'IN' ? ' = ' : ' != ') . $phName;
Expand Down
7 changes: 7 additions & 0 deletions framework/db/sqlite/conditions/InConditionBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
namespace yii\db\sqlite\conditions;

use yii\base\NotSupportedException;
use yii\db\ExpressionInterface;

/**
* {@inheritdoc}
Expand Down Expand Up @@ -37,12 +38,18 @@ protected function buildCompositeInCondition($operator, $columns, $values, &$par
{
$quotedColumns = [];
foreach ($columns as $i => $column) {
if ($column instanceof ExpressionInterface) {
$column = $column->expression;
}
$quotedColumns[$i] = strpos($column, '(') === false ? $this->queryBuilder->db->quoteColumnName($column) : $column;
}
$vss = [];
foreach ($values as $value) {
$vs = [];
foreach ($columns as $i => $column) {
if ($column instanceof ExpressionInterface) {
$column = $column->expression;
}
if (isset($value[$column])) {
$phName = $this->queryBuilder->bindParam($value[$column], $params);
$vs[] = $quotedColumns[$i] . ($operator === 'IN' ? ' = ' : ' != ') . $phName;
Expand Down
4 changes: 4 additions & 0 deletions tests/framework/db/QueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1184,6 +1184,7 @@ public function conditionProvider()
//in using array object containing only null value
[['in', 'id', new TraversableObject([null])], '[[id]] IS NULL', []],
[['not in', 'id', new TraversableObject([null])], '[[id]] IS NOT NULL', []],
[['not in', new Expression('id'), new TraversableObject([null])], '[[id]] IS NOT NULL', []],

'composite in using array objects' => [
['in', new TraversableObject(['id', 'name']), new TraversableObject([
Expand All @@ -1196,6 +1197,7 @@ public function conditionProvider()

// in object conditions
[new InCondition('id', 'in', 1), '[[id]]=:qp0', [':qp0' => 1]],
[new InCondition(new Expression('id'), 'in', 1), '[[id]]=:qp0', [':qp0' => 1]],
[new InCondition('id', 'in', [1]), '[[id]]=:qp0', [':qp0' => 1]],
[new InCondition('id', 'not in', 1), '[[id]]<>:qp0', [':qp0' => 1]],
[new InCondition('id', 'not in', [1]), '[[id]]<>:qp0', [':qp0' => 1]],
Expand Down Expand Up @@ -1237,6 +1239,7 @@ public function conditionProvider()
case 'sqlite':
$conditions = array_merge($conditions, [
[['in', ['id', 'name'], [['id' => 1, 'name' => 'foo'], ['id' => 2, 'name' => 'bar']]], '(([[id]] = :qp0 AND [[name]] = :qp1) OR ([[id]] = :qp2 AND [[name]] = :qp3))', [':qp0' => 1, ':qp1' => 'foo', ':qp2' => 2, ':qp3' => 'bar']],
[['in', [new Expression('id'), 'name'], [['id' => 1, 'name' => 'foo'], ['id' => 2, 'name' => 'bar']]], '(([[id]] = :qp0 AND [[name]] = :qp1) OR ([[id]] = :qp2 AND [[name]] = :qp3))', [':qp0' => 1, ':qp1' => 'foo', ':qp2' => 2, ':qp3' => 'bar']],
[['not in', ['id', 'name'], [['id' => 1, 'name' => 'foo'], ['id' => 2, 'name' => 'bar']]], '(([[id]] != :qp0 OR [[name]] != :qp1) AND ([[id]] != :qp2 OR [[name]] != :qp3))', [':qp0' => 1, ':qp1' => 'foo', ':qp2' => 2, ':qp3' => 'bar']],
//[ ['in', ['id', 'name'], (new Query())->select(['id', 'name'])->from('users')->where(['active' => 1])], 'EXISTS (SELECT 1 FROM (SELECT [[id]], [[name]] FROM [[users]] WHERE [[active]]=:qp0) AS a WHERE a.[[id]] = [[id AND a.]]name[[ = ]]name`)', [':qp0' => 1] ],
//[ ['not in', ['id', 'name'], (new Query())->select(['id', 'name'])->from('users')->where(['active' => 1])], 'NOT EXISTS (SELECT 1 FROM (SELECT [[id]], [[name]] FROM [[users]] WHERE [[active]]=:qp0) AS a WHERE a.[[id]] = [[id]] AND a.[[name = ]]name`)', [':qp0' => 1] ],
Expand All @@ -1246,6 +1249,7 @@ public function conditionProvider()
$conditions = array_merge($conditions, [
[['in', ['id', 'name'], [['id' => 1, 'name' => 'foo'], ['id' => 2, 'name' => 'bar']]], '([[id]], [[name]]) IN ((:qp0, :qp1), (:qp2, :qp3))', [':qp0' => 1, ':qp1' => 'foo', ':qp2' => 2, ':qp3' => 'bar']],
[['not in', ['id', 'name'], [['id' => 1, 'name' => 'foo'], ['id' => 2, 'name' => 'bar']]], '([[id]], [[name]]) NOT IN ((:qp0, :qp1), (:qp2, :qp3))', [':qp0' => 1, ':qp1' => 'foo', ':qp2' => 2, ':qp3' => 'bar']],
[['not in', [new Expression('id'), 'name'], [['id' => 1, 'name' => 'foo'], ['id' => 2, 'name' => 'bar']]], '([[id]], [[name]]) NOT IN ((:qp0, :qp1), (:qp2, :qp3))', [':qp0' => 1, ':qp1' => 'foo', ':qp2' => 2, ':qp3' => 'bar']],
[['in', ['id', 'name'], (new Query())->select(['id', 'name'])->from('users')->where(['active' => 1])], '([[id]], [[name]]) IN (SELECT [[id]], [[name]] FROM [[users]] WHERE [[active]]=:qp0)', [':qp0' => 1]],
[['not in', ['id', 'name'], (new Query())->select(['id', 'name'])->from('users')->where(['active' => 1])], '([[id]], [[name]]) NOT IN (SELECT [[id]], [[name]] FROM [[users]] WHERE [[active]]=:qp0)', [':qp0' => 1]],
]);
Expand Down

0 comments on commit 730f0e5

Please sign in to comment.