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

Commit 25cd01e

Browse files
committed
Merge branch 'hotfix/24'
Close #24 Fixes #16
2 parents 49e0d38 + ddd7fa5 commit 25cd01e

File tree

2 files changed

+97
-74
lines changed

2 files changed

+97
-74
lines changed

src/BaseInputFilter.php

+2-7
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

+95-67
Original file line numberDiff line numberDiff line change
@@ -435,44 +435,82 @@ public function testCanGetValidationMessages()
435435
}
436436
}
437437

438-
/**
439-
* Idea for this one is that one input may only need to be validated if another input is present.
440-
*
441-
* Commenting out for now, as validation context may make this irrelevant, and unsure what API to expose.
442-
public function testCanConditionallyInvokeValidators()
438+
/*
439+
* Idea for this one is that validation may need to rely on context -- e.g., a "password confirmation"
440+
* field may need to know what the original password entered was in order to compare.
441+
*/
442+
443+
public function contextProvider()
443444
{
444-
$this->markTestIncomplete();
445+
$data = ['fooInput' => 'fooValue'];
446+
$arrayAccessData = new ArrayObject(['fooInput' => 'fooValue']);
447+
$expectedFromData = ['fooInput' => 'fooValue'];
448+
449+
return [
450+
// Description => [$data, $customContext, $expectedContext]
451+
'by default get context from data (array)' => [$data, null, $expectedFromData],
452+
'by default get context from data (ArrayAccess)' => [$arrayAccessData, null, $expectedFromData],
453+
'use custom context' => [[], 'fooContext', 'fooContext'],
454+
];
445455
}
446-
*/
447456

448457
/**
449-
* Idea for this one is that validation may need to rely on context -- e.g., a "password confirmation"
450-
* field may need to know what the original password entered was in order to compare.
458+
* @dataProvider contextProvider
451459
*/
452-
public function testValidationCanUseContext()
460+
public function testValidationContext($data, $customContext, $expectedContext)
453461
{
454462
$filter = new InputFilter();
455463

456-
$store = new stdClass;
457-
$foo = new Input();
458-
$foo->getValidatorChain()->attach(new Validator\Callback(function ($value, $context) use ($store) {
459-
$store->value = $value;
460-
$store->context = $context;
461-
return true;
462-
}));
464+
$input = $this->createInputInterfaceMock(true, true, $expectedContext);
465+
$filter->add($input, 'fooInput');
463466

464-
$bar = new Input();
465-
$bar->getValidatorChain()->attach(new Validator\Digits());
467+
$filter->setData($data);
466468

467-
$filter->add($foo, 'foo')
468-
->add($bar, 'bar');
469+
$this->assertTrue(
470+
$filter->isValid($customContext),
471+
'isValid() value not match. Detail: ' . json_encode($filter->getMessages())
472+
);
473+
}
474+
475+
public function testBuildValidationContextUsingInputGetRawValue()
476+
{
477+
$data = [];
478+
$expectedContext = ['fooInput' => 'fooRawValue'];
479+
$filter = new InputFilter();
480+
481+
$input = $this->createInputInterfaceMock(true, true, $expectedContext, 'fooRawValue');
482+
$filter->add($input, 'fooInput');
469483

470-
$data = ['foo' => 'foo', 'bar' => 123];
471484
$filter->setData($data);
472485

473-
$this->assertTrue($filter->isValid());
474-
$this->assertEquals('foo', $store->value);
475-
$this->assertEquals($data, $store->context);
486+
$this->assertTrue(
487+
$filter->isValid(),
488+
'isValid() value not match. Detail: ' . json_encode($filter->getMessages())
489+
);
490+
}
491+
492+
public function testContextIsTheSameWhenARequiredInputIsGivenAndOptionalInputIsMissing()
493+
{
494+
$data = [
495+
'inputRequired' => 'inputRequiredValue',
496+
];
497+
$expectedContext = [
498+
'inputRequired' => 'inputRequiredValue',
499+
'inputOptional' => null,
500+
];
501+
$inputRequired = $this->createInputInterfaceMock(true, true, $expectedContext);
502+
$inputOptional = $this->createInputInterfaceMock(false);
503+
504+
$filter = new InputFilter();
505+
$filter->add($inputRequired, 'inputRequired');
506+
$filter->add($inputOptional, 'inputOptional');
507+
508+
$filter->setData($data);
509+
510+
$this->assertTrue(
511+
$filter->isValid(),
512+
'isValid() value not match. Detail: ' . json_encode($filter->getMessages())
513+
);
476514
}
477515

