Skip to content
This repository was archived by the owner on Jan 30, 2020. It is now read-only.

Commit de0e3c9

Browse files
committed
Delegate to InputInterface::isValid when data not exists
Delegate to input isValid grant full control about the fallback value feature. This commit also consolidate Input::setFallbackValue tests
1 parent 8c35a20 commit de0e3c9

File tree

7 files changed

+224
-32
lines changed

7 files changed

+224
-32
lines changed

src/ArrayInput.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,20 @@ public function getValue()
6060
*/
6161
public function isValid($context = null)
6262
{
63+
$hasValue = $this->hasValue();
64+
$required = $this->isRequired();
65+
$hasFallback = $this->hasFallback();
66+
67+
if (! $hasValue && $required && !$hasFallback) {
68+
$this->setErrorMessage('Value is required');
69+
return false;
70+
}
71+
72+
if (! $hasValue && $required && $hasFallback) {
73+
$this->setValue($this->getFallbackValue());
74+
return true;
75+
}
76+
6377
if (!$this->continueIfEmpty() && !$this->allowEmpty()) {
6478
$this->injectNotEmptyValidator();
6579
}
@@ -74,7 +88,7 @@ public function isValid($context = null)
7488
}
7589
$result = $validator->isValid($value, $context);
7690
if (!$result) {
77-
if ($this->hasFallback()) {
91+
if ($hasFallback) {
7892
$this->setValue($this->getFallbackValue());
7993
$result = true;
8094
}

src/BaseInputFilter.php

Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -254,43 +254,13 @@ protected function validateInputs(array $inputs, $data = [], $context = null)
254254
continue;
255255
}
256256

257-
$hasFallback = ($input instanceof Input && $input->hasFallback());
258-
259257
// If input is optional (not required), and value is not set, then ignore.
260258
if (!array_key_exists($name, $data)
261259
&& !$input->isRequired()
262260
) {
263261
continue;
264262
}
265263

266-
// If the value is required, not present in the data set, and
267-
// has no fallback, validation fails.
268-
if (!array_key_exists($name, $data)
269-
&& $input->isRequired()
270-
&& !$hasFallback
271-
) {
272-
$input->setErrorMessage('Value is required');
273-
$this->invalidInputs[$name] = $input;
274-
275-
if ($input->breakOnFailure()) {
276-
return false;
277-
}
278-
279-
$valid = false;
280-
continue;
281-
}
282-
283-
// If the value is required, not present in the data set, and
284-
// has a fallback, validation passes, and we set the input
285-
// value to the fallback.
286-
if (!array_key_exists($name, $data)
287-
&& $input->isRequired()
288-
&& $hasFallback
289-
) {
290-
$input->setValue($input->getFallbackValue());
291-
continue;
292-
}
293-
294264
// Make sure we have a value (empty) for validation of context
295265
if (!array_key_exists($name, $data)) {
296266
$data[$name] = null;
@@ -545,7 +515,7 @@ protected function populate()
545515
$input->clearRawValues();
546516
}
547517

548-
if (!isset($this->data[$name])) {
518+
if (!array_key_exists($name, $this->data)) {
549519
// No value; clear value in this input
550520
if ($input instanceof InputFilterInterface) {
551521
$input->setData([]);
@@ -557,6 +527,11 @@ protected function populate()
557527
continue;
558528
}
559529

530+
if ($input instanceof Input) {
531+
$input->resetValue();
532+
continue;
533+
}
534+
560535
$input->setValue(null);
561536
continue;
562537
}

src/FileInput.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,17 @@ public function isEmptyFile($rawValue)
113113
public function isValid($context = null)
114114
{
115115
$rawValue = $this->getRawValue();
116+
$hasValue = $this->hasValue();
116117
$empty = $this->isEmptyFile($rawValue);
117118
$required = $this->isRequired();
118119
$allowEmpty = $this->allowEmpty();
119120
$continueIfEmpty = $this->continueIfEmpty();
120121

122+
if (! $hasValue && $required && ! $this->hasFallback()) {
123+
$this->setErrorMessage('Value is required');
124+
return false;
125+
}
126+
121127
if ($empty && ! $required && ! $continueIfEmpty) {
122128
return true;
123129
}

src/Input.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,11 +371,22 @@ public function merge(InputInterface $input)
371371
public function isValid($context = null)
372372
{
373373
$value = $this->getValue();
374+
$hasValue = $this->hasValue();
374375
$empty = ($value === null || $value === '' || $value === []);
375376
$required = $this->isRequired();
376377
$allowEmpty = $this->allowEmpty();
377378
$continueIfEmpty = $this->continueIfEmpty();
378379

380+
if (! $hasValue && $required && ! $this->hasFallback()) {
381+
$this->setErrorMessage('Value is required');
382+
return false;
383+
}
384+
385+
if (! $hasValue && $required && $this->hasFallback()) {
386+
$this->setValue($this->getFallbackValue());
387+
return true;
388+
}
389+
379390
if ($empty && ! $required && ! $continueIfEmpty) {
380391
return true;
381392
}

test/ArrayInputTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,4 +246,16 @@ public function testNotAllowEmptyWithFilterConvertsEmptyToNonEmptyIsValid()
246246
}));
247247
$this->assertTrue($this->input->isValid());
248248
}
249+
250+
public function fallbackValueVsIsValidProvider()
251+
{
252+
$dataSets = parent::fallbackValueVsIsValidProvider();
253+
array_walk($dataSets, function (&$set) {
254+
$set[0] = [$set[0]]; // Wrap fallback value into an array.
255+
$set[1] = [$set[1]]; // Wrap value into an array.
256+
$set[3] = [$set[3]]; // Wrap expected value into an array.
257+
});
258+
259+
return $dataSets;
260+
}
249261
}

