@@ -37,7 +37,8 @@ |
||
| 37 | 37 | parent::setUp(); |
| 38 | 38 | |
| 39 | 39 | $this->container->bindSingleton(ReaderInterface::class, (new Factory())->create()); |
| 40 | - $this->container->bindSingleton(SchemaProviderInterface::class, static function (FactoryInterface $factory) { |
|
| 40 | + $this->container->bindSingleton(SchemaProviderInterface::class, static function (FactoryInterface $factory) |
|
| 41 | + { |
|
| 41 | 42 | return $factory->make(SchemaProvider::class, [ |
| 42 | 43 | 'readers' => [ |
| 43 | 44 | $factory->make(AttributeReader::class), |
@@ -18,7 +18,8 @@ |
||
| 18 | 18 | $errors = array_merge($core->callAction($controller, $action, $parameters), $parameters['errors'] ?? []); |
| 19 | 19 | $errorMapper = new ErrorMapper($parameters['schema']); |
| 20 | 20 | |
| 21 | - if ($errors !== []) { |
|
| 21 | + if ($errors !== []) |
|
| 22 | + { |
|
| 22 | 23 | throw new ValidationException( |
| 23 | 24 | $errorMapper->mapErrors($errors), |
| 24 | 25 | $parameters['context'] ?? null |
@@ -29,9 +29,11 @@ |
||
| 29 | 29 | |
| 30 | 30 | private function validateFilter(FilterInterface $filter, array $data, mixed $context = null): array |
| 31 | 31 | { |
| 32 | - if ($filter instanceof HasFilterDefinition) { |
|
| 32 | + if ($filter instanceof HasFilterDefinition) |
|
| 33 | + { |
|
| 33 | 34 | $definition = $filter->filterDefinition(); |
| 34 | - if ($definition instanceof ShouldBeValidated) { |
|
| 35 | + if ($definition instanceof ShouldBeValidated) |
|
| 36 | + { |
|
| 35 | 37 | /** @var ValidationProviderInterface $validationProvider */ |
| 36 | 38 | $validationProvider = $this->container->get(ValidationProviderInterface::class); |
| 37 | 39 | |
@@ -42,18 +42,22 @@ discard block |
||
| 42 | 42 | */ |
| 43 | 43 | public function makeSchema(string $name, array $schema): array |
| 44 | 44 | { |
| 45 | - if (empty($schema)) { |
|
| 45 | + if (empty($schema)) |
|
| 46 | + { |
|
| 46 | 47 | throw new SchemaException(\sprintf('Filter `%s` does not define any schema', $name)); |
| 47 | 48 | } |
| 48 | 49 | |
| 49 | 50 | $result = []; |
| 50 | - foreach ($schema as $field => $definition) { |
|
| 51 | + foreach ($schema as $field => $definition) |
|
| 52 | + { |
|
| 51 | 53 | $optional = false; |
| 52 | 54 | |
| 53 | 55 | // short definition |
| 54 | - if (\is_string($definition)) { |
|
| 56 | + if (\is_string($definition)) |
|
| 57 | + { |
|
| 55 | 58 | // simple scalar field definition |
| 56 | - if (!\class_exists($definition)) { |
|
| 59 | + if (!\class_exists($definition)) |
|
| 60 | + { |
|
| 57 | 61 | [$source, $origin] = $this->parseDefinition($field, $definition); |
| 58 | 62 | $result[$field] = [ |
| 59 | 63 | self::SCHEMA_SOURCE => $source, |
@@ -74,25 +78,30 @@ discard block |
||
| 74 | 78 | continue; |
| 75 | 79 | } |
| 76 | 80 | |
| 77 | - if (!\is_array($definition) || $definition === []) { |
|
| 81 | + if (!\is_array($definition) || $definition === []) |
|
| 82 | + { |
|
| 78 | 83 | throw new SchemaException( |
| 79 | 84 | \sprintf('Invalid schema definition at `%s`->`%s`', $name, $field) |
| 80 | 85 | ); |
| 81 | 86 | } |
| 82 | 87 | |
| 83 | 88 | // complex definition |
| 84 | - if (!empty($definition[self::ORIGIN])) { |
|
| 89 | + if (!empty($definition[self::ORIGIN])) |
|
| 90 | + { |
|
| 85 | 91 | $origin = $definition[self::ORIGIN]; |
| 86 | 92 | |
| 87 | 93 | // [class, 'data:something.*'] vs [class, 'data:something'] |
| 88 | 94 | $iterate = \str_contains((string)$origin, '.*') || !empty($definition[self::ITERATE]); |
| 89 | 95 | $origin = \rtrim($origin, '.*'); |
| 90 | - } else { |
|
| 96 | + } |
|
| 97 | + else |
|
| 98 | + { |
|
| 91 | 99 | $origin = $field; |
| 92 | 100 | $iterate = true; |
| 93 | 101 | } |
| 94 | 102 | |
| 95 | - if (!empty($definition[self::OPTIONAL])) { |
|
| 103 | + if (!empty($definition[self::OPTIONAL])) |
|
| 104 | + { |
|
| 96 | 105 | $optional = true; |
| 97 | 106 | } |
| 98 | 107 | |
@@ -105,7 +114,8 @@ discard block |
||
| 105 | 114 | self::SCHEMA_OPTIONAL => $optional, |
| 106 | 115 | ]; |
| 107 | 116 | |
| 108 | - if ($iterate) { |
|
| 117 | + if ($iterate) |
|
| 118 | + { |
|
| 109 | 119 | [$source, $origin] = $this->parseDefinition($field, $definition[self::ITERATE] ?? $origin); |
| 110 | 120 | |
| 111 | 121 | $map[self::SCHEMA_ITERATE_SOURCE] = $source; |
@@ -137,11 +147,13 @@ discard block |
||
| 137 | 147 | 'path', |
| 138 | 148 | 'remoteAddress', |
| 139 | 149 | 'uri' |
| 140 | - ], true)) { |
|
| 150 | + ], true)) |
|
| 151 | + { |
|
| 141 | 152 | return [$definition, $field]; |
| 142 | 153 | } |
| 143 | 154 | |
| 144 | - if (!\str_contains($definition, ':')) { |
|
| 155 | + if (!\str_contains($definition, ':')) |
|
| 156 | + { |
|
| 145 | 157 | return ['data', empty($definition) ? $field : $definition]; |
| 146 | 158 | } |
| 147 | 159 | |
@@ -27,17 +27,23 @@ discard block |
||
| 27 | 27 | $errors = []; |
| 28 | 28 | $result = $this->mapData($mappingSchema, $input, $setters); |
| 29 | 29 | |
| 30 | - foreach ($mappingSchema as $field => $map) { |
|
| 31 | - if (empty($map[Builder::SCHEMA_FILTER])) { |
|
| 30 | + foreach ($mappingSchema as $field => $map) |
|
| 31 | + { |
|
| 32 | + if (empty($map[Builder::SCHEMA_FILTER])) |
|
| 33 | + { |
|
| 32 | 34 | continue; |
| 33 | 35 | } |
| 34 | 36 | |
| 35 | 37 | $nested = $map[Builder::SCHEMA_FILTER]; |
| 36 | - if (empty($map[Builder::SCHEMA_ARRAY])) { |
|
| 38 | + if (empty($map[Builder::SCHEMA_ARRAY])) |
|
| 39 | + { |
|
| 37 | 40 | // slicing down |
| 38 | - try { |
|
| 41 | + try |
|
| 42 | + { |
|
| 39 | 43 | $result[$field] = $this->provider->createFilter($nested, $input->withPrefix($map[Builder::SCHEMA_ORIGIN])); |
| 40 | - } catch (ValidationException $e) { |
|
| 44 | + } |
|
| 45 | + catch (ValidationException $e) |
|
| 46 | + { |
|
| 41 | 47 | $errors[$field] = $e->errors; |
| 42 | 48 | unset($result[$field]); |
| 43 | 49 | } |
@@ -47,10 +53,14 @@ discard block |
||
| 47 | 53 | $values = []; |
| 48 | 54 | |
| 49 | 55 | // List of "key" => "location in request" |
| 50 | - foreach ($this->iterate($map, $input) as $index => $origin) { |
|
| 51 | - try { |
|
| 56 | + foreach ($this->iterate($map, $input) as $index => $origin) |
|
| 57 | + { |
|
| 58 | + try |
|
| 59 | + { |
|
| 52 | 60 | $values[$index] = $this->provider->createFilter($nested, $input->withPrefix($origin)); |
| 53 | - } catch (ValidationException $e) { |
|
| 61 | + } |
|
| 62 | + catch (ValidationException $e) |
|
| 63 | + { |
|
| 54 | 64 | $errors[$field][$index] = $e->errors; |
| 55 | 65 | } |
| 56 | 66 | } |
@@ -64,13 +74,17 @@ discard block |
||
| 64 | 74 | public function mapData(array $mappingSchema, InputInterface $input, array $setters = []): array |
| 65 | 75 | { |
| 66 | 76 | $result = []; |
| 67 | - foreach ($mappingSchema as $field => $map) { |
|
| 68 | - if (empty($map[Builder::SCHEMA_FILTER])) { |
|
| 77 | + foreach ($mappingSchema as $field => $map) |
|
| 78 | + { |
|
| 79 | + if (empty($map[Builder::SCHEMA_FILTER])) |
|
| 80 | + { |
|
| 69 | 81 | $value = $input->getValue($map[Builder::SCHEMA_SOURCE], $map[Builder::SCHEMA_ORIGIN]); |
| 70 | 82 | |
| 71 | - if ($value !== null) { |
|
| 83 | + if ($value !== null) |
|
| 84 | + { |
|
| 72 | 85 | /** @var Setter $setter */ |
| 73 | - foreach ($setters[$field] ?? [] as $setter) { |
|
| 86 | + foreach ($setters[$field] ?? [] as $setter) |
|
| 87 | + { |
|
| 74 | 88 | $value = $setter->updateValue($value); |
| 75 | 89 | } |
| 76 | 90 | |
@@ -79,7 +93,8 @@ discard block |
||
| 79 | 93 | continue; |
| 80 | 94 | } |
| 81 | 95 | |
| 82 | - if (empty($map[Builder::SCHEMA_ARRAY])) { |
|
| 96 | + if (empty($map[Builder::SCHEMA_ARRAY])) |
|
| 97 | + { |
|
| 83 | 98 | $filter = $this->filterFactory->createFilterInstance($map[Builder::SCHEMA_FILTER]); |
| 84 | 99 | $result[$field] = $this->mapData( |
| 85 | 100 | $this->schemaProvider->getSchema($filter), |
@@ -102,11 +117,13 @@ discard block |
||
| 102 | 117 | $schema[Builder::SCHEMA_ITERATE_ORIGIN] |
| 103 | 118 | ); |
| 104 | 119 | |
| 105 | - if (empty($values) || !\is_array($values)) { |
|
| 120 | + if (empty($values) || !\is_array($values)) |
|
| 121 | + { |
|
| 106 | 122 | return []; |
| 107 | 123 | } |
| 108 | 124 | |
| 109 | - foreach (\array_keys($values) as $key) { |
|
| 125 | + foreach (\array_keys($values) as $key) |
|
| 126 | + { |
|
| 110 | 127 | yield $key => $schema[Builder::SCHEMA_ORIGIN] . '.' . $key; |
| 111 | 128 | } |
| 112 | 129 | } |
@@ -33,7 +33,8 @@ discard block |
||
| 33 | 33 | |
| 34 | 34 | public function getSchema(FilterInterface $filter): array |
| 35 | 35 | { |
| 36 | - if (!isset($this->schema[$filter::class])) { |
|
| 36 | + if (!isset($this->schema[$filter::class])) |
|
| 37 | + { |
|
| 37 | 38 | $this->read($filter); |
| 38 | 39 | } |
| 39 | 40 | |
@@ -42,7 +43,8 @@ discard block |
||
| 42 | 43 | |
| 43 | 44 | public function getSetters(FilterInterface $filter): array |
| 44 | 45 | { |
| 45 | - if (!isset($this->setters[$filter::class])) { |
|
| 46 | + if (!isset($this->setters[$filter::class])) |
|
| 47 | + { |
|
| 46 | 48 | $this->read($filter); |
| 47 | 49 | } |
| 48 | 50 | |
@@ -53,7 +55,8 @@ discard block |
||
| 53 | 55 | { |
| 54 | 56 | $this->schema[$filter::class] = []; |
| 55 | 57 | $this->setters[$filter::class] = []; |
| 56 | - foreach ($this->readers as $reader) { |
|
| 58 | + foreach ($this->readers as $reader) |
|
| 59 | + { |
|
| 57 | 60 | [$readSchema, $readSetters] = $reader->read($filter); |
| 58 | 61 | $this->schema[$filter::class] = \array_merge($this->schema[$filter::class], $readSchema); |
| 59 | 62 | $this->setters[$filter::class] = \array_merge($this->setters[$filter::class], $readSetters); |
@@ -33,15 +33,22 @@ |
||
| 33 | 33 | $setters = []; |
| 34 | 34 | $class = new \ReflectionClass($filter); |
| 35 | 35 | |
| 36 | - foreach ($class->getProperties() as $property) { |
|
| 36 | + foreach ($class->getProperties() as $property) |
|
| 37 | + { |
|
| 37 | 38 | /** @var object $attribute */ |
| 38 | - foreach ($this->reader->getPropertyMetadata($property) as $attribute) { |
|
| 39 | - if ($attribute instanceof AbstractInput || $attribute instanceof NestedFilter) { |
|
| 39 | + foreach ($this->reader->getPropertyMetadata($property) as $attribute) |
|
| 40 | + { |
|
| 41 | + if ($attribute instanceof AbstractInput || $attribute instanceof NestedFilter) |
|
| 42 | + { |
|
| 40 | 43 | $schema[$property->getName()] = $attribute->getSchema($property); |
| 41 | - } elseif ($attribute instanceof NestedArray) { |
|
| 44 | + } |
|
| 45 | + elseif ($attribute instanceof NestedArray) |
|
| 46 | + { |
|
| 42 | 47 | $prefix = $attribute->input->key ?? $attribute->prefix ?? $property->getName(); |
| 43 | 48 | $schema[$property->getName()] = [$attribute->class, $prefix . '.*']; |
| 44 | - } elseif ($attribute instanceof Setter) { |
|
| 49 | + } |
|
| 50 | + elseif ($attribute instanceof Setter) |
|
| 51 | + { |
|
| 45 | 52 | $setters[$property->getName()][] = $attribute; |
| 46 | 53 | } |
| 47 | 54 | } |
@@ -11,7 +11,8 @@ |
||
| 11 | 11 | |
| 12 | 12 | public function __construct(array $setters = []) |
| 13 | 13 | { |
| 14 | - foreach ($setters as $setter) { |
|
| 14 | + foreach ($setters as $setter) |
|
| 15 | + { |
|
| 15 | 16 | $this->register($setter); |
| 16 | 17 | } |
| 17 | 18 | } |
@@ -16,7 +16,8 @@ |
||
| 16 | 16 | public function setValue(FilterInterface $filter, \ReflectionProperty $property, mixed $value): void |
| 17 | 17 | { |
| 18 | 18 | $type = $property->getType(); |
| 19 | - if ($type === null) { |
|
| 19 | + if ($type === null) |
|
| 20 | + { |
|
| 20 | 21 | return; |
| 21 | 22 | } |
| 22 | 23 | |