mirror of
https://github.com/yiisoft/yii2.git
synced 2025-08-14 14:28:27 +08:00
added support for yii\db\Expression to querybuilder BETWEEN and LIKE
fixes #6164
This commit is contained in:
@ -31,6 +31,7 @@ Yii Framework 2 Change Log
|
||||
- Bug #6107: `yii message` was emptying existing translations in .po in case of multiple categories (samdark)
|
||||
- Bug #6112: `yii message` was incorrectly writing not yet translated strings in .po in case of multiple categories (samdark)
|
||||
- Bug #6172: `yii\rbac\DbManager` should properly quote table and column names (qiangxue)
|
||||
- Bug #6164: Added missing support for `yii\db\Exression` QueryBuilder `BETWEEN` and `LIKE` conditions (cebe)
|
||||
- Bug: Gii console command help information does not contain global options (qiangxue)
|
||||
- Bug: `yii\web\UrlRule` was unable to create URLs for rules containing unicode characters (samdark)
|
||||
- Enh #4181: Added `yii\bootstrap\Modal::$headerOptions` and `yii\bootstrap\Modal::$footerOptions` (tuxoff, samdark)
|
||||
|
@ -1020,10 +1020,24 @@ class QueryBuilder extends \yii\base\Object
|
||||
if (strpos($column, '(') === false) {
|
||||
$column = $this->db->quoteColumnName($column);
|
||||
}
|
||||
$phName1 = self::PARAM_PREFIX . count($params);
|
||||
$params[$phName1] = $value1;
|
||||
$phName2 = self::PARAM_PREFIX . count($params);
|
||||
$params[$phName2] = $value2;
|
||||
if ($value1 instanceof Expression) {
|
||||
foreach ($value1->params as $n => $v) {
|
||||
$params[$n] = $v;
|
||||
}
|
||||
$phName1 = $value1->expression;
|
||||
} else {
|
||||
$phName1 = self::PARAM_PREFIX . count($params);
|
||||
$params[$phName1] = $value1;
|
||||
}
|
||||
if ($value2 instanceof Expression) {
|
||||
foreach ($value2->params as $n => $v) {
|
||||
$params[$n] = $v;
|
||||
}
|
||||
$phName2 = $value2->expression;
|
||||
} else {
|
||||
$phName2 = self::PARAM_PREFIX . count($params);
|
||||
$params[$phName2] = $value2;
|
||||
}
|
||||
|
||||
return "$column $operator $phName1 AND $phName2";
|
||||
}
|
||||
@ -1181,7 +1195,9 @@ class QueryBuilder extends \yii\base\Object
|
||||
|
||||
list($column, $values) = $operands;
|
||||
|
||||
$values = (array) $values;
|
||||
if (!is_array($values)) {
|
||||
$values = [$values];
|
||||
}
|
||||
|
||||
if (empty($values)) {
|
||||
return $not ? '' : '0=1';
|
||||
@ -1193,8 +1209,15 @@ class QueryBuilder extends \yii\base\Object
|
||||
|
||||
$parts = [];
|
||||
foreach ($values as $value) {
|
||||
$phName = self::PARAM_PREFIX . count($params);
|
||||
$params[$phName] = empty($escape) ? $value : ('%' . strtr($value, $escape) . '%');
|
||||
if ($value instanceof Expression) {
|
||||
foreach ($value->params as $n => $v) {
|
||||
$params[$n] = $v;
|
||||
}
|
||||
$phName = $value->expression;
|
||||
} else {
|
||||
$phName = self::PARAM_PREFIX . count($params);
|
||||
$params[$phName] = empty($escape) ? $value : ('%' . strtr($value, $escape) . '%');
|
||||
}
|
||||
$parts[] = "$column $operator $phName";
|
||||
}
|
||||
|
||||
|
@ -166,6 +166,16 @@ class QueryBuilderTest extends DatabaseTestCase
|
||||
[ ['or like', 'name', ['heyho', 'abc']], '`name` LIKE :qp0 OR `name` LIKE :qp1', [':qp0' => '%heyho%', ':qp1' => '%abc%'] ],
|
||||
[ ['or not like', 'name', ['heyho', 'abc']], '`name` NOT LIKE :qp0 OR `name` NOT LIKE :qp1', [':qp0' => '%heyho%', ':qp1' => '%abc%'] ],
|
||||
|
||||
// like with Expression
|
||||
[ ['like', 'name', new Expression('CONCAT("test", colname, "%")')], '`name` LIKE CONCAT("test", colname, "%")', [] ],
|
||||
[ ['not like', 'name', new Expression('CONCAT("test", colname, "%")')], '`name` NOT LIKE CONCAT("test", colname, "%")', [] ],
|
||||
[ ['or like', 'name', new Expression('CONCAT("test", colname, "%")')], '`name` LIKE CONCAT("test", colname, "%")', [] ],
|
||||
[ ['or not like', 'name', new Expression('CONCAT("test", colname, "%")')], '`name` NOT LIKE CONCAT("test", colname, "%")', [] ],
|
||||
[ ['like', 'name', [new Expression('CONCAT("test", colname, "%")'), 'abc']], '`name` LIKE CONCAT("test", colname, "%") AND `name` LIKE :qp0', [':qp0' => '%abc%'] ],
|
||||
[ ['not like', 'name', [new Expression('CONCAT("test", colname, "%")'), 'abc']], '`name` NOT LIKE CONCAT("test", colname, "%") AND `name` NOT LIKE :qp0', [':qp0' => '%abc%'] ],
|
||||
[ ['or like', 'name', [new Expression('CONCAT("test", colname, "%")'), 'abc']], '`name` LIKE CONCAT("test", colname, "%") OR `name` LIKE :qp0', [':qp0' => '%abc%'] ],
|
||||
[ ['or not like', 'name', [new Expression('CONCAT("test", colname, "%")'), 'abc']], '`name` NOT LIKE CONCAT("test", colname, "%") OR `name` NOT LIKE :qp0', [':qp0' => '%abc%'] ],
|
||||
|
||||
// not
|
||||
[ ['not', 'name'], 'NOT (name)', [] ],
|
||||
|
||||
@ -177,10 +187,13 @@ class QueryBuilderTest extends DatabaseTestCase
|
||||
[ ['or', 'id=1', 'id=2'], '(id=1) OR (id=2)', [] ],
|
||||
[ ['or', 'type=1', ['or', 'id=1', 'id=2']], '(type=1) OR ((id=1) OR (id=2))', [] ],
|
||||
|
||||
|
||||
// between
|
||||
[ ['between', 'id', 1, 10], '`id` BETWEEN :qp0 AND :qp1', [':qp0' => 1, ':qp1' => 10] ],
|
||||
[ ['not between', 'id', 1, 10], '`id` NOT BETWEEN :qp0 AND :qp1', [':qp0' => 1, ':qp1' => 10] ],
|
||||
[ ['between', 'date', new Expression('(NOW() - INTERVAL 1 MONTH)'), new Expression('NOW()')], '`date` BETWEEN (NOW() - INTERVAL 1 MONTH) AND NOW()', [] ],
|
||||
[ ['between', 'date', new Expression('(NOW() - INTERVAL 1 MONTH)'), 123], '`date` BETWEEN (NOW() - INTERVAL 1 MONTH) AND :qp0', [':qp0' => 123] ],
|
||||
[ ['not between', 'date', new Expression('(NOW() - INTERVAL 1 MONTH)'), new Expression('NOW()')], '`date` NOT BETWEEN (NOW() - INTERVAL 1 MONTH) AND NOW()', [] ],
|
||||
[ ['not between', 'date', new Expression('(NOW() - INTERVAL 1 MONTH)'), 123], '`date` NOT BETWEEN (NOW() - INTERVAL 1 MONTH) AND :qp0', [':qp0' => 123] ],
|
||||
|
||||
// in
|
||||
[ ['in', 'id', [1, 2, 3]], '`id` IN (:qp0, :qp1, :qp2)', [':qp0' => 1, ':qp1' => 2, ':qp2' => 3] ],
|
||||
@ -194,7 +207,6 @@ class QueryBuilderTest extends DatabaseTestCase
|
||||
[ ['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] ],
|
||||
|
||||
|
||||
// exists
|
||||
[ ['exists', (new Query())->select('id')->from('users')->where(['active' => 1])], 'EXISTS (SELECT `id` FROM `users` WHERE `active`=:qp0)', [':qp0' => 1] ],
|
||||
[ ['not exists', (new Query())->select('id')->from('users')->where(['active' => 1])], 'NOT EXISTS (SELECT `id` FROM `users` WHERE `active`=:qp0)', [':qp0' => 1] ],
|
||||
@ -209,6 +221,11 @@ class QueryBuilderTest extends DatabaseTestCase
|
||||
[ ['!=', 'a', 'b'], '`a` != :qp0', [':qp0' => 'b'] ],
|
||||
[ ['>=', 'date', new Expression('DATE_SUB(NOW(), INTERVAL 1 MONTH)')], '`date` >= DATE_SUB(NOW(), INTERVAL 1 MONTH)', [] ],
|
||||
[ ['>=', 'date', new Expression('DATE_SUB(NOW(), INTERVAL :month MONTH)', [':month' => 2])], '`date` >= DATE_SUB(NOW(), INTERVAL :month MONTH)', [':month' => 2] ],
|
||||
|
||||
// hash condition
|
||||
[ ['a' => 1, 'b' => 2], '(`a`=:qp0) AND (`b`=:qp1)', [':qp0' => 1, ':qp1' => 2] ],
|
||||
[ ['a' => new Expression('CONCAT(col1, col2)'), 'b' => 2], '(`a`=CONCAT(col1, col2)) AND (`b`=:qp0)', [':qp0' => 2] ],
|
||||
|
||||
];
|
||||
|
||||
// adjust dbms specific escaping
|
||||
|
Reference in New Issue
Block a user