From 2c31674f424122fe004c4b7bce9f5042cfd94661 Mon Sep 17 00:00:00 2001 From: Chris Blokland Date: Tue, 13 Feb 2018 11:05:53 +0100 Subject: [PATCH 1/7] Allow non array values for input filter --- src/BaseInputFilter.php | 15 ++++--------- test/BaseInputFilterTest.php | 19 ---------------- test/InputFilterTest.php | 42 ++++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 30 deletions(-) diff --git a/src/BaseInputFilter.php b/src/BaseInputFilter.php index 10aff0d3..2e7f9a8d 100644 --- a/src/BaseInputFilter.php +++ b/src/BaseInputFilter.php @@ -178,22 +178,15 @@ public function remove($name) */ public function setData($data) { - // A null value indicates an empty set - if (null === $data) { - $data = []; - } - if ($data instanceof Traversable) { $data = ArrayUtils::iteratorToArray($data); } - if (! is_array($data)) { - throw new Exception\InvalidArgumentException(sprintf( - '%s expects an array or Traversable argument; received %s', - __METHOD__, - (is_object($data) ? get_class($data) : gettype($data)) - )); + // A null value indicates an empty set + if (null === $data || ! is_array($data)) { + $data = []; } + $this->data = $data; $this->populate(); return $this; diff --git a/test/BaseInputFilterTest.php b/test/BaseInputFilterTest.php index 1685020b..2e82363b 100644 --- a/test/BaseInputFilterTest.php +++ b/test/BaseInputFilterTest.php @@ -106,25 +106,6 @@ public function testGetRawValueThrowExceptionIfInputDoesNotExists() $inputFilter->getRawValue('not exists'); } - public function testSetDataWithInvalidDataTypeThrowsInvalidArgumentException() - { - $inputFilter = $this->inputFilter; - - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('expects an array or Traversable argument; received stdClass'); - /** @noinspection PhpParamsInspection */ - $inputFilter->setData(new stdClass()); - } - - public function testIsValidThrowExceptionIfDataWasNotSetYet() - { - $inputFilter = $this->inputFilter; - - $this->expectException(RuntimeException::class); - $this->expectExceptionMessage('no data present to validate'); - $inputFilter->isValid(); - } - public function testSetValidationGroupSkipsRecursionWhenInputIsNotAnInputFilter() { $inputFilter = $this->inputFilter; diff --git a/test/InputFilterTest.php b/test/InputFilterTest.php index fd1e9d81..5655d6d1 100644 --- a/test/InputFilterTest.php +++ b/test/InputFilterTest.php @@ -11,6 +11,7 @@ use ArrayIterator; use PHPUnit_Framework_MockObject_MockObject as MockObject; +use stdClass; use Zend\InputFilter\Factory; use Zend\InputFilter\Input; use Zend\InputFilter\InputFilter; @@ -104,4 +105,45 @@ public function testNestedInputFilterShouldAllowNullValueForData() $filter1->setData(['nested' => null]); self::assertNull($filter1->getValues()['nested']['nestedField1']); } + + public function testNestedInputFilterShouldAllowNonArrayValueForData() + { + $filter1 = new InputFilter(); + $filter1->add([ + 'type' => InputFilter::class, + 'nestedField1' => [ + 'required' => false + ] + ], 'nested'); + + // non scalar and non null value + $filter1->setData(['nested' => false]); + self::assertNull($filter1->getValues()['nested']['nestedField1']); + + $filter1->setData(['nested' => 123]); + self::assertNull($filter1->getValues()['nested']['nestedField1']); + + $filter1->setData(['nested' => new stdClass()]); + self::assertNull($filter1->getValues()['nested']['nestedField1']); + } + + public function testInputFilterShouldAllowNonArrayValueForData() { + $filter1 = new InputFilter(); + $filter1->add([ + 'type' => Input::class, + 'required' => true + ], 'filter'); + + // non scalar and non null value + $filter1->setData(false); + self::assertNull($filter1->getValues()['filter']); + + $filter1->setData(['nested' => 123]); + self::assertNull($filter1->getValues()['filter']); + + $filter1->setData(['nested' => new stdClass()]); + self::assertNull($filter1->getValues()['filter']); + } + + } From 37a1b06ccc92a6656c8a172d9f2fe7b78d9da159 Mon Sep 17 00:00:00 2001 From: Chris Blokland Date: Tue, 13 Feb 2018 12:42:03 +0100 Subject: [PATCH 2/7] Fix #159 use empty array if nested input filter has non array value --- src/BaseInputFilter.php | 23 +++++++++++++++++++---- test/BaseInputFilterTest.php | 9 +++++++++ test/InputFilterTest.php | 20 -------------------- 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/BaseInputFilter.php b/src/BaseInputFilter.php index 2e7f9a8d..d616bdc8 100644 --- a/src/BaseInputFilter.php +++ b/src/BaseInputFilter.php @@ -178,15 +178,22 @@ public function remove($name) */ public function setData($data) { + // A null value indicates an empty set + if (null === $data) { + $data = []; + } + if ($data instanceof Traversable) { $data = ArrayUtils::iteratorToArray($data); } - // A null value indicates an empty set - if (null === $data || ! is_array($data)) { - $data = []; + if (! is_array($data)) { + throw new Exception\InvalidArgumentException(sprintf( + '%s expects an array or Traversable argument; received %s', + __METHOD__, + (is_object($data) ? get_class($data) : gettype($data)) + )); } - $this->data = $data; $this->populate(); return $this; @@ -516,6 +523,14 @@ protected function populate() $value = $this->data[$name]; if ($input instanceof InputFilterInterface) { + if ($value instanceof Traversable) { + $value = ArrayUtils::iteratorToArray($value); + } + + if (! is_array($value)) { + $value = []; + } + $input->setData($value); continue; } diff --git a/test/BaseInputFilterTest.php b/test/BaseInputFilterTest.php index 2e82363b..7a9ccab7 100644 --- a/test/BaseInputFilterTest.php +++ b/test/BaseInputFilterTest.php @@ -106,6 +106,15 @@ public function testGetRawValueThrowExceptionIfInputDoesNotExists() $inputFilter->getRawValue('not exists'); } + public function testIsValidThrowExceptionIfDataWasNotSetYet() + { + $inputFilter = $this->inputFilter; + + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('no data present to validate'); + $inputFilter->isValid(); + } + public function testSetValidationGroupSkipsRecursionWhenInputIsNotAnInputFilter() { $inputFilter = $this->inputFilter; diff --git a/test/InputFilterTest.php b/test/InputFilterTest.php index 5655d6d1..17d22aeb 100644 --- a/test/InputFilterTest.php +++ b/test/InputFilterTest.php @@ -126,24 +126,4 @@ public function testNestedInputFilterShouldAllowNonArrayValueForData() $filter1->setData(['nested' => new stdClass()]); self::assertNull($filter1->getValues()['nested']['nestedField1']); } - - public function testInputFilterShouldAllowNonArrayValueForData() { - $filter1 = new InputFilter(); - $filter1->add([ - 'type' => Input::class, - 'required' => true - ], 'filter'); - - // non scalar and non null value - $filter1->setData(false); - self::assertNull($filter1->getValues()['filter']); - - $filter1->setData(['nested' => 123]); - self::assertNull($filter1->getValues()['filter']); - - $filter1->setData(['nested' => new stdClass()]); - self::assertNull($filter1->getValues()['filter']); - } - - } From f4bee5aafebdd989ea910931a532084f92638b66 Mon Sep 17 00:00:00 2001 From: Chris Blokland Date: Tue, 13 Feb 2018 12:44:53 +0100 Subject: [PATCH 3/7] Remove code duplication --- src/BaseInputFilter.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/BaseInputFilter.php b/src/BaseInputFilter.php index d616bdc8..32bbf72c 100644 --- a/src/BaseInputFilter.php +++ b/src/BaseInputFilter.php @@ -523,11 +523,8 @@ protected function populate() $value = $this->data[$name]; if ($input instanceof InputFilterInterface) { - if ($value instanceof Traversable) { - $value = ArrayUtils::iteratorToArray($value); - } - - if (! is_array($value)) { + // Fixes #159 + if (! is_array($value) && !$value instanceof Traversable) { $value = []; } From 3c46f0222691a72911bbef7c0252e139f665b8d3 Mon Sep 17 00:00:00 2001 From: Chris Blokland Date: Tue, 13 Feb 2018 12:46:12 +0100 Subject: [PATCH 4/7] Restore test to verify InvalidArgumentException is thrown in setData() --- test/BaseInputFilterTest.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/BaseInputFilterTest.php b/test/BaseInputFilterTest.php index 7a9ccab7..1685020b 100644 --- a/test/BaseInputFilterTest.php +++ b/test/BaseInputFilterTest.php @@ -106,6 +106,16 @@ public function testGetRawValueThrowExceptionIfInputDoesNotExists() $inputFilter->getRawValue('not exists'); } + public function testSetDataWithInvalidDataTypeThrowsInvalidArgumentException() + { + $inputFilter = $this->inputFilter; + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('expects an array or Traversable argument; received stdClass'); + /** @noinspection PhpParamsInspection */ + $inputFilter->setData(new stdClass()); + } + public function testIsValidThrowExceptionIfDataWasNotSetYet() { $inputFilter = $this->inputFilter; From ebb2d75d92f015eb0e0747ecd1e1816a34d3398f Mon Sep 17 00:00:00 2001 From: Chris Blokland Date: Wed, 14 Feb 2018 12:38:20 +0100 Subject: [PATCH 5/7] Fix code styling issue --- src/BaseInputFilter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BaseInputFilter.php b/src/BaseInputFilter.php index 32bbf72c..124a16b3 100644 --- a/src/BaseInputFilter.php +++ b/src/BaseInputFilter.php @@ -524,7 +524,7 @@ protected function populate() if ($input instanceof InputFilterInterface) { // Fixes #159 - if (! is_array($value) && !$value instanceof Traversable) { + if (! is_array($value) && ! $value instanceof Traversable) { $value = []; } From 62d0286bde1c13be05f7e2da106a4da2011d860e Mon Sep 17 00:00:00 2001 From: Chris Blokland Date: Fri, 23 Feb 2018 15:03:10 +0100 Subject: [PATCH 6/7] Move test to correct class to fix coverage --- test/BaseInputFilterTest.php | 18 ++++++++++++++++++ test/InputFilterTest.php | 21 --------------------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/test/BaseInputFilterTest.php b/test/BaseInputFilterTest.php index 1685020b..829c82d6 100644 --- a/test/BaseInputFilterTest.php +++ b/test/BaseInputFilterTest.php @@ -585,6 +585,24 @@ public function testMerge() ); } + public function testNestedInputFilterShouldAllowNonArrayValueForData() + { + $filter1 = new BaseInputFilter(); + $nestedFilter = new BaseInputFilter(); + $nestedFilter->add(new Input('nestedField1')); + $filter1->add($nestedFilter, 'nested'); + + // non scalar and non null value + $filter1->setData(['nested' => false]); + self::assertNull($filter1->getValues()['nested']['nestedField1']); + + $filter1->setData(['nested' => 123]); + self::assertNull($filter1->getValues()['nested']['nestedField1']); + + $filter1->setData(['nested' => new stdClass()]); + self::assertNull($filter1->getValues()['nested']['nestedField1']); + } + public function addMethodArgumentsProvider() { $inputTypes = $this->inputProvider(); diff --git a/test/InputFilterTest.php b/test/InputFilterTest.php index 17d22aeb..16a45b6c 100644 --- a/test/InputFilterTest.php +++ b/test/InputFilterTest.php @@ -105,25 +105,4 @@ public function testNestedInputFilterShouldAllowNullValueForData() $filter1->setData(['nested' => null]); self::assertNull($filter1->getValues()['nested']['nestedField1']); } - - public function testNestedInputFilterShouldAllowNonArrayValueForData() - { - $filter1 = new InputFilter(); - $filter1->add([ - 'type' => InputFilter::class, - 'nestedField1' => [ - 'required' => false - ] - ], 'nested'); - - // non scalar and non null value - $filter1->setData(['nested' => false]); - self::assertNull($filter1->getValues()['nested']['nestedField1']); - - $filter1->setData(['nested' => 123]); - self::assertNull($filter1->getValues()['nested']['nestedField1']); - - $filter1->setData(['nested' => new stdClass()]); - self::assertNull($filter1->getValues()['nested']['nestedField1']); - } } From 0570a91fa3e48bcb2311bd6ea7dc111669b4383e Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Mon, 14 May 2018 12:32:05 -0500 Subject: [PATCH 7/7] Adds CHANGELOG entry for #163 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c520fb35..10aff78f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,12 @@ All notable changes to this project will be documented in this file, in reverse ### Fixed +- [#163](https://github.com/zendframework/zend-inputfilter/pull/163) adds code to `BaseInputFilter::populate()` to detect non-iterable, + non-null values passed as a value for a composed input filter. Previously, these would trigger + an exception; they now instead result in an empty array being used to populate the + input filter, which will generally result in invalidation without causing an + exception. + - [#162](https://github.com/zendframework/zend-inputfilter/pull/162) fixes incorrect abstract service factory registration in `ConfigProvider`as per the [latest documentation](https://docs.zendframework.com/zend-inputfilter/specs/#setup). In particular, it ensures that the `InputFilterAbstractFactory` is registered under the `input_filters` configuration instead of the