test/FileInputTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,25 @@ public function testRequiredNotEmptyValidatorNotAddedWhenOneExists()
311311
$this->markTestSkipped('Test is not enabled in FileInputTest');
312312
}
313313

314+
public function testFallbackValueVsIsValidRules(
315+
$fallbackValue = null,
316+
$originalValue = null,
317+
$isValid = null,
318+
$expectedValue = null
319+
) {
320+
$this->markTestSkipped('Input::setFallbackValue is not implemented on FileInput');
321+
}
322+
323+
324+
public function testFallbackValueVsIsValidRulesWhenValueNotSet(
325+
$fallbackValue = null,
326+
$originalValue = null,
327+
$isValid = null,
328+
$expectedValue = null
329+
) {
330+
$this->markTestSkipped('Input::setFallbackValue is not implemented on FileInput');
331+
}
332+
314333
public function testMerge()
315334
{
316335
$value = ['tmp_name' => 'bar'];

test/InputTest.php

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@
99

1010
namespace ZendTest\InputFilter;
1111

12+
use PHPUnit_Framework_MockObject_MockObject as MockObject;
1213
use PHPUnit_Framework_TestCase as TestCase;
1314
use RuntimeException;
15+
use stdClass;
1416
use Zend\Filter;
1517
use Zend\InputFilter\Input;
1618
use Zend\Validator;
19+
use Zend\Validator\ValidatorChain;
1720

1821
class InputTest extends TestCase
1922
{
@@ -95,6 +98,78 @@ public function testContinueIfEmptyFlagIsMutable()
9598
$this->assertTrue($input->continueIfEmpty());
9699
}
97100

101+
/**
102+
* @dataProvider setValueProvider
103+
*/
104+
public function testSetFallbackValue($fallbackValue)
105+
{
106+
$input = $this->input;
107+
108+
$return = $input->setFallbackValue($fallbackValue);
109+
$this->assertSame($input, $return, 'setFallbackValue() must return it self');
110+
111+
$this->assertEquals($fallbackValue, $input->getFallbackValue(), 'getFallbackValue() value not match');
112+
$this->assertEquals(true, $input->hasFallback(), 'hasFallback() value not match');
113+
}
114+
115+
/**
116+
* @dataProvider fallbackValueVsIsValidProvider
117+
*/
118+
public function testFallbackValueVsIsValidRules($fallbackValue, $originalValue, $isValid, $expectedValue)
119+
{
120+
$input = $this->input;
121+
$input->setContinueIfEmpty(true);
122+
123+
$input->setValidatorChain($this->createValidatorChainMock($isValid));
124+
$input->setFallbackValue($fallbackValue);
125+
$input->setValue($originalValue);
126+
127+
$this->assertTrue(
128+
$input->isValid(),
129+
'isValid() should be return always true when fallback value is set. Detail: ' .
130+
json_encode($input->getMessages())
131+
);
132+
$this->assertEquals([], $input->getMessages(), 'getMessages() should be empty because the input is valid');
133+
$this->assertSame($expectedValue, $input->getRawValue(), 'getRawValue() value not match');
134+
$this->assertSame($expectedValue, $input->getValue(), 'getValue() value not match');
135+
}
136+
137+
/**
138+
* @dataProvider fallbackValueVsIsValidProvider
139+
*/
140+
public function testFallbackValueVsIsValidRulesWhenValueNotSet($fallbackValue, $originalValue, $isValid)
141+
{
142+
$expectedValue = $fallbackValue; // Should always return the fallback value
143+
144+
$input = $this->input;
145+
$input->setContinueIfEmpty(true);
146+
147+
$input->setValidatorChain($this->createValidatorChainMock($isValid));
148+
$input->setFallbackValue($fallbackValue);
149+
150+
$this->assertTrue(
151+
$input->isValid(),
152+
'isValid() should be return always true when fallback value is set. Detail: ' .
153+
json_encode($input->getMessages())
154+
);
155+
$this->assertEquals([], $input->getMessages(), 'getMessages() should be empty because the input is valid');
156+
$this->assertSame($expectedValue, $input->getRawValue(), 'getRawValue() value not match');
157+
$this->assertSame($expectedValue, $input->getValue(), 'getValue() value not match');
158+
}
159+
160+
public function testRequiredWithoutFallbackAndValueNotSetThenFail()
161+
{
162+
$input = $this->input;
163+
$input->setRequired(true);
164+
$input->setContinueIfEmpty(true);
165+
166+
$this->assertFalse(
167+
$input->isValid(),
168+
'isValid() should be return always false when no fallback value, is required, and not data is set.'
169+
);
170+
$this->assertEquals(['Value is required'], $input->getMessages(), 'getMessages() should be empty because the input is valid');
171+
}
172+
98173
public function testNotEmptyValidatorNotInjectedIfContinueIfEmptyIsTrue()
99174
{
100175
$input = new Input('foo');
@@ -883,4 +958,84 @@ public function testResetValueReturnsInputValueToDefaultValue($value)
883958
$this->assertSame($input, $return, 'resetValue() must return itself');
884959
$this->assertEquals($originalInput, $input, 'Input was not reset to the default value state');
885960
}
961+
962+
public function fallbackValueVsIsValidProvider()
963+
{
964+
$isValid = true;
965+
966+
$originalValue = 'fooValue';
967+
$fallbackValue = 'fooFallbackValue';
968+
969+
// @codingStandardsIgnoreStart
970+
return [
971+
// Description => [$inputIsRequired, $fallbackValue, $originalValue, $isValid, $expectedValue]
972+
'Input: Invalid. getValue: fallback' => [$fallbackValue, $originalValue, !$isValid, $fallbackValue],
973+
'Input: Valid. getValue: original' => [$fallbackValue, $originalValue, $isValid, $originalValue],
974+
];
975+
// @codingStandardsIgnoreEnd
976+
}
977+
978+
public function setValueProvider()
979+
{
980+
$emptyValues = $this->emptyValueProvider();
981+
$mixedValues = $this->mixedValueProvider();
982+
983+
$values = array_merge($emptyValues, $mixedValues);
984+
985+
return $values;
986+
}
987+
988+
public function emptyValueProvider()
989+
{
990+
return [
991+
// Description => [$value]
992+
'null' => [null],
993+
'""' => [''],
994+
// '"0"' => ['0'],
995+
// '0' => [0],
996+
// '0.0' => [0.0],
997+
// 'false' => [false],
998+
'[]' => [[]],
999+
];
1000+
}
1001+
1002+
public function mixedValueProvider()
1003+
{
1004+
return [
1005+
// Description => [$value]
1006+
'"0"' => ['0'],
1007+
'0' => [0],
1008+
'0.0' => [0.0],
1009+
'false' => [false],
1010+
'php' => ['php'],
1011+
'whitespace' => [' '],
1012+
'1' => [1],
1013+
'1.0' => [1.0],
1014+
'true' => [true],
1015+
'["php"]' => [['php']],
1016+
'object' => [new stdClass()],
1017+
// @codingStandardsIgnoreStart
1018+
'callable' => [function () {}],
1019+
// @codingStandardsIgnoreEnd
1020+
];
1021+
}
1022+
1023+
/**
1024+
* @param null|bool $isValid If set stub isValid method for return the argument value.
1025+
*
1026+
* @return MockObject|ValidatorChain
1027+
*/
1028+
protected function createValidatorChainMock($isValid = null)
1029+
{
1030+
/** @var ValidatorChain|MockObject $validatorChain */
1031+
$validatorChain = $this->getMock(ValidatorChain::class);
1032+
1033+
if ($isValid !== null) {
1034+
$validatorChain->method('isValid')
1035+
->willReturn($isValid)
1036+
;
1037+
}
1038+
1039+
return $validatorChain;
1040+
}
8861041
}

0 commit comments

Comments
 (0)