Merge pull request #2885 branch 'query-filter'

* query-filter:
  added CHANGELOG lines
  added tests for redis
  added proper tests for elasticsearch
  removed unnecessary code duplication
  adjusted tests
  typo
  renamed Query::filter() to Query::filterWhere()
  reverted elasticsearch rename of filter
  Adjusted search model code generated by Gii CRUD generator
  Added support for arbitrary number of parameters for NOT, AND, OR in filter methods of Query
  Gii CRUD generator now uses new addFilter method
  Query::filter() adjustments
  fixes #2002
  Added tests for Query::filter()

Conflicts:
	framework/db/QueryTrait.php
This commit is contained in:
Carsten Brandt
2014-04-02 19:33:40 +02:00
16 changed files with 562 additions and 29 deletions

View File

@@ -114,6 +114,7 @@ Yii Framework 2 Change Log
- Enh #1921: Grid view ActionColumn now allow to name buttons like `{controller/action}` (creocoder)
- Enh #1973: `yii message/extract` is now able to generate `.po` files (SergeiKutanov, samdark)
- Enh #1984: ActionFilter will now mark event as handled when action run is aborted (cebe)
- Enh #2002: Added filterWhere() method to yii\db\Query to allow easy addition of search filter conditions by ignoring empty search fields (samdark, cebe)
- Enh #2003: Added `filter` property to `ExistValidator` and `UniqueValidator` to support adding additional filtering conditions (qiangxue)
- Enh #2008: `yii message/extract` is now able to save translation strings to database (kate-kate, samdark)
- Enh #2043: Added support for custom request body parsers (danschmidt5189, cebe)

View File

@@ -526,7 +526,6 @@ class Query extends Component implements QueryInterface
{
$this->where = $condition;
$this->addParams($params);
return $this;
}
@@ -570,7 +569,65 @@ class Query extends Component implements QueryInterface
$this->where = ['or', $this->where, $condition];
}
$this->addParams($params);
return $this;
}
/**
* Sets the WHERE part of the query ignoring empty parameters.
*
* @param string|array $condition the conditions that should be put in the WHERE part. Please refer to [[where()]]
* on how to specify this parameter.
* @param array $params the parameters (name => value) to be bound to the query.
* @return static the query object itself
* @see andFilter()
* @see orFilter()
*/
public function filterWhere($condition, $params = [])
{
$condition = $this->filterCondition($condition);
if ($condition !== []) {
$this->where($condition, $params);
}
return $this;
}
/**
* Adds an additional WHERE condition to the existing one ignoring empty parameters.
* The new condition and the existing one will be joined using the 'AND' operator.
*
* @param string|array $condition the new WHERE condition. Please refer to [[where()]]
* on how to specify this parameter.
* @param array $params the parameters (name => value) to be bound to the query.
* @return static the query object itself
* @see filter()
* @see orFilter()
*/
public function andFilterWhere($condition, $params = [])
{
$condition = $this->filterCondition($condition);
if ($condition !== []) {
$this->andWhere($condition, $params);
}
return $this;
}
/**
* Adds an additional WHERE condition to the existing one ignoring empty parameters.
* The new condition and the existing one will be joined using the 'OR' operator.
*
* @param string|array $condition the new WHERE condition. Please refer to [[where()]]
* on how to specify this parameter.
* @param array $params the parameters (name => value) to be bound to the query.
* @return static the query object itself
* @see filter()
* @see andFilter()
*/
public function orFilterWhere($condition, $params = [])
{
$condition = $this->filterCondition($condition);
if ($condition !== []) {
$this->orWhere($condition, $params);
}
return $this;
}

View File