478516
/**
@@ -640,48 +678,6 @@ public function testValidationMarksInputInvalidWhenRequiredAndAllowEmptyFlagIsFa
640678
$this->assertFalse($filter->isValid());
641679
}
642680

643-
public static function contextDataProvider()
644-
{
645-
return [
646-
['', 'y', true],
647-
['', 'n', false],
648-
];
649-
}
650-
651-
/**
652-
* Idea here is that an empty field may or may not be valid based on
653-
* context.
654-
*/
655-
/**
656-
* @dataProvider contextDataProvider()
657-
*/
658-
// @codingStandardsIgnoreStart
659-
public function testValidationMarksInputValidWhenAllowEmptyFlagIsTrueAndContinueIfEmptyIsTrueAndContextValidatesEmptyField($allowEmpty, $blankIsValid, $valid)
660-
{
661-
// @codingStandardsIgnoreEnd
662-
$filter = new InputFilter();
663-
664-
$data = [
665-
'allowEmpty' => $allowEmpty,
666-
'blankIsValid' => $blankIsValid,
667-
];
668-
669-
$allowEmpty = new Input();
670-
$allowEmpty->setAllowEmpty(true)
671-
->setContinueIfEmpty(true);
672-
673-
$blankIsValid = new Input();
674-
$blankIsValid->getValidatorChain()->attach(new Validator\Callback(function ($value, $context) {
675-
return ('y' === $value && empty($context['allowEmpty']));
676-
}));
677-
678-
$filter->add($allowEmpty, 'allowEmpty')
679-
->add($blankIsValid, 'blankIsValid');
680-
$filter->setData($data);
681-
682-
$this->assertSame($valid, $filter->isValid());
683-
}
684-
685681
public function testCanRetrieveRawValuesIndividuallyWithoutValidating()
686682
{
687683
if (!extension_loaded('intl')) {
@@ -1051,4 +1047,36 @@ public function testAllowsValidatingArrayAccessData()
10511047
$filter->setData($data);
10521048
$this->assertTrue($filter->isValid());
10531049
}
1050+
1051+
/**
1052+
* @param null|bool $isValid
1053+
* @param mixed $expectedContext
1054+
* @param mixed $getRawValue
1055+
*
1056+
* @return MockObject|InputInterface
1057+
*/
1058+
protected function createInputInterfaceMock($isRequired, $isValid = null, $expectedContext = 'not-set', $getRawValue = 'not-set')
1059+
{
1060+
/** @var InputInterface|MockObject $input */
1061+
$input = $this->getMock(InputInterface::class);
1062+
$input->method('isRequired')
1063+
->willReturn($isRequired)
1064+
;
1065+
if ($getRawValue !== 'not-set') {
1066+
$input->method('getRawValue')
1067+
->willReturn($getRawValue)
1068+
;
1069+
}
1070+
if ($isValid !== null) {
1071+
$mockMethod = $input->expects($this->once())
1072+
->method('isValid')
1073+
->willReturn($isValid)
1074+
;
1075+
if ($expectedContext !== 'not-set') {
1076+
$mockMethod->with($expectedContext);
1077+
}
1078+
}
1079+
1080+
return $input;
1081+
}
10541082
}

0 commit comments

Comments
 (0)