Commit 3c1a8141 by Alexander Makarov

fixes #2002

parent 19327ebd
......@@ -459,7 +459,7 @@ class Query extends Component implements QueryInterface
* @param string $filter
* @return static the query object itself
*/
public function filter($filter)
public function applyFilter($filter)
{
$this->filter = $filter;
......
......@@ -471,6 +471,26 @@ class Query extends Component implements QueryInterface
}
/**
* 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 filter($condition, $params = [])
{
$condition = $this->filterCondition($condition);
if ($condition !== []) {
$this->where($condition, $params);
}
return $this;
}
/**
* Adds an additional WHERE condition to the existing one.
* 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()]]
......@@ -493,6 +513,27 @@ class Query extends Component implements QueryInterface
}
/**
* 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 andFilter($condition, $params = [])
{
$condition = $this->filterCondition($condition);
if ($condition !== []) {
$this->andWhere($condition, $params);
}
return $this;
}
/**
* Adds an additional WHERE condition to the existing one.
* 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()]]
......@@ -515,6 +556,27 @@ class Query extends Component implements QueryInterface
}
/**
* 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 orFilter($condition, $params = [])
{
$condition = $this->filterCondition($condition);
if ($condition !== []) {
$this->orWhere($condition, $params);
}
return $this;
}
/**
* Sets the GROUP BY part of the query.
* @param string|array $columns the columns to be grouped by.
* Columns can be specified in either a string (e.g. "id, name") or an array (e.g. ['id', 'name']).
......@@ -744,4 +806,39 @@ class Query extends Component implements QueryInterface
->callSnippets($from, $source, $match, $this->snippetOptions)
->queryColumn();
}
/**
* Returns new condition with empty (null, empty string, blank string, or empty array) parameters removed
*
* @param array $condition original condition
* @return array condition with empty parameters removed
*/
protected function filterCondition($condition)
{
if (is_array($condition) && isset($condition[0])) {
$operator = strtoupper($condition[0]);
switch ($operator) {
case 'IN':
case 'NOT IN':
case 'LIKE':
case 'OR LIKE':
case 'NOT LIKE':
case 'OR NOT LIKE':
if (!$this->parameterNotEmpty($condition[2])) {
$condition = [];
}
break;
case 'BETWEEN':
case 'NOT BETWEEN':
if (!$this->parameterNotEmpty($condition[2]) && !$this->parameterNotEmpty($condition[3])) {
$condition = [];
}
break;
}
} else {
$condition = $this->filterConditionHash($condition);
}
return $condition;
}
}
......@@ -521,6 +521,26 @@ class Query extends Component implements QueryInterface
}
/**
* 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 filter($condition, $params = [])
{
$condition = $this->filterCondition($condition);
if ($condition !== []) {
$this->where($condition, $params);
}
return $this;
}
/**
* Adds an additional WHERE condition to the existing one.
* 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()]]
......@@ -543,6 +563,27 @@ class Query extends Component implements QueryInterface
}
/**
* 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 andFilter($condition, $params = [])
{
$condition = $this->filterCondition($condition);
if ($condition !== []) {
$this->andWhere($condition, $params);
}
return $this;
}
/**
* Adds an additional WHERE condition to the existing one.
* 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()]]
......@@ -565,6 +606,27 @@ class Query extends Component implements QueryInterface
}
/**
* 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 orFilter($condition, $params = [])
{
$condition = $this->filterCondition($condition);
if ($condition !== []) {
$this->orWhere($condition, $params);
}
return $this;
}
/**
* 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.
......@@ -821,4 +883,39 @@ class Query extends Component implements QueryInterface
return $this;
}
/**
* Returns new condition with empty (null, empty string, blank string, or empty array) parameters removed
*
* @param array $condition original condition
* @return array condition with empty parameters removed
*/
protected function filterCondition($condition)
{
if (is_array($condition) && isset($condition[0])) {
$operator = strtoupper($condition[0]);
switch ($operator) {
case 'IN':
case 'NOT IN':
case 'LIKE':
case 'OR LIKE':
case 'NOT LIKE':
case 'OR NOT LIKE':
if (!$this->parameterNotEmpty($condition[2])) {
$condition = [];
}
break;
case 'BETWEEN':
case 'NOT BETWEEN':
if (!$this->parameterNotEmpty($condition[2]) && !$this->parameterNotEmpty($condition[3])) {
$condition = [];
}
break;
}
} else {
$condition = $this->filterConditionHash($condition);
}
return $condition;
}
}
......@@ -144,6 +144,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 andFilter()
* @see orFilter()
*/
public function filter($condition);
/**
* Adds an additional WHERE condition to the existing one.
* 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()]]
......@@ -155,6 +166,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 filter()
* @see orFilter()
*/
public function andFilter($condition);
/**
* Adds an additional WHERE condition to the existing one.
* 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()]]
......@@ -166,6 +188,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 filter()
* @see andFilter()
*/
public function orFilter($condition);
/**
* Sets the ORDER BY part of the query.
* @param string|array $columns the columns (and the directions) to be ordered by.
* Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array
......
......@@ -89,6 +89,67 @@ trait QueryTrait
}
/**
* Returns true if value passed is null, empty string, blank string, or empty array.
*
* @param $value
* @return boolean if parameter is empty
*/
protected function parameterNotEmpty($value)
{
if (is_string($value)) {
$value = trim($value);
}
return $value !== '' && $value !== [] && $value !== null;
}
/**
* Returns new condition with empty (null, empty string, blank string, or empty array) parameters in hash format
* removed
*
* @param array $condition original condition
* @return array condition with empty parameters removed
*/
protected function filterConditionHash($condition)
{
if (is_array($condition) && !isset($condition[0])) {
// hash format: 'column1' => 'value1', 'column2' => 'value2', ...
$condition = array_filter($condition, [$this, 'parameterNotEmpty']);
}
return $condition;
}
/**
* Returns new condition with empty (null, empty string, blank string, or empty array) parameters removed
*
* @param array $condition original condition
* @return array condition with empty parameters removed
*/
protected function filterCondition($condition)
{
return $this->filterConditionHash($condition);
}
/**
* Sets the WHERE part of the query ignoring empty parameters.
*
* See [[QueryInterface::where()]] for detailed documentation.
*
* @param array $condition the conditions that should be put in the WHERE part.
* @return static the query object itself
* @see andFilter()
* @see orFilter()
*/
public function filter($condition)
{
$condition = $this->filterCondition($condition);
if ($condition !== []) {
$this->where($condition);
}
return $this;
}
/**
* Adds an additional WHERE condition to the existing one.
* 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()]]
......@@ -109,6 +170,26 @@ trait QueryTrait
}
/**
* 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 filter()
* @see orFilter()
*/
public function andFilter($condition)
{
$condition = $this->filterCondition($condition);
if ($condition !== []) {
$this->andWhere($condition);
}
return $this;
}
/**
* Adds an additional WHERE condition to the existing one.
* 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()]]
......@@ -129,6 +210,26 @@ trait QueryTrait
}
/**
* 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 filter()
* @see andFilter()
*/
public function orFilter($condition)
{
$condition = $this->filterCondition($condition);
if ($condition !== []) {
$this->orWhere($condition);
}
return $this;
}
/**
* Sets the ORDER BY part of the query.
* @param string|array $columns the columns (and the directions) to be ordered by.
* Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array
......
......@@ -153,31 +153,20 @@ class QueryTest extends ElasticSearchTestCase
public function testFilter()
{
// should work with hash format
$query = new Query;
$query->filter('id = :id', [':id' => 1]);
$this->assertEquals('id = :id', $query->where);
$this->assertEquals([':id' => 1], $query->params);
$query->andFilter('name = :name', [':name' => 'something']);
$this->assertEquals(['and', 'id = :id', 'name = :name'], $query->where);
$this->assertEquals([':id' => 1, ':name' => 'something'], $query->params);
$query->orFilter('age = :age', [':age' => '30']);
$this->assertEquals(['or', ['and', 'id = :id', 'name = :name'], 'age = :age'], $query->where);
$this->assertEquals([':id' => 1, ':name' => 'something', ':age' => '30'], $query->params);
$query = new Query;
$query->filter('id = :id', [':id' => '']);
$this->assertEquals('', $query->where);
$this->assertEquals([], $query->params);
$query->andFilter('name = :name', [':name' => '']);
$this->assertEquals('', $query->where);
$this->assertEquals([], $query->params);
$query->orFilter('age = :age', [':age' => '']);
$this->assertEquals('', $query->where);
$this->assertEquals([], $query->params);
$query->filter([
'id' => 0,
'title' => ' ',
'author_ids' => [],
]);
$this->assertEquals(['id' => 0], $query->where);
$query->andFilter(['status' => null]);
$this->assertEquals(['id' => 0], $query->where);
$query->orFilter(['name' => '']);
$this->assertEquals(['id' => 0], $query->where);
}
// TODO test facets
......
......@@ -70,44 +70,20 @@ class QueryTest extends MongoDbTestCase
public function testFilter()
{
// should work with hash format
$query = new Query;
$query->filter(['name' => 'name1']);
$this->assertEquals(['name' => 'name1'], $query->where);
$query->andFilter(['address' => 'address1']);
$this->assertEquals(
[
'and',
['name' => 'name1'],
['address' => 'address1']
],
$query->where
);
$query->orFilter(['name' => 'name2']);
$this->assertEquals(
[
'or',
[
'and',
['name' => 'name1'],
['address' => 'address1']
],
['name' => 'name2']
],
$query->where
);
$query = new Query;
$query->filter(['name' => '']);
$this->assertEquals('', $query->where);
$query->filter([
'id' => 0,
'title' => ' ',
'author_ids' => [],
]);
$this->assertEquals(['id' => 0], $query->where);
$query->andFilter(['address' => '']);
$this->assertEquals([], $query->where);
$query->andFilter(['status' => null]);
$this->assertEquals(['id' => 0], $query->where);
$query->orFilter(['name' => '']);
$this->assertEquals([], $query->where);
$this->assertEquals(['id' => 0], $query->where);
}
public function testOrder()
......
......@@ -62,31 +62,59 @@ class QueryTest extends SphinxTestCase
public function testFilter()
{
// should just call where() when string is passed
$query = new Query;
$query->filter('id = :id', [':id' => 1]);
$query->filter('id = :id', [':id' => null]);
$this->assertEquals('id = :id', $query->where);
$this->assertEquals([':id' => 1], $query->params);
$this->assertEquals([':id' => null], $query->params);
$query->andFilter('name = :name', [':name' => 'something']);
$this->assertEquals(['and', 'id = :id', 'name = :name'], $query->where);
$this->assertEquals([':id' => 1, ':name' => 'something'], $query->params);
// should work with hash format
$query = new Query;
$query->filter([
'id' => 0,
'title' => ' ',
'author_ids' => [],
]);
$this->assertEquals(['id' => 0], $query->where);
$query->orFilter('age = :age', [':age' => '30']);
$this->assertEquals(['or', ['and', 'id = :id', 'name = :name'], 'age = :age'], $query->where);
$this->assertEquals([':id' => 1, ':name' => 'something', ':age' => '30'], $query->params);
$query->andFilter(['status' => null]);
$this->assertEquals(['id' => 0], $query->where);
$query->orFilter(['name' => '']);
$this->assertEquals(['id' => 0], $query->where);
// should work with operator format
$query = new Query;
$query->filter('id = :id', [':id' => '']);
$this->assertEquals('', $query->where);
$this->assertEquals([], $query->params);
$condition = ['like', 'name', 'Alex'];
$query->filter($condition);
$this->assertEquals($condition, $query->where);
$query->andFilter(['between', 'id', null, null]);
$this->assertEquals($condition, $query->where);
$query->orFilter(['not between', 'id', null, null]);
$this->assertEquals($condition, $query->where);
$query->andFilter(['in', 'id', []]);
$this->assertEquals($condition, $query->where);
$query->andFilter(['not in', 'id', []]);
$this->assertEquals($condition, $query->where);
$query->andFilter(['not in', 'id', []]);
$this->assertEquals($condition, $query->where);
$query->andFilter(['like', 'id', '']);
$this->assertEquals($condition, $query->where);
$query->andFilter(['or like', 'id', '']);
$this->assertEquals($condition, $query->where);
$query->andFilter('name = :name', [':name' => '']);
$this->assertEquals('', $query->where);
$this->assertEquals([], $query->params);
$query->andFilter(['not like', 'id', ' ']);
$this->assertEquals($condition, $query->where);
$query->orFilter('age = :age', [':age' => '']);
$this->assertEquals('', $query->where);
$this->assertEquals([], $query->params);
$query->andFilter(['or not like', 'id', null]);
$this->assertEquals($condition, $query->where);
}
public function testGroup()
......
......@@ -51,32 +51,59 @@ class QueryTest extends DatabaseTestCase
public function testFilter()
{
// should just call where() when string is passed
$query = new Query;
$query->filter('id = :id', [':id' => 1]);
$query->filter('id = :id', [':id' => null]);
$this->assertEquals('id = :id', $query->where);
$this->assertEquals([':id' => 1], $query->params);
$this->assertEquals([':id' => null], $query->params);
$query->andFilter('name = :name', [':name' => 'something']);
$this->assertEquals(['and', 'id = :id', 'name = :name'], $query->where);
$this->assertEquals([':id' => 1, ':name' => 'something'], $query->params);
// should work with hash format
$query = new Query;
$query->filter([
'id' => 0,
'title' => ' ',
'author_ids' => [],
]);
$this->assertEquals(['id' => 0], $query->where);
$query->orFilter('age = :age', [':age' => '30']);
$this->assertEquals(['or', ['and', 'id = :id', 'name = :name'], 'age = :age'], $query->where);
$this->assertEquals([':id' => 1, ':name' => 'something', ':age' => '30'], $query->params);
$query->andFilter(['status' => null]);
$this->assertEquals(['id' => 0], $query->where);
$query->orFilter(['name' => '']);
$this->assertEquals(['id' => 0], $query->where);
// should work with operator format
$query = new Query;
$condition = ['like', 'name', 'Alex'];
$query->filter($condition);
$this->assertEquals($condition, $query->where);
$query->andFilter(['between', 'id', null, null]);
$this->assertEquals($condition, $query->where);
$query->orFilter(['not between', 'id', null, null]);
$this->assertEquals($condition, $query->where);
$query->andFilter(['in', 'id', []]);
$this->assertEquals($condition, $query->where);
$query->andFilter(['not in', 'id', []]);
$this->assertEquals($condition, $query->where);
$query->andFilter(['not in', 'id', []]);
$this->assertEquals($condition, $query->where);
$query = new Query();
$query->filter('id = :id', [':id' => '']);
$this->assertEquals('', $query->where);
$this->assertEquals([], $query->params);
$query->andFilter(['like', 'id', '']);
$this->assertEquals($condition, $query->where);
$query->andFilter('name = :name', [':name' => '']);
$this->assertEquals('', $query->where);
$this->assertEquals([], $query->params);
$query->andFilter(['or like', 'id', '']);
$this->assertEquals($condition, $query->where);
$query->orFilter('age = :age', [':age' => '']);
$this->assertEquals('', $query->where);
$this->assertEquals([], $query->params);
$query->andFilter(['not like', 'id', ' ']);
$this->assertEquals($condition, $query->where);
$query->andFilter(['or not like', 'id', null]);
$this->assertEquals($condition, $query->where);
}
public function testJoin()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment