diff --git a/README.md b/README.md index d9f83f48..1dcb439e 100644 --- a/README.md +++ b/README.md @@ -319,8 +319,8 @@ The following options are supported by all filters except `Callback` and `Finder multiple values. If disabled, and multiple values are being passed, the filter will fall back to using the default value defined by the `defaultValue` option. -- `mode` (`string`, defaults to `OR`) The conditional mode to use when searching for - multiple values. Valid values are `OR` and `AND`. +- `mode` (`string`, defaults to `OR`) The conditional mode to use when matching + against multiple fields. Valid values are `OR` and `AND`. #### `Finder` diff --git a/src/Model/Filter/Value.php b/src/Model/Filter/Value.php index 5c5444bc..49f5b05b 100644 --- a/src/Model/Filter/Value.php +++ b/src/Model/Filter/Value.php @@ -1,6 +1,8 @@ 'OR', + 'mode' => 'OR' ]; /** @@ -36,21 +38,19 @@ public function process() return; } - $this->query()->andWhere(function ($e) use ($value, $isMultiValue) { - /* @var $e \Cake\Database\Expression\QueryExpression */ - $field = $this->field(); - - if (strtoupper($this->config('mode')) === 'OR' && - $isMultiValue - ) { - return $e->in($field, $value); - } + $expressions = []; + foreach ($this->fields() as $field) { + $expressions[] = function (QueryExpression $e) use ($field, $value, $isMultiValue) { + if ($isMultiValue) { + return $e->in($field, $value); + } - foreach ((array)$value as $val) { - $e->eq($field, $val); - } + return $e->eq($field, $value); + }; + } - return $e; - }); + if (!empty($expressions)) { + $this->query()->andWhere([$this->config('mode') => $expressions]); + } } } diff --git a/tests/TestCase/Model/Filter/ValueTest.php b/tests/TestCase/Model/Filter/ValueTest.php index 3cb2fe4c..b08fc7b8 100644 --- a/tests/TestCase/Model/Filter/ValueTest.php +++ b/tests/TestCase/Model/Filter/ValueTest.php @@ -87,6 +87,55 @@ public function testProcessSingleValueWithAndMode() ); } + /** + * @return void + */ + public function testProcessSingleValueAndMultiField() + { + $articles = TableRegistry::get('Articles'); + $manager = new Manager($articles); + $filter = new Value('title', $manager, [ + 'field' => ['title', 'other'] + ]); + $filter->args(['title' => 'foo']); + $filter->query($articles->find()); + $filter->process(); + + $this->assertRegExp( + '/WHERE \(Articles\.title = :c0 OR Articles\.other = :c1\)$/', + $filter->query()->sql() + ); + $this->assertEquals( + ['foo', 'foo'], + Hash::extract($filter->query()->valueBinder()->bindings(), '{s}.value') + ); + } + + /** + * @return void + */ + public function testProcessSingleValueAndMultiFieldWithAndMode() + { + $articles = TableRegistry::get('Articles'); + $manager = new Manager($articles); + $filter = new Value('title', $manager, [ + 'field' => ['title', 'other'], + 'mode' => 'and' + ]); + $filter->args(['title' => 'foo']); + $filter->query($articles->find()); + $filter->process(); + + $this->assertRegExp( + '/WHERE \(Articles\.title = :c0 AND Articles\.other = :c1\)$/', + $filter->query()->sql() + ); + $this->assertEquals( + ['foo', 'foo'], + Hash::extract($filter->query()->valueBinder()->bindings(), '{s}.value') + ); + } + /** * @return void */ @@ -125,7 +174,7 @@ public function testProcessMultiValueWithAndMode() $filter->process(); $this->assertRegExp( - '/WHERE \(Articles\.title = :c0 AND Articles\.title = :c1\)$/', + '/WHERE Articles\.title IN \(:c0,:c1\)$/', $filter->query()->sql() ); $this->assertEquals( @@ -134,6 +183,59 @@ public function testProcessMultiValueWithAndMode() ); } + /** + * @return void + */ + public function testProcessMultiValueAndMultiField() + { + $articles = TableRegistry::get('Articles'); + $manager = new Manager($articles); + $filter = new Value('title', $manager, [ + 'multiValue' => true, + 'field' => ['title', 'other'] + ]); + $filter->args(['title' => ['foo', 'bar']]); + $filter->query($articles->find()); + $filter->process(); + + $this->assertRegExp( + '/WHERE \(Articles\.title IN \(:c0,:c1\) ' . + 'OR Articles\.other IN \(:c2,:c3\)\)$/', + $filter->query()->sql() + ); + $this->assertEquals( + ['foo', 'bar', 'foo', 'bar'], + Hash::extract($filter->query()->valueBinder()->bindings(), '{s}.value') + ); + } + + /** + * @return void + */ + public function testProcessMultiValueAndMultiFieldWithAndMode() + { + $articles = TableRegistry::get('Articles'); + $manager = new Manager($articles); + $filter = new Value('title', $manager, [ + 'multiValue' => true, + 'field' => ['title', 'other'], + 'mode' => 'and' + ]); + $filter->args(['title' => ['foo', 'bar']]); + $filter->query($articles->find()); + $filter->process(); + + $this->assertRegExp( + '/WHERE \(Articles\.title IN \(:c0,:c1\) ' . + 'AND Articles\.other IN \(:c2,:c3\)\)$/', + $filter->query()->sql() + ); + $this->assertEquals( + ['foo', 'bar', 'foo', 'bar'], + Hash::extract($filter->query()->valueBinder()->bindings(), '{s}.value') + ); + } + /** * @return void */