From 277a6fdef60da2bc53d7f4d314e58bd2c7d0cf19 Mon Sep 17 00:00:00 2001 From: Lennart van den Dool Date: Thu, 21 May 2015 11:34:07 +0200 Subject: [PATCH 01/12] Query helper method for filter values containing operators Basic implementation proposal for yiisoft/yii2#2022 Shortcomings/todo's: * filtering on non-scalars (where IN statements) not supported * Numeric properties with a corresponding validation rule will yield errors when they contain an alphanumeric operator. These properties' rules should be defined as 'string' or 'safe'. * no implementation example in Gii code (yet). --- framework/db/QueryTrait.php | 31 +++++++++++++++++++++++++++++++ tests/framework/db/QueryTest.php | 30 ++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/framework/db/QueryTrait.php b/framework/db/QueryTrait.php index 40d17f11cc0..1c1167a619b 100644 --- a/framework/db/QueryTrait.php +++ b/framework/db/QueryTrait.php @@ -375,4 +375,35 @@ public function offset($offset) $this->offset = $offset; return $this; } + + /** + * Helper for easy querying on gridview filter input allowing the use some common operators + * + * The comparison operator is intelligently determined based on the first few characters in the given value. In particular, it recognizes the following operators if they appear as the leading characters in the given value: + * <: the column must be less than the given value. + * >: the column must be greater than the given value. + * <=: the column must be less than or equal to the given value. + * >=: the column must be greater than or equal to the given value. + * <>: the column must not be the same as the given value. Note that when $partialMatch is true, this would mean the value must not be a substring of the column. + * =: the column must be equal to the given value. + * none of the above: use the $defaultOperator + * + * Note that when the value is empty, no comparison expression will be added to the search condition. + * + * @param string $name column name + * @param scalar $value column value + * @param string $defaultOperator Defaults to =, performing an exact match. + * For example: use 'like' for partial matching + */ + public function compare($name, $value, $defaultOperator = '=') + { + $matches=[]; + if (preg_match("/^(<>|>=|>|<=|<|=)/", $value, $matches)) { + $op = $matches[1]; + $value = substr($value, strlen($op)); + } else { + $op = $defaultOperator; + } + $this->andFilterWhere([$op, $name, $value]); + } } diff --git a/tests/framework/db/QueryTest.php b/tests/framework/db/QueryTest.php index 3f1cf07535c..5f0a9f7cc7b 100644 --- a/tests/framework/db/QueryTest.php +++ b/tests/framework/db/QueryTest.php @@ -220,6 +220,36 @@ public function testCount() $this->assertEquals(2, $count); } + /** + * @depends testFilterWhere + */ + public function testCompare() + { + $query = new Query; + + $query->compare('name', null); + $this->assertNull($query->where); + + $query->compare('name', ''); + $this->assertNull($query->where); + + $query->compare('name', 'John Doe'); + $condition = ['=', 'name', 'John Doe']; + $this->assertEquals($condition, $query->where); + + $condition = ['and', $condition, ['like', 'name', 'Doe']]; + $query->compare('name', 'Doe', 'like'); + $this->assertEquals($condition, $query->where); + + $condition = ['and', $condition, ['>', 'rating', '9']]; + $query->compare('rating', '>9'); + $this->assertEquals($condition, $query->where); + + $condition = ['and', $condition, ['<=', 'value', '100']]; + $query->compare('value', '<=100'); + $this->assertEquals($condition, $query->where); + } + /** * @see https://github.com/yiisoft/yii2/issues/8068 * From 631e3d39b16c0d11d61369e8f82624ce1983fb3c Mon Sep 17 00:00:00 2001 From: Lennart van den Dool Date: Thu, 21 May 2015 11:53:21 +0200 Subject: [PATCH 02/12] more sensible comment --- framework/db/QueryTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/db/QueryTrait.php b/framework/db/QueryTrait.php index 1c1167a619b..58504b6f343 100644 --- a/framework/db/QueryTrait.php +++ b/framework/db/QueryTrait.php @@ -377,7 +377,7 @@ public function offset($offset) } /** - * Helper for easy querying on gridview filter input allowing the use some common operators + * Helper method for easy querying on values containing some common operators. * * The comparison operator is intelligently determined based on the first few characters in the given value. In particular, it recognizes the following operators if they appear as the leading characters in the given value: * <: the column must be less than the given value. From 87020277a412bf3ffc06f42014fa66622b4a048c Mon Sep 17 00:00:00 2001 From: Lennart van den Dool Date: Thu, 21 May 2015 11:58:40 +0200 Subject: [PATCH 03/12] Update CHANGELOG.md --- framework/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 86b43a6c0ee..e4b5f49f480 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -15,6 +15,7 @@ Yii Framework 2 Change Log - Enh #8415: `yii\helpers\Html` allows correct rendering of conditional comments containing `!IE` (salaros, klimov-paul) - Enh #8444: Added `yii\widgets\LinkPager::$linkOptions` to allow configuring HTML attributes of the `a` tags (zinzinday) - Enh #8486: Added support to automatically set the `maxlength` attribute for `Html::activeTextArea()` and `Html::activePassword()` (klimov-paul) +- Enh #2022: `yii\db\QueryTrait` now contains a compare() method that allows filtering using operators in the query value (lennartvdd) - Chg #6354: `ErrorHandler::logException()` will now log the whole exception object instead of only its string representation (cebe) From cbca646c44c0735e5ada6f48777d38384a5898ae Mon Sep 17 00:00:00 2001 From: Lennart van den Dool Date: Thu, 21 May 2015 12:03:39 +0200 Subject: [PATCH 04/12] Method name according to yii2 convention --- framework/db/QueryTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/db/QueryTrait.php b/framework/db/QueryTrait.php index 58504b6f343..fef824d9f2a 100644 --- a/framework/db/QueryTrait.php +++ b/framework/db/QueryTrait.php @@ -395,7 +395,7 @@ public function offset($offset) * @param string $defaultOperator Defaults to =, performing an exact match. * For example: use 'like' for partial matching */ - public function compare($name, $value, $defaultOperator = '=') + public function andFilterCompare($name, $value, $defaultOperator = '=') { $matches=[]; if (preg_match("/^(<>|>=|>|<=|<|=)/", $value, $matches)) { From f2dcdd663057bb049dd6fc0c7ac52616f8121d19 Mon Sep 17 00:00:00 2001 From: Lennart van den Dool Date: Thu, 21 May 2015 12:05:32 +0200 Subject: [PATCH 05/12] reflact method name change in CHANGELOG.md --- framework/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index e4b5f49f480..96064a0704e 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -15,7 +15,7 @@ Yii Framework 2 Change Log - Enh #8415: `yii\helpers\Html` allows correct rendering of conditional comments containing `!IE` (salaros, klimov-paul) - Enh #8444: Added `yii\widgets\LinkPager::$linkOptions` to allow configuring HTML attributes of the `a` tags (zinzinday) - Enh #8486: Added support to automatically set the `maxlength` attribute for `Html::activeTextArea()` and `Html::activePassword()` (klimov-paul) -- Enh #2022: `yii\db\QueryTrait` now contains a compare() method that allows filtering using operators in the query value (lennartvdd) +- Enh #2022: `yii\db\QueryTrait` now contains a andFilterCompare() method that allows filtering using operators in the query value (lennartvdd) - Chg #6354: `ErrorHandler::logException()` will now log the whole exception object instead of only its string representation (cebe) From 68943a168be8d3fe8010c8b597a6150500527cd4 Mon Sep 17 00:00:00 2001 From: Lennart van den Dool Date: Thu, 21 May 2015 12:06:53 +0200 Subject: [PATCH 06/12] use PR # instead of issue # in CHANGELOG.md --- framework/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 96064a0704e..20a68a3d858 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -15,7 +15,7 @@ Yii Framework 2 Change Log - Enh #8415: `yii\helpers\Html` allows correct rendering of conditional comments containing `!IE` (salaros, klimov-paul) - Enh #8444: Added `yii\widgets\LinkPager::$linkOptions` to allow configuring HTML attributes of the `a` tags (zinzinday) - Enh #8486: Added support to automatically set the `maxlength` attribute for `Html::activeTextArea()` and `Html::activePassword()` (klimov-paul) -- Enh #2022: `yii\db\QueryTrait` now contains a andFilterCompare() method that allows filtering using operators in the query value (lennartvdd) +- Enh #8505: `yii\db\QueryTrait` now contains a andFilterCompare() method that allows filtering using operators in the query value (lennartvdd) - Chg #6354: `ErrorHandler::logException()` will now log the whole exception object instead of only its string representation (cebe) From a6e4c9a3c3fc4b8c7a36691988fa31c8cee11514 Mon Sep 17 00:00:00 2001 From: Lennart van den Dool Date: Thu, 21 May 2015 12:13:21 +0200 Subject: [PATCH 07/12] Reflect method name change in test.. --- tests/framework/db/QueryTest.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/framework/db/QueryTest.php b/tests/framework/db/QueryTest.php index 5f0a9f7cc7b..b892897bc3c 100644 --- a/tests/framework/db/QueryTest.php +++ b/tests/framework/db/QueryTest.php @@ -227,26 +227,26 @@ public function testCompare() { $query = new Query; - $query->compare('name', null); + $query->andFilterCompare('name', null); $this->assertNull($query->where); - $query->compare('name', ''); + $query->andFilterCompare('name', ''); $this->assertNull($query->where); - $query->compare('name', 'John Doe'); + $query->andFilterCompare('name', 'John Doe'); $condition = ['=', 'name', 'John Doe']; $this->assertEquals($condition, $query->where); $condition = ['and', $condition, ['like', 'name', 'Doe']]; - $query->compare('name', 'Doe', 'like'); + $query->andFilterCompare('name', 'Doe', 'like'); $this->assertEquals($condition, $query->where); $condition = ['and', $condition, ['>', 'rating', '9']]; - $query->compare('rating', '>9'); + $query->andFilterCompare('rating', '>9'); $this->assertEquals($condition, $query->where); $condition = ['and', $condition, ['<=', 'value', '100']]; - $query->compare('value', '<=100'); + $query->andFilterCompare('value', '<=100'); $this->assertEquals($condition, $query->where); } From 5e7ace015752592144c5c3f4fd1d2fdd2d84fc3b Mon Sep 17 00:00:00 2001 From: Lennart van den Dool Date: Thu, 21 May 2015 23:32:14 +0200 Subject: [PATCH 08/12] move RDBMS specific method to yii\db\Query --- framework/db/Query.php | 31 +++++++++++++++++++++++++++++++ framework/db/QueryTrait.php | 31 ------------------------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/framework/db/Query.php b/framework/db/Query.php index 3aa9e3f90d7..1aff49adb03 100644 --- a/framework/db/Query.php +++ b/framework/db/Query.php @@ -826,4 +826,35 @@ public static function create($from) 'params' => $from->params, ]); } + + /** + * Helper method for easy querying on values containing some common operators. + * + * The comparison operator is intelligently determined based on the first few characters in the given value. In particular, it recognizes the following operators if they appear as the leading characters in the given value: + * <: the column must be less than the given value. + * >: the column must be greater than the given value. + * <=: the column must be less than or equal to the given value. + * >=: the column must be greater than or equal to the given value. + * <>: the column must not be the same as the given value. Note that when $partialMatch is true, this would mean the value must not be a substring of the column. + * =: the column must be equal to the given value. + * none of the above: use the $defaultOperator + * + * Note that when the value is empty, no comparison expression will be added to the search condition. + * + * @param string $name column name + * @param scalar $value column value + * @param string $defaultOperator Defaults to =, performing an exact match. + * For example: use 'like' for partial matching + */ + public function andFilterCompare($name, $value, $defaultOperator = '=') + { + $matches=[]; + if (preg_match("/^(<>|>=|>|<=|<|=)/", $value, $matches)) { + $op = $matches[1]; + $value = substr($value, strlen($op)); + } else { + $op = $defaultOperator; + } + $this->andFilterWhere([$op, $name, $value]); + } } diff --git a/framework/db/QueryTrait.php b/framework/db/QueryTrait.php index fef824d9f2a..40d17f11cc0 100644 --- a/framework/db/QueryTrait.php +++ b/framework/db/QueryTrait.php @@ -375,35 +375,4 @@ public function offset($offset) $this->offset = $offset; return $this; } - - /** - * Helper method for easy querying on values containing some common operators. - * - * The comparison operator is intelligently determined based on the first few characters in the given value. In particular, it recognizes the following operators if they appear as the leading characters in the given value: - * <: the column must be less than the given value. - * >: the column must be greater than the given value. - * <=: the column must be less than or equal to the given value. - * >=: the column must be greater than or equal to the given value. - * <>: the column must not be the same as the given value. Note that when $partialMatch is true, this would mean the value must not be a substring of the column. - * =: the column must be equal to the given value. - * none of the above: use the $defaultOperator - * - * Note that when the value is empty, no comparison expression will be added to the search condition. - * - * @param string $name column name - * @param scalar $value column value - * @param string $defaultOperator Defaults to =, performing an exact match. - * For example: use 'like' for partial matching - */ - public function andFilterCompare($name, $value, $defaultOperator = '=') - { - $matches=[]; - if (preg_match("/^(<>|>=|>|<=|<|=)/", $value, $matches)) { - $op = $matches[1]; - $value = substr($value, strlen($op)); - } else { - $op = $defaultOperator; - } - $this->andFilterWhere([$op, $name, $value]); - } } From 143ba817261f0ba5e2cfa260e2bcb3c9686a231d Mon Sep 17 00:00:00 2001 From: Lennart van den Dool Date: Thu, 21 May 2015 23:35:44 +0200 Subject: [PATCH 09/12] Update CHANGELOG.md --- framework/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 20a68a3d858..3f7b1488ff5 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -15,7 +15,7 @@ Yii Framework 2 Change Log - Enh #8415: `yii\helpers\Html` allows correct rendering of conditional comments containing `!IE` (salaros, klimov-paul) - Enh #8444: Added `yii\widgets\LinkPager::$linkOptions` to allow configuring HTML attributes of the `a` tags (zinzinday) - Enh #8486: Added support to automatically set the `maxlength` attribute for `Html::activeTextArea()` and `Html::activePassword()` (klimov-paul) -- Enh #8505: `yii\db\QueryTrait` now contains a andFilterCompare() method that allows filtering using operators in the query value (lennartvdd) +- Enh #8505: `yii\db\Query` now contains a andFilterCompare() method that allows filtering using operators in the query value (lennartvdd) - Chg #6354: `ErrorHandler::logException()` will now log the whole exception object instead of only its string representation (cebe) From c81ff5c941977bf9c3fb0da59644be8ff07e4f89 Mon Sep 17 00:00:00 2001 From: Lennart van den Dool Date: Fri, 22 May 2015 15:30:13 +0200 Subject: [PATCH 10/12] support method chaining like andFilterWhere() --- framework/db/Query.php | 2 +- tests/framework/db/QueryTest.php | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/framework/db/Query.php b/framework/db/Query.php index 1aff49adb03..2650443c1f9 100644 --- a/framework/db/Query.php +++ b/framework/db/Query.php @@ -855,6 +855,6 @@ public function andFilterCompare($name, $value, $defaultOperator = '=') } else { $op = $defaultOperator; } - $this->andFilterWhere([$op, $name, $value]); + return $this->andFilterWhere([$op, $name, $value]); } } diff --git a/tests/framework/db/QueryTest.php b/tests/framework/db/QueryTest.php index b892897bc3c..4b4b8f6cf29 100644 --- a/tests/framework/db/QueryTest.php +++ b/tests/framework/db/QueryTest.php @@ -223,11 +223,12 @@ public function testCount() /** * @depends testFilterWhere */ - public function testCompare() + public function testAndFilterCompare() { $query = new Query; - $query->andFilterCompare('name', null); + $result = $query->andFilterCompare('name', null); + $this->assertInstanceOf('yii\db\Query', $result); $this->assertNull($query->where); $query->andFilterCompare('name', ''); From 4d52f4e1dee3561fa20e4c61c1615fb3fbd252af Mon Sep 17 00:00:00 2001 From: Lennart van den Dool Date: Fri, 22 May 2015 15:53:49 +0200 Subject: [PATCH 11/12] Update comment --- framework/db/Query.php | 1 + 1 file changed, 1 insertion(+) diff --git a/framework/db/Query.php b/framework/db/Query.php index 2650443c1f9..72a98e4b313 100644 --- a/framework/db/Query.php +++ b/framework/db/Query.php @@ -845,6 +845,7 @@ public static function create($from) * @param scalar $value column value * @param string $defaultOperator Defaults to =, performing an exact match. * For example: use 'like' for partial matching + * @return static The query object itself */ public function andFilterCompare($name, $value, $defaultOperator = '=') { From e6d4a4f59c5bd67f25884120cd138493ff3eb17d Mon Sep 17 00:00:00 2001 From: Lennart van den Dool Date: Tue, 2 Jun 2015 10:27:27 +0200 Subject: [PATCH 12/12] use $this instead of static in phpdoc [skip ci] --- framework/db/Query.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/db/Query.php b/framework/db/Query.php index 8da9c8bbc33..0ad426d18af 100644 --- a/framework/db/Query.php +++ b/framework/db/Query.php @@ -845,7 +845,7 @@ public static function create($from) * @param scalar $value column value * @param string $defaultOperator Defaults to =, performing an exact match. * For example: use 'like' for partial matching - * @return static The query object itself + * @return $this The query object itself */ public function andFilterCompare($name, $value, $defaultOperator = '=') {