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

Commit e06ffa9

Browse files
committed
Fix loop validation input context is mutable.
Fix #16
1 parent 651e553 commit e06ffa9

File tree

2 files changed

+109
-8
lines changed

2 files changed

+109
-8
lines changed

src/BaseInputFilter.php

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,8 @@ public function isValid($context = null)
231231
*/
232232
protected function validateInputs(array $inputs, $data = [], $context = null)
233233
{
234+
$inputContext = $context ?: (array_merge($this->getRawValues(), (array) $data));
235+
234236
$this->validInputs = [];
235237
$this->invalidInputs = [];
236238
$valid = true;
@@ -261,14 +263,7 @@ protected function validateInputs(array $inputs, $data = [], $context = null)
261263
continue;
262264
}
263265

264-
// Make sure we have a value (empty) for validation of context
265-
if (!array_key_exists($name, $data)) {
266-
$data[$name] = null;
267-
}
268-
269266
// Validate an input
270-
$inputContext = $context ?: $data;
271-
272267
if (!$input->isValid($inputContext)) {
273268
// Validation failure
274269
$this->invalidInputs[$name] = $input;

test/BaseInputFilterTest.php

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,10 +445,84 @@ public function testCanConditionallyInvokeValidators()
445445
}
446446
*/
447447

448-
/**
448+
/*
449449
* Idea for this one is that validation may need to rely on context -- e.g., a "password confirmation"
450450
* field may need to know what the original password entered was in order to compare.
451451
*/
452+
453+
public function contextProvider()
454+
{
455+
$data = ['fooInput' => 'fooValue'];
456+
$arrayAccessData = new ArrayObject(['fooInput' => 'fooValue']);
457+
$expectedFromData = ['fooInput' => 'fooValue'];
458+
459+
return [
460+
// Description => [$data, $customContext, $expectedContext]
461+
'by default get context from data (array)' => [$data, null, $expectedFromData],
462+
'by default get context from data (ArrayAccess)' => [$arrayAccessData, null, $expectedFromData],
463+
'use custom context' => [[], 'fooContext', 'fooContext'],
464+
];
465+
}
466+
467+
/**
468+
* @dataProvider contextProvider
469+
*/
470+
public function testValidationContext($data, $customContext, $expectedContext)
471+
{
472+
$filter = new InputFilter();
473+
474+
$input = $this->createInputInterfaceMock(true, true, $expectedContext);
475+
$filter->add($input, 'fooInput');
476+
477+
$filter->setData($data);
478+
479+
$this->assertTrue(
480+
$filter->isValid($customContext),
481+
'isValid() value not match. Detail: ' . json_encode($filter->getMessages())
482+
);
483+
}
484+
485+
public function testBuildValidationContextUsingInputGetRawValue()
486+
{
487+
$data = [];
488+
$expectedContext = ['fooInput' => 'fooRawValue'];
489+
$filter = new InputFilter();
490+
491+
$input = $this->createInputInterfaceMock(true, true, $expectedContext, 'fooRawValue');
492+
$filter->add($input, 'fooInput');
493+
494+
$filter->setData($data);
495+
496+
$this->assertTrue(
497+
$filter->isValid(),
498+
'isValid() value not match. Detail: ' . json_encode($filter->getMessages())
499+
);
500+
}
501+
502+
public function testContextIsTheSameWhenARequiredInputIsGivenAndOptionalInputIsMissing()
503+
{
504+
$data = [
505+
'inputRequired' => 'inputRequiredValue',
506+
];
507+
$expectedContext = [
508+
'inputRequired' => 'inputRequiredValue',
509+
'inputOptional' => null,
510+
];
511+
$inputRequired = $this->createInputInterfaceMock(true, true, $expectedContext);
512+
$inputOptional = $this->createInputInterfaceMock(false);
513+
514+
$filter = new InputFilter();
515+
$filter->add($inputRequired, 'inputRequired');
516+
$filter->add($inputOptional, 'inputOptional');
517+
518+
$filter->setData($data);
519+
520+
$this->assertTrue(
521+
$filter->isValid(),
522+
'isValid() value not match. Detail: ' . json_encode($filter->getMessages())
523+
);
524+
}
525+
452526
public function testValidationCanUseContext()
453527
{
454528
$filter = new InputFilter();
@@ -1051,4 +1125,36 @@ public function testAllowsValidatingArrayAccessData()
10511125
$filter->setData($data);
10521126
$this->assertTrue($filter->isValid());
10531127
}
1128+
1129+
/**
1130+
* @param null|bool $isValid
1131+
* @param mixed $expectedContext
1132+
* @param mixed $getRawValue
1133+
*
1134+
* @return MockObject|InputInterface
1135+
*/
1136+
protected function createInputInterfaceMock($isRequired, $isValid = null, $expectedContext = 'not-set', $getRawValue = 'not-set')
1137+
{
1138+
/** @var InputInterface|MockObject $input */
1139+
$input = $this->getMock(InputInterface::class);
1140+
$input->method('isRequired')
1141+
->willReturn($isRequired)
1142+
;
1143+
if ($getRawValue !== 'not-set') {
1144+
$input->method('getRawValue')
1145+
->willReturn($getRawValue)
1146+
;
1147+
}
1148+
if ($isValid !== null) {
1149+
$mockMethod = $input->expects($this->once())
1150+
->method('isValid')
1151+
->willReturn($isValid)
1152+
;
1153+
if ($expectedContext !== 'not-set') {
1154+
$mockMethod->with($expectedContext);
1155+
}
1156+
}
1157+
1158+
return $input;
1159+
}
10541160
}

0 commit comments

Comments
 (0)