diff --git a/CHANGELOG.md b/CHANGELOG.md
index 03f44a44..4534b71a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,11 +2,22 @@
All notable changes to this project will be documented in this file, in reverse chronological order by release.
-## 2.9.2 - TBD
+## 2.10.0 - 2019-01-30
### Added
-- Nothing.
+- [#176](https://github.com/zendframework/zend-inputfilter/pull/176) adds the interface `UnfilteredDataInterface`, with the following methods:
+
+ ```php
+ public function getUnfilteredData() : array|object;
+ public function setUnfilteredData(array|object $data) : $this;
+ ```
+
+ By default, the `BaseInputFilter` now implements this interface.
+
+ The primary purpose of the interface is to allow the ability to access ALL
+ original raw data, and not just the data the input filter knows about. This is
+ particularly useful with collections.
### Changed
diff --git a/composer.json b/composer.json
index d895fafd..d4825e7d 100644
--- a/composer.json
+++ b/composer.json
@@ -12,8 +12,8 @@
},
"extra": {
"branch-alias": {
- "dev-master": "2.9.x-dev",
- "dev-develop": "2.10.x-dev"
+ "dev-master": "2.10.x-dev",
+ "dev-develop": "2.11.x-dev"
},
"zf": {
"component": "Zend\\InputFilter",
diff --git a/composer.lock b/composer.lock
index 001e4d10..990d3352 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "b7ceabdec2f140507b9c15f618abc0d9",
+ "content-hash": "e21de7a4adcf1b5fdb80477fd117b56b",
"packages": [
{
"name": "container-interop/container-interop",
diff --git a/docs/book/unfiltered-data.md b/docs/book/unfiltered-data.md
new file mode 100644
index 00000000..e9141a81
--- /dev/null
+++ b/docs/book/unfiltered-data.md
@@ -0,0 +1,49 @@
+# Unfiltered Data
+
+> Since 2.10.0
+
+On input filters, there are several methods for retrieving the data:
+
+- `getValues()` will return all known values after filtering them.
+- `getRawValues()` will return all known values with no filtering applied.
+- `getUnknown()` returns the set of all unknown values (values with no
+ corresponding input or input filter).
+
+At times, particularly when working with collections, you may want access to the
+complete set of original data provided to the input filter. This can be
+accomplished by merging the sets returned by `getRawValues()` and
+`getUnknown()` when working with normal input filters, but this approach breaks
+down when working with collections.
+
+Version 2.10.0 introduces a new interface, `Zend\InputFilter\UnfilteredDataInterface`,
+for dealing with this situation. `Zend\InputFilter\BaseInputFilter`, which
+forms the parent class for all shipped input filter implementations, implements
+the interface, which consists of the following methods:
+
+```php
+interface UnfilteredDataInterface
+{
+ /**
+ * @return array|object
+ */
+ public function getUnfilteredData()
+ {
+ return $this->unfilteredData;
+ }
+
+ /**
+ * @param array|object $data
+ * @return $this
+ */
+ public function setUnfilteredData($data)
+ {
+ $this->unfilteredData = $data;
+ return $this;
+ }
+}
+```
+
+The `setUnfilteredData()` method is called by `setData()` with the full `$data`
+provided to that method, ensuring that `getUnfilteredData()` will always provide
+the original data with which the input filter was initialized, with no filtering
+applied.
diff --git a/mkdocs.yml b/mkdocs.yml
index 2b9d4633..6e056c3c 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -1,13 +1,14 @@
docs_dir: docs/book
site_dir: docs/html
pages:
- - index.md
- - Intro: intro.md
+ - Home: index.md
+ - Introduction: intro.md
- Reference:
- Specifications: specs.md
- Files: file-input.md
- "Optional Input Filters": optional-input-filters.md
+ - "Unfiltered Data": unfiltered-data.md
site_name: zend-inputfilter
site_description: zend-inputfilter
repo_url: 'https://github.com/zendframework/zend-inputfilter'
-copyright: 'Copyright (c) 2016-2017 Zend Technologies USA Inc.'
+copyright: 'Copyright (c) 2016-2019 Zend Technologies USA Inc.'
diff --git a/src/BaseInputFilter.php b/src/BaseInputFilter.php
index 5b9b5223..c6db8319 100644
--- a/src/BaseInputFilter.php
+++ b/src/BaseInputFilter.php
@@ -3,7 +3,7 @@
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
- * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright Copyright (c) 2005-2019 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -18,13 +18,19 @@ class BaseInputFilter implements
InputFilterInterface,
UnknownInputsCapableInterface,
InitializableInterface,
- ReplaceableInputInterface
+ ReplaceableInputInterface,
+ UnfilteredDataInterface
{
/**
* @var null|array
*/
protected $data;
+ /**
+ * @var array|object
+ */
+ protected $unfilteredData = [];
+
/**
* @var InputInterface[]|InputFilterInterface[]
*/
@@ -194,8 +200,12 @@ public function setData($data)
(is_object($data) ? get_class($data) : gettype($data))
));
}
+
+ $this->setUnfilteredData($data);
+
$this->data = $data;
$this->populate();
+
return $this;
}
@@ -602,4 +612,22 @@ public function merge(BaseInputFilter $inputFilter)
return $this;
}
+
+ /**
+ * @return array|object
+ */
+ public function getUnfilteredData()
+ {
+ return $this->unfilteredData;
+ }
+
+ /**
+ * @param array|object $data
+ * @return $this
+ */
+ public function setUnfilteredData($data)
+ {
+ $this->unfilteredData = $data;
+ return $this;
+ }
}
diff --git a/src/CollectionInputFilter.php b/src/CollectionInputFilter.php
index 005525fc..5c3e9188 100644
--- a/src/CollectionInputFilter.php
+++ b/src/CollectionInputFilter.php
@@ -153,6 +153,8 @@ public function setData($data)
));
}
+ $this->setUnfilteredData($data);
+
foreach ($data as $item) {
if (is_array($item) || $item instanceof Traversable) {
continue;
diff --git a/src/UnfilteredDataInterface.php b/src/UnfilteredDataInterface.php
new file mode 100644
index 00000000..18d7bc37
--- /dev/null
+++ b/src/UnfilteredDataInterface.php
@@ -0,0 +1,25 @@
+getValues()['nested']['nestedField1']);
}
+ public function testInstanceOfUnfilteredDataInterface()
+ {
+ $baseInputFilter = new BaseInputFilter();
+
+ self::assertInstanceOf(
+ UnfilteredDataInterface::class,
+ $baseInputFilter,
+ sprintf('%s should implement %s', BaseInputFilter::class, UnfilteredDataInterface::class)
+ );
+ }
+
+ public function testGetUnfilteredDataReturnsArray()
+ {
+ $baseInputFilter = new BaseInputFilter();
+
+ self::assertInternalType('array', $baseInputFilter->getUnfilteredData());
+ }
+
+ public function testSetUnfilteredDataReturnsBaseInputFilter()
+ {
+ $baseInputFilter = new BaseInputFilter();
+
+ self::assertInstanceOf(BaseInputFilter::class, $baseInputFilter->setUnfilteredData([]));
+ }
+
+ public function testSettingAndReturningDataArrayUnfilteredDataInterface()
+ {
+ $testArray = [
+ 'foo' => 'bar',
+ ];
+
+ $baseInputFilter = new BaseInputFilter();
+ $baseInputFilter->setUnfilteredData($testArray);
+
+ self::assertSame($testArray, $baseInputFilter->getUnfilteredData());
+ }
+
+ public function testSettingAndReturnDataArrayUsingSetDataForUnfilteredDataInterface()
+ {
+ $testArray = [
+ 'foo' => 'bar',
+ ];
+
+ $baseInputFilter = new BaseInputFilter();
+ $baseInputFilter->setData($testArray);
+
+ self::assertSame($testArray, $baseInputFilter->getUnfilteredData());
+ }
+
+ public function testSetDataUsingSetDataAndApplyFiltersReturningSameAsOriginalForUnfilteredData()
+ {
+ $filteredArray = [
+ 'bar' => 'foo',
+ ];
+
+ $unfilteredArray = array_merge(
+ $filteredArray,
+ [
+ 'foo' => 'bar',
+ ]
+ );
+
+ /** @var BaseInputFilter $baseInputFilter */
+ $baseInputFilter = (new BaseInputFilter())
+ ->add(new Input(), 'bar')
+ ->setData($unfilteredArray);
+
+ self::assertSame($unfilteredArray, $baseInputFilter->getUnfilteredData());
+ self::assertSame($filteredArray, $baseInputFilter->getValues());
+ self::assertSame($filteredArray, $baseInputFilter->getRawValues());
+ }
+
public function addMethodArgumentsProvider()
{
$inputTypes = $this->inputProvider();
diff --git a/test/CollectionInputFilterTest.php b/test/CollectionInputFilterTest.php
index e09a6e12..5b7ad186 100644
--- a/test/CollectionInputFilterTest.php
+++ b/test/CollectionInputFilterTest.php
@@ -765,4 +765,35 @@ public function testUsesMessageFromComposedNotEmptyValidatorWhenRequiredButColle
[NotEmpty::IS_EMPTY => $message],
], $this->inputFilter->getMessages());
}
+
+ public function testSetDataUsingSetDataAndRunningIsValidReturningSameAsOriginalForUnfilteredData()
+ {
+ $filteredArray = [
+ [
+ 'bar' => 'foo',
+ 'foo' => 'bar',
+ ],
+ ];
+
+ $unfilteredArray = array_merge(
+ $filteredArray,
+ [
+ [
+ 'foo' => 'bar',
+ ],
+ ]
+ );
+
+ /** @var BaseInputFilter $baseInputFilter */
+ $baseInputFilter = (new BaseInputFilter())
+ ->add(new Input(), 'bar');
+
+ /** @var CollectionInputFilter $collectionInputFilter */
+ $collectionInputFilter = (new CollectionInputFilter())->setInputFilter($baseInputFilter);
+ $collectionInputFilter->setData($unfilteredArray);
+
+ $collectionInputFilter->isValid();
+
+ self::assertSame($unfilteredArray, $collectionInputFilter->getUnfilteredData());
+ }
}