Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Query helper method for filter values containing operators #8505

Closed
wants to merge 14 commits into from
Closed
1 change: 1 addition & 0 deletions framework/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 #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)


Expand Down
31 changes: 31 additions & 0 deletions framework/db/QueryTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -375,4 +375,35 @@ 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]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will fail for NOSQL queries such as yii\elasticsearhc\Query or yii\mongodb\Query

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True.. it's RDBMS specific. Would moving this method out of the generic QueryTrait to yii\db\Query suffice?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we could try to port it to the noSQL implementations. Will do that for redis and ES.

}
}
30 changes: 30 additions & 0 deletions tests/framework/db/QueryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down