More Related Content Similar to Melhorando sua API com DSLs (20) More from Augusto Pascutti (20) Melhorando sua API com DSLs6. 1 <?php
2
3 use RespectValidationValidator as v;
4
5 v::stringType()
6 ->exactLength(8)
7 ->contains("-")
8 ->contains("/^[A-Z]{3}/")
9 ->contains("/[0-9]{4}$/")
10 ->assert($something);
7. 1 <?php
2
3 namespace EasyTaxiValidationRules;
4
5 use RespectValidationRules as BaseRules;
6
7 class CarPlate extends BaseRulesAllOf
8 {
9 public function __construct()
10 {
11 $this->name = 'Brazilian car plate';
12
13 parent::__construct(
14 new BaseRulesStringType(),
15 new ExactLength(8),
16 new BaseRuleContains("-")->setName('Separator'),
17 new BaseRuleContains("/^[A-Z]{3}/")->setName("Prefix")
18 new BaseRuleContains("/^[0-9]{4}/")->setName("Sufix")
19 );
20 }
21 }
8. 1 <?php
2
3 namespace EasyTaxiValidationRules;
4
5 use RespectValidationRules as BaseRules;
6
7 class CarPlate extends BaseRulesAllOf
8 {
9 public function __construct()
10 {
11 $this->name = 'Brazilian car plate';
12
13 parent::__construct(
14 new BaseRulesStringType(),
15 new ExactLength(8),
16 new BaseRuleContains("-")->setName('Separator'),
17 new BaseRuleContains("/^[A-Z]{3}/")->setName("Prefix")
18 new BaseRuleContains("/^[0-9]{4}/")->setName("Sufix")
19 );
20 }
21 }
9. 1 <?php
2
3 // ... dentro de algum método de um Controller ...
4
5 ValidationValidator::arrayType()
6 ->key('driver_name', v::driverName())
7 ->key('driver_birthdate', v::minimumAge(18))
8 ->key(
9 'driver_car', v::arrayType(
10 v::key("model", v::carModel($this->get('model.vehicle'))),
11 v::key("assembler", v::carAssembler()),
12 v::key("year", v::maximumAge(5)),
13 v::key("plate", v::carPlate())
14 )
15 )
16 ->key('license_number', v::driverLicense())
17 ->key('taxi_permission', v::taxiPermissionNumber())
18 ->key('address', v::address())
19 ->assert($_POST);
11. 1 <?php
2
3 namespace RespectValidation;
4
5 class Validator
6 {
7 public function stringType() {}
8 public function contains($search) {}
9 public function assert($mixed) {}
10 }
13. 1 <?php
2
3 namespace RespectValidation;
4
5 interface Rule
6 {
7 public function isValid($mixed): bool;
8 }
15. 1 <?php
2
3 namespace RespectValidationRules;
4
5 use RespectValidation;
6
7 class StringType implements ValidationRule
8 {
9 public function isValid($mixed): bool
10 {
11 return is_string($mixed);
12 }
13 }
16. 3 namespace RespectValidationRules;
4
5 use RespectValidation;
6
7 class AllOf implements ValidationRule
8 {
9 protected $rules = [];
10
17 public function __construct(ValidationRule ...$rules)
18 {
19 $this->rules = $rules;
20 }
21
22 public function isValid($mixed): bool
23 {
24 foreach ($this->rules as $rule) {
25 if (false === $rule->isValid($mixed)) {
26 return false;
27 }
28 }
29
30 return true;
31 }
32 }
18. 1 <?php
2
3 $factory = new RespectValidationRuleFactory;
4 $rule = $factory->createInstance('StringType');
19. 1 <?php
2
3 namespace RespectValidation;
4
5 class RuleFactory
6 {
7 public function createInstance($ruleName, array $args = []): Rule
8 {
9 $ruleNamespace = 'RespectValidationRules';
10 $className = $ruleNamespace . $rule;
11 $reflection = new ReflectionClass($className);
12
13 return $reflection->newInstanceArgs($args);
14 }
15 }
21. 1 <?php
2
3 namespace RespectValidation;
4
5 class RuleFactory
6 {
7 public function __call($methodName, $methodArguments)
8 {
9 return $this->createInstance($methodName, $methodArguments);
10 }
11
12 public function createInstance($ruleName, array $args = []): Rule
13 {
14 /* ... */
15 }
16 }
22. 1 <?php
2
3 $checkFor = new RespectValidationRuleFactory;
4
5 $isString = $checkFor->StringType();
6
7 $isTwitterUserName = $checkFor->AllOf(
8 $checkFor->AlNum(),
9 $checkFor->NoWhitespace(),
10 $checkFor->Length(1, 15)
11 );
24. 3 namespace RespectValidation;
4
5 class RuleFactory
6 {
7 private static $factory = null;
8
9 public static function getInstance()
10 {
11 if (is_null(self::$factory)) {
12 self::$factory = new static;
13 }
14
15 return self::$factory;
16 }
17
18 public static function __callStatic($methodName, $methodArguments)
19 {
20 $factory = self::getFactory();
21
22 return $factory->createInstance($methodName, $methodArguments);
23 }
24
25 /* ... */
26 }
25. 1 <?php
2
3 use RespectValidationRuleFactory as v;
4
5 $isTwitterUserName = v::AllOf(
6 v::AlNum(),
7 v::NoWhitespace(),
8 v::Length(1, 15)
9 );
29. 1 <?php
2
3 namespace EasyTaxiValidation;
4
5 interface Rule
6 {
7 public function isValid($mixed): bool;
8 }
30. 1 <?php
2
3 namespace EasyTaxiValidationRules;
4
5 use EasyTaxiValidation;
6 use RespectValidationValidator as v;
7
8 class PlateValidator implements Rule
9 {
10 public function isValid($mixed): bool
11 {
12 return v::stringType()
13 ->exactLength(8)
14 ->contains("-")
15 ->contains("/^[A-Z]{3}/")
16 ->contains("/[0-9]{4}$/")
17 ->setName('Car plate')
18 ->validate($mixed);
19 }
20 }
32. 1 <?php
2
3 namespace EasyTaxiDriver;
4
5 class Car
6 {
7 /**
8 * @PlateValidator
9 */
10 private $plate = '';
11
12 public function __construct($plate)
13 {
14 $this->plate = $plate;
15 }
16 }
33. 1 <?php
2
3 use EasyTaxiAnnotation;
4 use EasyTaxiValidation;
5
6 $filter = new AnnotationFilter();
7 $factory = new AnnotationFactory($filter);
8 $validator = new ValidationValidator($factory);
9 $fusca = new Car('AAA-1111');
10
11 $validator->annotations($fusca);
35. 1 <?php
2
3 namespace EasyTaxiAnnotation;
4
5 class Filter
6 {
7 public function firstAnnotation($doc): string {
8 foreach ($this->breakLines($doc) as $line) {
9 if (false === $this->hasAnnotation($line)) {
10 continue;
11 }
12
13 return $this->filterName($line);
14 }
15 }
16
17 private function breakLines($doc): array {
18 return explode(PHP_EOL, $doc);
19 }
20
21 private function hasAnnotation($line): bool {
22 return false !== strpos($line, '@');
23 }
24
25 private function filterName($line): string {
26 return trim(str_replace(['*', '/', '@'], '', $line));
27 }
28 }
37. 3 namespace EasyTaxiAnnotation;
4
5 class Factory
6 {
7 private $filter = null;
8
9 public function __construct(Filter $annotationFilter)
10 {
11 $this->filter = $annotationFilter;
12 }
13
14 public function createFromProperty($instance, $propertyName)
15 {
16 $object = new ReflectionObject($instance);
17 $property = $object->getProperty($propertyName);
18
19 return $this->createInstanceFromComment($property->getDocComment());
20 }
21
22 private function createInstanceFromComment($doc)
23 {
24 $annotationClass = $this->filter->firstAnnotation($doc);
25 $class = new ReflectionClass($annotationClass);
26
27 return $class->newInstance();
28 }
29 }
39. 3 namespace EasyTaxiValidation;
4
5 use EasyTaxiAnnotation;
6
7 class Validator
8 {
9 private $annotationFactory = null;
10
11 public function __construct(AnnotationFactory $factory) {
12 $this->annotationFactory = $factory;
13 }
14
15 public function annotations($object) {
16 $annotation = $this->annotationFactory;
17 $class = new ReflectionObject($object);
18 $properties = $class->getProperties();
19 foreach ($properties as $property) {
20 $propertyName = $property->getName();
21 $rule = $annotation->createFromProperty($object, $propertyName);
22 if ($rule->isValid($object)) {
23 continue;
24 }
25
26 throw new Exception("$propertyName is not valid.");
27 }
28 }
29 }
40. 1 <?php
2
3 use EasyTaxiAnnotation;
4 use EasyTaxiValidation;
5
6 $filter = new AnnotationFilter();
7 $factory = new AnnotationFactory($filter);
8 $validator = new ValidationValidator($factory);
9 $fusca = new Car('AAA-1111');
10
11 $validator->annotation($fusca);
61. 1 <?php
2
3 use RespectValidationValidator as v;
4
5 v::stringType()
6 ->exactLength(8)
7 ->contains("-")
8 ->contains("/^[A-Z]{3}/")
9 ->contains("/[0-9]{4}$/")
10 ->assert($something);