-
-
Save bakura10/e35887640ef00942476c to your computer and use it in GitHub Desktop.
<?php | |
class MyInputFilter extends InputFilter | |
{ | |
public function __construct() | |
{ | |
$this->add(['name' => 'example', 'required' => false]); | |
$this->add(['name' => 'foo', 'required' => false]); | |
$this->add(['name' => 'bar', 'required' => false]); | |
} | |
} | |
$inputFilter = new MyInputFilter(); | |
$inputFilter->setData(['foo' => 'myValue', 'unknown' => 'lolzor']); | |
if ($inputFilter->isValid()) { | |
$values = $inputFilter->getValues(); | |
// Do you expect (1) ['example' => null, 'foo' => 'myValue', 'bar' => null] | |
// OR (2) : ['example' => null, 'foo' => 'myValue', 'bar' => null, 'unknown' => 'lolzor'] | |
// OR (3) : ['foo' => 'myValue'] | |
// OR (4) : ['foo' => 'myValue', 'unknown' => 'lolzor'] | |
} | |
// Currently, ZF2 does (1), I personally expect it to do (3), with getUnknown returning unknown fields |
<?php | |
public function dataProvider() | |
{ | |
return [ | |
// Validate none | |
[ | |
'validation_group' => InputCollection::VALIDATE_NONE, | |
'data' => [], | |
'result_raw_data' => [], | |
'result_filtered_data' => [], | |
'result_unknown_data' => [], | |
'is_valid' => true | |
], | |
// Validate all | |
[ | |
'validation_group' => InputCollection::VALIDATE_ALL, | |
'data' => ['email' => '[email protected]', 'first_name' => ' Michaël '], | |
'result_raw_data' => ['email' => '[email protected]', 'first_name' => ' Michaël '], | |
'result_filtered_data' => ['email' => '[email protected]', 'first_name' => 'Michaël'], | |
'result_unknown_data' => [], | |
'is_valid' => true | |
], | |
// Validate all with first_name not given | |
[ | |
'validation_group' => InputCollection::VALIDATE_ALL, | |
'data' => ['email' => '[email protected]'], | |
'result_raw_data' => ['email' => '[email protected]'], | |
'result_filtered_data' => ['email' => '[email protected]'], | |
'result_unknown_data' => [], | |
'is_valid' => true | |
], | |
// Validate all with unknown value | |
[ | |
'validation_group' => InputCollection::VALIDATE_ALL, | |
'data' => ['email' => '[email protected]', 'unknown' => 'value'], | |
'result_raw_data' => ['email' => '[email protected]'], | |
'result_filtered_data' => ['email' => '[email protected]'], | |
'result_unknown_data' => ['unknown' => 'value'], | |
'is_valid' => true | |
], | |
// Assert fails if required input is not present | |
[ | |
'validation_group' => InputCollection::VALIDATE_ALL, | |
'data' => ['first_name' => 'Michaël'], | |
'result_raw_data' => ['first_name' => 'Michaël'], | |
'result_filtered_data' => ['first_name' => 'Michaël'], | |
'result_unknown_data' => [], | |
'is_valid' => false | |
], | |
// Validate only one field (with validation group) without unknown fields | |
[ | |
'validation_group' => ['email'], | |
'data' => ['email' => '[email protected]', 'first_name' => 'Michaël'], | |
'result_raw_data' => ['email' => '[email protected]'], | |
'result_filtered_data' => ['email' => '[email protected]'], | |
'result_unknown_data' => [], | |
'is_valid' => true | |
], | |
// Validate only one field with a nested input collection | |
[ | |
'validation_group' => InputCollection::VALIDATE_ALL, | |
'data' => ['email' => '[email protected]', 'address' => ['city' => 'a']], | |
'result_raw_data' => ['email' => '[email protected]', 'address' => ['city' => 'a']], | |
'result_filtered_data' => ['email' => '[email protected]'], | |
'result_unknown_data' => [], | |
'is_valid' => false | |
], | |
// Validate two fields with a nested input collection | |
[ | |
'validation_group' => InputCollection::VALIDATE_ALL, | |
'data' => ['email' => '[email protected]', 'address' => ['city' => ' abc ']], | |
'result_raw_data' => ['email' => '[email protected]', 'address' => ['city' => ' abc ']], | |
'result_filtered_data' => ['email' => '[email protected]', 'address' => ['city' => 'abc']], | |
'result_unknown_data' => [], | |
'is_valid' => true | |
], | |
// Assert can have unknown field in nested inputs | |
[ | |
'validation_group' => InputCollection::VALIDATE_ALL, | |
'data' => ['email' => '[email protected]', 'address' => ['unknown' => 'abc']], | |
'result_raw_data' => ['email' => '[email protected]'], | |
'result_filtered_data' => ['email' => '[email protected]'], | |
'result_unknown_data' => ['address' => ['unknown' => 'abc']], | |
'is_valid' => true | |
], | |
// Assert that validation group applies to nested inputs | |
[ | |
'validation_group' => ['address' => ['city']], | |
'data' => ['email' => '[email protected]', 'address' => ['city' => ' abc ']], | |
'result_raw_data' => ['address' => ['city' => ' abc ']], | |
'result_filtered_data' => ['address' => ['city' => 'abc']], | |
'result_unknown_data' => [], | |
'is_valid' => true | |
] | |
]; | |
} | |
/** | |
* @dataProvider dataProvider | |
*/ | |
public function testBehaviour( | |
$validationGroup, | |
array $data, | |
array $resultRawData, | |
array $resultFilteredData, | |
array $resultUnknownData, | |
$isValid | |
) { | |
$inputCollection = new InputCollection(); | |
$inputCollection->setName('user'); | |
// We add one input that is required, one that is optional, and a nested input collection | |
$input1 = new Input(); | |
$input1->setName('email'); | |
$input1->setRequired(true); | |
$input2 = new Input(); | |
$input2->setName('first_name'); | |
$input2->getFilterChain()->attachByName(StringTrim::class); | |
$addressInputCollection = new InputCollection(); | |
$addressInputCollection->setName('address'); | |
$input3 = new Input(); | |
$input3->setName('city'); | |
$input3->getFilterChain()->attachByName(StringTrim::class); | |
$input3->getValidatorChain()->attachByName(StringLength::class, ['min' => 2]); | |
$addressInputCollection->addInput($input3); | |
$inputCollection->addInput($input1); | |
$inputCollection->addInput($input2); | |
$inputCollection->addInput($addressInputCollection); | |
$inputCollection->setValidationGroup($validationGroup); | |
$result = $inputCollection->runAgainst($data); | |
$this->assertEquals($isValid, $result->isValid()); | |
$this->assertEquals($resultRawData, $result->getRawData()); | |
$this->assertEquals($resultFilteredData, $result->getData()); | |
$this->assertEquals($resultUnknownData, $result->getUnknownData()); | |
} |
@bakura10 regarding PATCH, with the Restful controller's I usually do this:
public function patch($id, $data)
{
$group = array_keys($data);
$filter = $this->getInputFilter();
$filter->setValidationGroup($group);
return $this->update($id, $data);
}
And therefore reusing the actual PUT logic from the controller. This has helped me a lot, with only two drawback: the input filter must be injected into the controller (a good thing) but then holds state between the patch()
and update()
call. But well, I didn't consider that much of a waste. Furthermore, it breaks when you send more fields than defined in the input filter. But I guess you could diff it against all input filter elements.
I have updated this file with a few unit tests that show my expected behavior. Does everyone agree with that?
@juriansluiman > That is a nice trick, actually.
The only thing I wonder about is why you want to return the "unknown" data. Is there a use case for it?
Also, for the scenario "// Validate only one field (with validation group) without unknown fields": you provide a field email
and first_name
. The validation group is set to email
and the unknown fields are null. I have no real scenario for the unkown fields, but I'd rather argue that if you provide such feature, it would also return first_name
in that case.
So: $result->getUnknownData()
will return all data which didn't came through the filter. This is including input filters which are excluded from the collection by its validation group.
first_name is not an unknown field because it is indeed set in the input filter. I have few cases for unknown data but I know that this is something that was asked by a lot of people in ZF and was added to ZF2.1 iirc, so I suppose there is a use case!
So: $result->getUnknownData() will return all data which didn't came through the filter. This is including input filters which are excluded from the collection by its validation group.
That makes sense. What you mean is that, once you set a validation group, everything that DO NOT belong to the validation group (even if it has been set as an input collection element) should be considered like an unknown field?
That makes sense. What you mean is that, once you set a validation group, everything that DO NOT belong to the validation group (even if it has been set as an input collection element) should be considered like an unknown field?
Correct :)
Correct :)
👍
I think we all agree that #2 and #4 are wrong.
Regarding the checkbox, thanks that's a very good input. Actually, I think that this should be handled by Zend\Form component to validate one value for each of its fields. But when using input filter on its own, I definitely think that #3 is more logical! Actually, I'm using input filters in REST context and I was always limited by current behavior of Input Filter. You cannot actually implement any PATCHing using it.
I'll therefore based my refactor on that.