From 1f97edc3d02918fd145b34b4b5d192235635996f Mon Sep 17 00:00:00 2001 From: Albert221 Date: Sat, 16 Dec 2017 16:27:57 +0100 Subject: [PATCH 1/4] Use symfony/property-access for accessing $data in ->validate() --- composer.json | 2 +- src/Validator.php | 15 ++++++++++++++- tests/EverythingTest.php | 7 +++---- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/composer.json b/composer.json index acf4934..b24d0e0 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ "minimum-stability": "stable", "require": { "php": ">=7.0", - "psr/http-message": "~1.0" + "symfony/property-access": "^4.0" }, "require-dev": { "phpunit/phpunit": "^6.0", diff --git a/src/Validator.php b/src/Validator.php index 269e090..3384e60 100644 --- a/src/Validator.php +++ b/src/Validator.php @@ -5,6 +5,10 @@ namespace Albert221\Validation; use InvalidArgumentException; +use RuntimeException; +use Symfony\Component\PropertyAccess\Exception\AccessException; +use Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException; +use Symfony\Component\PropertyAccess\PropertyAccess; class Validator { @@ -77,9 +81,18 @@ public function addField(string $name): Field */ public function validate($data): VerdictList { + $propertyAccessor = PropertyAccess::createPropertyAccessor(); + $verdicts = []; foreach ($this->fields as $field) { - $value = $data[$field->getName()] ?? null; + try { + $value = $propertyAccessor->getValue( + $data, + is_array($data) ? "[" . $field->getName() . "]" : $field->getName() + ); + } catch (RuntimeException $e) { + $value = null; + } foreach ($field->getRules() as $rule) { $verdicts[] = $rule->verdict($value); diff --git a/tests/EverythingTest.php b/tests/EverythingTest.php index 7df366b..5bb381e 100644 --- a/tests/EverythingTest.php +++ b/tests/EverythingTest.php @@ -46,7 +46,7 @@ public function setUp() */ public function testEverything(bool $shouldBeValid, array $data) { - $valid = Validator::build() + $verdicts = Validator::build() ->addField('username') ->addRule(Rule\Required::class) // ->addRule(Rule\Length::class, ['min' => 4]) @@ -70,10 +70,9 @@ public function testEverything(bool $shouldBeValid, array $data) ->addField('confirm_password') ->addRule(Rule\Required::class) // ->addRule(Rule\SameAs::class, ['field' => 'password']) - ->validate($data) - ->passes(); + ->validate($data); - $this->assertEquals($shouldBeValid, $valid); + $this->assertEquals($shouldBeValid, $verdicts->passes()); } /** From 326badbd459593d67bc61a67ef5a062b3eda64a6 Mon Sep 17 00:00:00 2001 From: Albert221 Date: Sat, 16 Dec 2017 16:55:55 +0100 Subject: [PATCH 2/4] Use lower version of property-access to address PHP7.0 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index b24d0e0..0004ebb 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ "minimum-stability": "stable", "require": { "php": ">=7.0", - "symfony/property-access": "^4.0" + "symfony/property-access": "^3.4" }, "require-dev": { "phpunit/phpunit": "^6.0", From 32b09241e777a828706c900725f5fe9b2e3812c6 Mon Sep 17 00:00:00 2001 From: Albert221 Date: Sat, 16 Dec 2017 19:02:17 +0100 Subject: [PATCH 3/4] Split Rule to Rule and RuleValidator --- src/Rule/Required.php | 14 ----------- src/Rule/RequiredValidator.php | 23 +++++++++++++++++++ src/Rule/Rule.php | 22 ++++++++---------- src/Rule/RuleValidator.php | 18 +++++++++++++++ src/RuleValidatorFactory.php | 23 +++++++++++++++++++ src/Validator.php | 20 +++++++++++++--- tests/TestValidateRuleValidator.php | 18 +++++++++++++++ ...atorTest.php => ValidatorTestValidate.php} | 18 ++++----------- 8 files changed, 112 insertions(+), 44 deletions(-) create mode 100644 src/Rule/RequiredValidator.php create mode 100644 src/Rule/RuleValidator.php create mode 100644 src/RuleValidatorFactory.php create mode 100644 tests/TestValidateRuleValidator.php rename tests/{ValidatorTest.php => ValidatorTestValidate.php} (82%) diff --git a/src/Rule/Required.php b/src/Rule/Required.php index 3dcd65b..2804e68 100644 --- a/src/Rule/Required.php +++ b/src/Rule/Required.php @@ -13,18 +13,4 @@ class Required extends Rule { protected $message = 'This field is required.'; - - /** - * {@inheritdoc} - */ - public function verdict($value): VerdictInterface - { - $passes = false; - - if (null !== $value) { - $passes = true; - } - - return Verdict::create($passes, $this); - } } diff --git a/src/Rule/RequiredValidator.php b/src/Rule/RequiredValidator.php new file mode 100644 index 0000000..f4a4349 --- /dev/null +++ b/src/Rule/RequiredValidator.php @@ -0,0 +1,23 @@ +validator = $validator; } - public function getField(): Field - { - return $this->field; - } - /** - * @return string + * @return Field */ - public function getFieldName(): string + public function getField(): Field { - return $this->field->getName(); + return $this->field; } /** @@ -102,11 +97,12 @@ public function setMessage(string $message) } /** - * @param $value - * - * @return VerdictInterface + * @return string */ - abstract public function verdict($value): VerdictInterface; + public function validatedBy(): string + { + return get_class($this) . 'Validator'; + } // // Methods taken from Field and ValidatorBuilder for easy methods chaining. diff --git a/src/Rule/RuleValidator.php b/src/Rule/RuleValidator.php new file mode 100644 index 0000000..1376abd --- /dev/null +++ b/src/Rule/RuleValidator.php @@ -0,0 +1,18 @@ +validatedBy(); + + return new $validatorName(); + } +} diff --git a/src/Validator.php b/src/Validator.php index 3384e60..83059bd 100644 --- a/src/Validator.php +++ b/src/Validator.php @@ -4,14 +4,18 @@ namespace Albert221\Validation; +use Albert221\Validation\Rule\Validator\RuleValidator; use InvalidArgumentException; use RuntimeException; -use Symfony\Component\PropertyAccess\Exception\AccessException; -use Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException; use Symfony\Component\PropertyAccess\PropertyAccess; class Validator { + /** + * @var RuleValidatorFactory + */ + private $ruleValidatorFactory; + /** * @var Field[] */ @@ -25,6 +29,14 @@ public static function build() return new self(); } + /** + * Validator constructor. + */ + public function __construct() + { + $this->ruleValidatorFactory = new RuleValidatorFactory(); + } + /** * @return Field[] */ @@ -95,7 +107,9 @@ public function validate($data): VerdictList } foreach ($field->getRules() as $rule) { - $verdicts[] = $rule->verdict($value); + $ruleValidator = $this->ruleValidatorFactory->getInstance($rule); + + $verdicts[] = $ruleValidator->verdict($value, $rule); } } diff --git a/tests/TestValidateRuleValidator.php b/tests/TestValidateRuleValidator.php new file mode 100644 index 0000000..9345449 --- /dev/null +++ b/tests/TestValidateRuleValidator.php @@ -0,0 +1,18 @@ +createMock(Field::class)) extends Rule { - public $verdict = false; - - public function verdict($value): VerdictInterface + public function validatedBy(): string { - $this->verdict = true; - return new class implements VerdictInterface { - public function getField(): Field - { - } - - public function passes(): bool - { - } - }; + return TestValidateRuleValidator::class; } }; @@ -95,7 +85,7 @@ public function passes(): bool ->validate([]); // Assert that verdict method was called on rules. - $this->assertTrue($rule->verdict); + $this->assertTrue(TestValidateRuleValidator::$called); $this->assertInstanceOf(VerdictList::class, $verdicts); } } From efb6f9160a2c7dc2f18bb4568f4acd4d81016f61 Mon Sep 17 00:00:00 2001 From: Albert221 Date: Sun, 17 Dec 2017 18:56:52 +0100 Subject: [PATCH 4/4] Add some tests --- tests/VerdictListTest.php | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/VerdictListTest.php b/tests/VerdictListTest.php index 81c5277..ae6cfb8 100644 --- a/tests/VerdictListTest.php +++ b/tests/VerdictListTest.php @@ -38,6 +38,38 @@ public function testFails() $this->assertTrue($list->fails()); } + public function testToArray() + { + $verdictList = new VerdictList([ + $this->getPassingVerdict() + ]); + + $this->assertInternalType('array', $verdictList->toArray()); + } + + public function testCount() + { + $verdictList = new VerdictList([ + $this->getPassingVerdict(), + $this->getPassingVerdict(), + $this->getFailingVerdict() + ]); + + $this->assertEquals(3, $verdictList->count()); + } + + public function testGetIterator() + { + $firstVerdict = $this->getPassingVerdict(); + + $verdictList = new VerdictList([ + $firstVerdict, + $this->getPassingVerdict() + ]); + + $this->assertEquals($firstVerdict, $verdictList->getIterator()->getArrayCopy()[0]); + } + /** * @return VerdictInterface */