diff --git a/composer.json b/composer.json index acf4934..0004ebb 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": "^3.4" }, "require-dev": { "phpunit/phpunit": "^6.0", 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 269e090..83059bd 100644 --- a/src/Validator.php +++ b/src/Validator.php @@ -4,10 +4,18 @@ namespace Albert221\Validation; +use Albert221\Validation\Rule\Validator\RuleValidator; use InvalidArgumentException; +use RuntimeException; +use Symfony\Component\PropertyAccess\PropertyAccess; class Validator { + /** + * @var RuleValidatorFactory + */ + private $ruleValidatorFactory; + /** * @var Field[] */ @@ -21,6 +29,14 @@ public static function build() return new self(); } + /** + * Validator constructor. + */ + public function __construct() + { + $this->ruleValidatorFactory = new RuleValidatorFactory(); + } + /** * @return Field[] */ @@ -77,12 +93,23 @@ 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); + $ruleValidator = $this->ruleValidatorFactory->getInstance($rule); + + $verdicts[] = $ruleValidator->verdict($value, $rule); } } 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()); } /** 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); } } 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 */