@@ -143,6 +143,17 @@ interface QueryInterface
*/
public function where($condition);
/**
* Sets the WHERE part of the query ignoring empty parameters.
*
* @param array $condition the conditions that should be put in the WHERE part. Please refer to [[where()]]
* on how to specify this parameter.
* @return static the query object itself
* @see andFilterWhere()
* @see orFilterWhere()
*/
public function filterWhere($condition);
/**
* Adds an additional WHERE condition to the existing one.
* The new condition and the existing one will be joined using the 'AND' operator.
@@ -154,6 +165,17 @@ interface QueryInterface
*/
public function andWhere($condition);
/**
* Adds an additional WHERE condition to the existing one ignoring empty parameters.
* The new condition and the existing one will be joined using the 'AND' operator.
* @param string|array $condition the new WHERE condition. Please refer to [[where()]]
* on how to specify this parameter.
* @return static the query object itself
* @see filterWhere()
* @see orFilterWhere()
*/
public function andFilterWhere($condition);
/**
* Adds an additional WHERE condition to the existing one.
* The new condition and the existing one will be joined using the 'OR' operator.
@@ -165,6 +187,17 @@ interface QueryInterface
*/
public function orWhere($condition);
/**
* Adds an additional WHERE condition to the existing one ignoring empty parameters.
* The new condition and the existing one will be joined using the 'OR' operator.
* @param string|array $condition the new WHERE condition. Please refer to [[where()]]
* on how to specify this parameter.
* @return static the query object itself
* @see filterWhere()
* @see andFilterWhere()
*/
public function orFilterWhere($condition);
/**
* Sets the ORDER BY part of the query.
* @param string|array $columns the columns (and the directions) to be ordered by.

View File

@@ -7,6 +7,8 @@
namespace yii\db;
use yii\base\NotSupportedException;
/**
* The BaseQuery trait represents the minimum method set of a database Query.
*
@@ -125,6 +127,149 @@ trait QueryTrait
return $this;
}
/**
* Sets the WHERE part of the query but ignores [[isParameterNotEmpty|empty parameters]].
*
* This function can be used to pass fields of a search form directly as search condition
* by ignoring fields that have not been filled.
*
* @param array $condition the conditions that should be put in the WHERE part.
* See [[where()]] on how to specify this parameter.
* @return static the query object itself
* @see where()
* @see andFilterWhere()
* @see orFilterWhere()
*/
public function filterWhere($condition)
{
$condition = $this->filterCondition($condition);
if ($condition !== []) {
$this->where($condition);
}
return $this;
}
/**
* Adds an additional WHERE condition to the existing one but ignores [[isParameterNotEmpty|empty parameters]].
* The new condition and the existing one will be joined using the 'AND' operator.
* @param string|array $condition the new WHERE condition. Please refer to [[where()]]
* on how to specify this parameter.
* @return static the query object itself
* @see filterWhere()
* @see orFilterWhere()
*/
public function andFilterWhere($condition)
{
$condition = $this->filterCondition($condition);
if ($condition !== []) {
$this->andWhere($condition);
}
return $this;
}
/**
* Adds an additional WHERE condition to the existing one but ignores [[isParameterNotEmpty|empty parameters]].
* The new condition and the existing one will be joined using the 'OR' operator.
* @param string|array $condition the new WHERE condition. Please refer to [[where()]]
* on how to specify this parameter.
* @return static the query object itself
* @see filterWhere()
* @see andFilterWhere()
*/
public function orFilterWhere($condition)
{
$condition = $this->filterCondition($condition);
if ($condition !== []) {
$this->orWhere($condition);
}
return $this;
}
/**
* Returns a new condition with [[isParameterNotEmpty|empty parameters]] removed.
*
* @param array $condition original condition
* @return array condition with [[isParameterNotEmpty|empty parameters]] removed.
* @throws NotSupportedException if the condition format is not supported
*/
protected function filterCondition($condition)
{
if (is_array($condition) && isset($condition[0])) {
$operator = strtoupper($condition[0]);
switch ($operator) {
case 'NOT':
case 'AND':
case 'OR':
for ($i = 1, $operandsCount = count($condition); $i < $operandsCount; $i++) {
$subCondition = $this->filterCondition($condition[$i]);
if ($this->isParameterNotEmpty($subCondition)) {
$condition[$i] = $subCondition;
} else {
unset($condition[$i]);
}
}
$operandsCount = count($condition) - 1;
if ($operator === 'NOT' && $operandsCount === 0) {
$condition = [];
} else {
// reindex array
array_splice($condition, 0, 0);
if ($operandsCount === 1) {
$condition = $condition[1];
}
}
break;
case 'IN':
case 'NOT IN':
case 'LIKE':
case 'OR LIKE':
case 'NOT LIKE':
case 'OR NOT LIKE':
if (!$this->isParameterNotEmpty($condition[2])) {
$condition = [];
}
break;
case 'BETWEEN':
case 'NOT BETWEEN':
if (!$this->isParameterNotEmpty($condition[2]) && !$this->isParameterNotEmpty($condition[3])) {
$condition = [];
}
break;
default:
throw new NotSupportedException("filterWhere() does not support the '$operator' operator.");
}
} elseif (is_array($condition)) {
// hash format: 'column1' => 'value1', 'column2' => 'value2', ...
return array_filter($condition, [$this, 'isParameterNotEmpty']);
} else {
throw new NotSupportedException("filterWhere() does not support plain string conditions use where() instead.");
}
return $condition;
}
/**
* Returns `true` if value passed is not "empty".
*
* The value is considered "empty", if
*
* - it is `null`,
* - an empty string (`''`),
* - a string containing only whitespace characters,
* - or an empty array.
*
* @param $value
* @return boolean if parameter is empty
*/
protected function isParameterNotEmpty($value)
{
if (is_string($value)) {
$value = trim($value);
}
return $value !== '' && $value !== [] && $value !== null;
}
/**
* Sets the ORDER BY part of the query.
* @param string|array $columns the columns (and the directions) to be ordered by.