Fixes #11697: Added filterHaving(), andFilterHaving() and orFilterHaving() to yii\db\Query

Signed-off-by: Alexander Makarov <sam@rmcreative.ru>
This commit is contained in:
Alexander Makarov
2016-12-14 23:58:04 +03:00
parent e78a7fe20e
commit 837b33767c
4 changed files with 146 additions and 18 deletions

View File

@ -369,6 +369,12 @@ You can also specify operator explicitly:
$query->andFilterCompare('name', 'Doe', 'like');
```
Since Yii 2.0.11 there are similar methods for `HAVING` condition:
- [[yii\db\Query::filterHaving()|filterHaving()]]
- [[yii\db\Query::andFilterHaving()|andFilterHaving()]]
- [[yii\db\Query::orFilterHaving()|orFilterHaving()]]
### [[yii\db\Query::orderBy()|orderBy()]] <span id="order-by"></span>
The [[yii\db\Query::orderBy()|orderBy()]] method specifies the `ORDER BY` fragment of a SQL query. For example,

View File

@ -73,6 +73,7 @@ Yii Framework 2 Change Log
- Enh: Added constants for specifying `yii\validators\CompareValidator::$type` (cebe)
- Enh #12854: Added `RangeNotSatisfiableHttpException` to cover HTTP error 416 file request exceptions (zalatov)
- Enh #13122: Optimized query for information about foreign keys in `yii\db\oci` (zlakomanoff)
- Enh #11697: Added `filterHaving()`, `andFilterHaving()` and `orFilterHaving()` to `yii\db\Query` (nicdnepr, samdark)
2.0.10 October 20, 2016
-----------------------

View File

@ -851,24 +851,6 @@ class Query extends Component implements QueryInterface
return $this;
}
public function andFilterHaving(array $condition)
{
$condition = $this->filterCondition($condition);
if ($condition !== []) {
$this->andHaving($condition);
}
return $this;
}
public function orFilterHaving(array $condition)
{
$condition = $this->filterCondition($condition);
if ($condition !== []) {
$this->orHaving($condition);
}
return $this;
}
/**
* Adds an additional HAVING condition to the existing one.
* The new condition and the existing one will be joined using the 'OR' operator.
@ -890,6 +872,91 @@ class Query extends Component implements QueryInterface
return $this;
}
/**
* Sets the HAVING part of the query but ignores [[isEmpty()|empty operands]].
*
* This method is similar to [[having()]]. The main difference is that this method will
* remove [[isEmpty()|empty query operands]]. As a result, this method is best suited
* for building query conditions based on filter values entered by users.
*
* The following code shows the difference between this method and [[having()]]:
*
* ```php
* // HAVING `age`=:age
* $query->filterHaving(['name' => null, 'age' => 20]);
* // HAVING `age`=:age
* $query->having(['age' => 20]);
* // HAVING `name` IS NULL AND `age`=:age
* $query->having(['name' => null, 'age' => 20]);
* ```
*
* Note that unlike [[having()]], you cannot pass binding parameters to this method.
*
* @param array $condition the conditions that should be put in the HAVING part.
* See [[having()]] on how to specify this parameter.
* @return $this the query object itself
* @see having()
* @see andFilterHaving()
* @see orFilterHaving()
* @since 2.0.11
*/
public function filterHaving(array $condition)
{
$condition = $this->filterCondition($condition);
if ($condition !== []) {
$this->having($condition);
}
return $this;
}
/**
* Adds an additional HAVING condition to the existing one but ignores [[isEmpty()|empty operands]].
* The new condition and the existing one will be joined using the 'AND' operator.
*
* This method is similar to [[andHaving()]]. The main difference is that this method will
* remove [[isEmpty()|empty query operands]]. As a result, this method is best suited
* for building query conditions based on filter values entered by users.
*
* @param array $condition the new HAVING condition. Please refer to [[having()]]
* on how to specify this parameter.
* @return $this the query object itself
* @see filterHaving()
* @see orFilterHaving()
* @since 2.0.11
*/
public function andFilterHaving(array $condition)
{
$condition = $this->filterCondition($condition);
if ($condition !== []) {
$this->andHaving($condition);
}
return $this;
}
/**
* Adds an additional HAVING condition to the existing one but ignores [[isEmpty()|empty operands]].
* The new condition and the existing one will be joined using the 'OR' operator.
*
* This method is similar to [[orHaving()]]. The main difference is that this method will
* remove [[isEmpty()|empty query operands]]. As a result, this method is best suited
* for building query conditions based on filter values entered by users.
*
* @param array $condition the new HAVING condition. Please refer to [[having()]]
* on how to specify this parameter.
* @return $this the query object itself
* @see filterHaving()
* @see andFilterHaving()
* @since 2.0.11
*/
public function orFilterHaving(array $condition)
{
$condition = $this->filterCondition($condition);
if ($condition !== []) {
$this->orHaving($condition);
}
return $this;
}
/**
* Appends a SQL statement using UNION operator.
* @param string|Query $sql the SQL statement to be appended using UNION

View File

@ -110,6 +110,60 @@ abstract class QueryTest extends DatabaseTestCase
$this->assertEquals($condition, $query->where);
}
public function testFilterHaving()
{
// should work with hash format
$query = new Query;
$query->filterHaving([
'id' => 0,
'title' => ' ',
'author_ids' => [],
]);
$this->assertEquals(['id' => 0], $query->having);
$query->andFilterHaving(['status' => null]);
$this->assertEquals(['id' => 0], $query->having);
$query->orFilterHaving(['name' => '']);
$this->assertEquals(['id' => 0], $query->having);
// should work with operator format
$query = new Query;
$condition = ['like', 'name', 'Alex'];
$query->filterHaving($condition);
$this->assertEquals($condition, $query->having);
$query->andFilterHaving(['between', 'id', null, null]);
$this->assertEquals($condition, $query->having);
$query->orFilterHaving(['not between', 'id', null, null]);
$this->assertEquals($condition, $query->having);
$query->andFilterHaving(['in', 'id', []]);
$this->assertEquals($condition, $query->having);
$query->andFilterHaving(['not in', 'id', []]);
$this->assertEquals($condition, $query->having);
$query->andFilterHaving(['not in', 'id', []]);
$this->assertEquals($condition, $query->having);
$query->andFilterHaving(['like', 'id', '']);
$this->assertEquals($condition, $query->having);
$query->andFilterHaving(['or like', 'id', '']);
$this->assertEquals($condition, $query->having);
$query->andFilterHaving(['not like', 'id', ' ']);
$this->assertEquals($condition, $query->having);
$query->andFilterHaving(['or not like', 'id', null]);
$this->assertEquals($condition, $query->having);
$query->andFilterHaving(['or', ['eq', 'id', null], ['eq', 'id', []]]);
$this->assertEquals($condition, $query->having);
}
public function testFilterRecursively()
{
$query = new Query();