Browse Source

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).

close #8505
tags/2.0.8
Lennart van den Dool 9 years ago committed by Carsten Brandt
parent
commit
f8a844a90f
  1. 3
      framework/CHANGELOG.md
  2. 37
      framework/db/Query.php
  3. 31
      tests/framework/db/QueryTest.php

3
framework/CHANGELOG.md

@ -283,6 +283,9 @@ Yii Framework 2 Change Log
- Enh #9263: Avoid extra DB query in RBAC DbManager in case auth item name is empty (samdark)
- Enh #9268: Improved display of boolean parameters in logged SQL queries (arkhamvm, samdark)
- Enh: Improved Console helper progress bar ETA time estimation, updated only once per second to avoid flapping (cebe)
- 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\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)
- Chg #8556: Extracted `yii\web\User::getAuthManager()` method (samdark)
- Chg #9181: `yii\helpers\BaseStringHelper::truncateHtml()` is now using `runtime` directory for `HTMLPurifier` cache (webdevsega)

37
framework/db/Query.php

@ -582,6 +582,43 @@ class Query extends Component implements QueryInterface
}
/**
* Adds a filtering condition for a specific column and allow the user to choose a filter operator.
*
* It adds an additional WHERE condition for the given field and determines the comparison operator
* based on the first few characters of the given value.
* The condition is added in the same way as in [[andFilterWhere]] so [[isEmpty()|empty values]] are ignored.
* The new condition and the existing one will be joined using the 'AND' operator.
*
* 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.
* - `=`: the column must be equal to the given value.
* - If none of the above operators is detected, the `$defaultOperator` will be used.
*
* @param string $name the column name.
* @param string $value the column value optionally prepended with the comparison operator.
* @param string $defaultOperator The operator to use, when no operator is given in `$value`.
* Defaults to `=`, performing an exact match.
* @return $this The query object itself
* @since 2.0.8
*/
public function andFilterCompare($name, $value, $defaultOperator = '=')
{
if (preg_match("/^(<>|>=|>|<=|<|=)/", $value, $matches)) {
$operator = $matches[1];
$value = substr($value, strlen($operator));
} else {
$operator = $defaultOperator;
}
return $this->andFilterWhere([$operator, $name, $value]);
}
/**
* Appends a JOIN part to the query.
* The first parameter specifies what type of join it is.
* @param string $type the type of join, such as INNER JOIN, LEFT JOIN.

31
tests/framework/db/QueryTest.php

@ -244,6 +244,37 @@ class QueryTest extends DatabaseTestCase
}
/**
* @depends testFilterWhere
*/
public function testAndFilterCompare()
{
$query = new Query;
$result = $query->andFilterCompare('name', null);
$this->assertInstanceOf('yii\db\Query', $result);
$this->assertNull($query->where);
$query->andFilterCompare('name', '');
$this->assertNull($query->where);
$query->andFilterCompare('name', 'John Doe');
$condition = ['=', 'name', 'John Doe'];
$this->assertEquals($condition, $query->where);
$condition = ['and', $condition, ['like', 'name', 'Doe']];
$query->andFilterCompare('name', 'Doe', 'like');
$this->assertEquals($condition, $query->where);
$condition = ['and', $condition, ['>', 'rating', '9']];
$query->andFilterCompare('rating', '>9');
$this->assertEquals($condition, $query->where);
$condition = ['and', $condition, ['<=', 'value', '100']];
$query->andFilterCompare('value', '<=100');
$this->assertEquals($condition, $query->where);
}
/**
* @see https://github.com/yiisoft/yii2/issues/8068
*
* @depends testCount

Loading…
Cancel
Save