From 7ea600a0464c052d9b4008f1d7eb2a286f4ad6f1 Mon Sep 17 00:00:00 2001 From: Romain Canon Date: Mon, 25 Dec 2023 19:58:38 +0100 Subject: [PATCH] misc: refactor normalizer integration Better architecture for upcoming JSON normalizer --- src/Library/Container.php | 26 +++++----- src/MapperBuilder.php | 16 +++--- src/Normalizer/ArrayNormalizer.php | 49 +++++++++++++++++ src/Normalizer/Format.php | 27 ++++++++-- src/Normalizer/FormatNormalizer.php | 30 ----------- src/Normalizer/Formatter/ArrayFormatter.php | 34 ------------ .../Formatter/ArrayFormatterFactory.php | 18 ------- src/Normalizer/Formatter/Formatter.php | 23 -------- src/Normalizer/Formatter/FormatterFactory.php | 18 ------- .../RecursiveTransformer.php} | 52 ++++++++----------- 10 files changed, 113 insertions(+), 180 deletions(-) create mode 100644 src/Normalizer/ArrayNormalizer.php delete mode 100644 src/Normalizer/FormatNormalizer.php delete mode 100644 src/Normalizer/Formatter/ArrayFormatter.php delete mode 100644 src/Normalizer/Formatter/ArrayFormatterFactory.php delete mode 100644 src/Normalizer/Formatter/Formatter.php delete mode 100644 src/Normalizer/Formatter/FormatterFactory.php rename src/Normalizer/{RecursiveNormalizer.php => Transformer/RecursiveTransformer.php} (77%) diff --git a/src/Library/Container.php b/src/Library/Container.php index 46349bc2..35fda302 100644 --- a/src/Library/Container.php +++ b/src/Library/Container.php @@ -47,12 +47,11 @@ use CuyZ\Valinor\Mapper\TreeMapper; use CuyZ\Valinor\Mapper\TypeArgumentsMapper; use CuyZ\Valinor\Mapper\TypeTreeMapper; -use CuyZ\Valinor\Normalizer\FormatNormalizer; -use CuyZ\Valinor\Normalizer\Formatter\Formatter; -use CuyZ\Valinor\Normalizer\Formatter\FormatterFactory; +use CuyZ\Valinor\Normalizer\ArrayNormalizer; +use CuyZ\Valinor\Normalizer\Format; use CuyZ\Valinor\Normalizer\Normalizer; -use CuyZ\Valinor\Normalizer\RecursiveNormalizer; use CuyZ\Valinor\Normalizer\Transformer\KeyTransformersHandler; +use CuyZ\Valinor\Normalizer\Transformer\RecursiveTransformer; use CuyZ\Valinor\Normalizer\Transformer\ValueTransformersHandler; use CuyZ\Valinor\Type\ClassType; use CuyZ\Valinor\Type\Parser\Factory\LexingTypeParserFactory; @@ -184,7 +183,7 @@ public function __construct(Settings $settings) return new CacheObjectBuilderFactory($factory, $cache); }, - RecursiveNormalizer::class => fn () => new RecursiveNormalizer( + RecursiveTransformer::class => fn () => new RecursiveTransformer( $this->get(ClassDefinitionRepository::class), new ValueTransformersHandler( $this->get(FunctionDefinitionRepository::class), @@ -196,6 +195,10 @@ public function __construct(Settings $settings) array_keys($settings->transformerAttributes), ), + ArrayNormalizer::class => fn () => new ArrayNormalizer( + $this->get(RecursiveTransformer::class), + ), + ClassDefinitionRepository::class => fn () => new CacheClassDefinitionRepository( new ReflectionClassDefinitionRepository( $this->get(TypeParserFactory::class), @@ -249,17 +252,14 @@ public function argumentsMapper(): ArgumentsMapper } /** - * @template T + * @template T of Normalizer * - * @param FormatterFactory> $formatterFactory - * @return Normalizer + * @param Format $format + * @return T */ - public function normalizer(FormatterFactory $formatterFactory): Normalizer + public function normalizer(Format $format): Normalizer { - return new FormatNormalizer( - $formatterFactory, - $this->get(RecursiveNormalizer::class), - ); + return $this->get($format->type()); } public function cacheWarmupService(): RecursiveCacheWarmupService diff --git a/src/MapperBuilder.php b/src/MapperBuilder.php index d0730a00..60d48881 100644 --- a/src/MapperBuilder.php +++ b/src/MapperBuilder.php @@ -9,8 +9,7 @@ use CuyZ\Valinor\Mapper\ArgumentsMapper; use CuyZ\Valinor\Mapper\Tree\Message\ErrorMessage; use CuyZ\Valinor\Mapper\TreeMapper; -use CuyZ\Valinor\Normalizer\Formatter\Formatter; -use CuyZ\Valinor\Normalizer\Formatter\FormatterFactory; +use CuyZ\Valinor\Normalizer\Format; use CuyZ\Valinor\Normalizer\Normalizer; use Psr\SimpleCache\CacheInterface; use Throwable; @@ -552,17 +551,14 @@ public function argumentsMapper(): ArgumentsMapper } /** - * Returns a normalizer instance. To see list of available formats, check - * out: @see \CuyZ\Valinor\Normalizer\Format + * @template T of Normalizer * - * @template T - * - * @param FormatterFactory> $formatterFactory - * @return Normalizer + * @param Format $format + * @return T */ - public function normalizer(FormatterFactory $formatterFactory): Normalizer + public function normalizer(Format $format): Normalizer { - return $this->container()->normalizer($formatterFactory); + return $this->container()->normalizer($format); } public function __clone() diff --git a/src/Normalizer/ArrayNormalizer.php b/src/Normalizer/ArrayNormalizer.php new file mode 100644 index 00000000..c711e5e6 --- /dev/null +++ b/src/Normalizer/ArrayNormalizer.php @@ -0,0 +1,49 @@ +|scalar|null> + */ +final class ArrayNormalizer implements Normalizer +{ + public function __construct( + private RecursiveTransformer $transformer, + ) {} + + public function normalize(mixed $value): mixed + { + $value = $this->transformer->transform($value); + + return $this->normalizeIterator($value); + } + + /** + * @param iterable|scalar|null $value + * @return array|scalar|null + */ + private function normalizeIterator(mixed $value): mixed + { + if (is_iterable($value)) { + if (! is_array($value)) { + $value = iterator_to_array($value); + } + + // PHP8.1 First-class callable syntax + $value = array_map([$this, 'normalizeIterator'], $value); + } + + return $value; + } +} diff --git a/src/Normalizer/Format.php b/src/Normalizer/Format.php index 12f3e48c..c8c32b45 100644 --- a/src/Normalizer/Format.php +++ b/src/Normalizer/Format.php @@ -4,9 +4,11 @@ namespace CuyZ\Valinor\Normalizer; -use CuyZ\Valinor\Normalizer\Formatter\ArrayFormatterFactory; - -/** @api */ +/** + * @api + * + * @template T of Normalizer + */ final class Format { /** @@ -42,9 +44,24 @@ final class Format * // ], * // ]; * ``` + * + * @return self + */ + public static function array(): self + { + return new self(ArrayNormalizer::class); + } + + /** + * @param class-string $type + */ + private function __construct(private string $type) {} + + /** + * @return class-string */ - public static function array(): ArrayFormatterFactory + public function type(): string { - return new ArrayFormatterFactory(); + return $this->type; } } diff --git a/src/Normalizer/FormatNormalizer.php b/src/Normalizer/FormatNormalizer.php deleted file mode 100644 index 47d1f463..00000000 --- a/src/Normalizer/FormatNormalizer.php +++ /dev/null @@ -1,30 +0,0 @@ - - */ -final class FormatNormalizer implements Normalizer -{ - /** - * @param FormatterFactory> $formatterFactory - */ - public function __construct( - private FormatterFactory $formatterFactory, - private RecursiveNormalizer $recursiveNormalizer, - ) {} - - public function normalize(mixed $value): mixed - { - return $this->recursiveNormalizer->normalize($value, $this->formatterFactory->new()); - } -} diff --git a/src/Normalizer/Formatter/ArrayFormatter.php b/src/Normalizer/Formatter/ArrayFormatter.php deleted file mode 100644 index 0d9509a7..00000000 --- a/src/Normalizer/Formatter/ArrayFormatter.php +++ /dev/null @@ -1,34 +0,0 @@ -|scalar|null> - */ -final class ArrayFormatter implements Formatter -{ - /** @var iterable|scalar|null */ - private mixed $value; - - public function push(mixed $value): void - { - $this->value = $value; - } - - public function value(): mixed - { - if (is_iterable($this->value) && ! is_array($this->value)) { - $this->value = iterator_to_array($this->value); - } - - return $this->value; - } -} diff --git a/src/Normalizer/Formatter/ArrayFormatterFactory.php b/src/Normalizer/Formatter/ArrayFormatterFactory.php deleted file mode 100644 index f738e781..00000000 --- a/src/Normalizer/Formatter/ArrayFormatterFactory.php +++ /dev/null @@ -1,18 +0,0 @@ - - */ -final class ArrayFormatterFactory implements FormatterFactory -{ - public function new(): ArrayFormatter - { - return new ArrayFormatter(); - } -} diff --git a/src/Normalizer/Formatter/Formatter.php b/src/Normalizer/Formatter/Formatter.php deleted file mode 100644 index ef148a69..00000000 --- a/src/Normalizer/Formatter/Formatter.php +++ /dev/null @@ -1,23 +0,0 @@ -|scalar|null $value - */ - public function push(mixed $value): void; - - /** - * @return T - */ - public function value(): mixed; -} diff --git a/src/Normalizer/Formatter/FormatterFactory.php b/src/Normalizer/Formatter/FormatterFactory.php deleted file mode 100644 index df7f6805..00000000 --- a/src/Normalizer/Formatter/FormatterFactory.php +++ /dev/null @@ -1,18 +0,0 @@ - $formatter + * @return array|scalar|null */ - public function normalize(mixed $value, Formatter $formatter): mixed + public function transform(mixed $value): mixed { - $this->doNormalize($value, $formatter, new WeakMap()); // @phpstan-ignore-line - - return $formatter->value(); + return $this->doTransform($value, new WeakMap()); // @phpstan-ignore-line } /** - * @param Formatter $formatter * @param WeakMap $references * @param list $attributes * @return iterable|scalar|null */ - private function doNormalize(mixed $value, Formatter $formatter, WeakMap $references, array $attributes = []): mixed + private function doTransform(mixed $value, WeakMap $references, array $attributes = []): mixed { if (is_object($value)) { if (isset($references[$value])) { @@ -66,11 +62,7 @@ private function doNormalize(mixed $value, Formatter $formatter, WeakMap $refere } if ($this->transformers === [] && $this->transformerAttributes === []) { - $value = $this->defaultTransformer($value, $formatter, $references); - - $formatter->push($value); - - return $value; + return $this->defaultTransformer($value, $references); } if ($this->transformerAttributes !== [] && is_object($value)) { @@ -79,24 +71,19 @@ private function doNormalize(mixed $value, Formatter $formatter, WeakMap $refere $attributes = [...$attributes, ...$classAttributes]; } - $value = $this->valueTransformers->transform( + return $this->valueTransformers->transform( $value, $attributes, $this->transformers, - fn (mixed $value) => $this->defaultTransformer($value, $formatter, $references), + fn (mixed $value) => $this->defaultTransformer($value, $references), ); - - $formatter->push($value); - - return $value; } /** - * @param Formatter $formatter * @param WeakMap $references * @return iterable|scalar|null */ - private function defaultTransformer(mixed $value, Formatter $formatter, WeakMap $references): mixed + private function defaultTransformer(mixed $value, WeakMap $references): mixed { if ($value === null) { return null; @@ -117,7 +104,7 @@ private function defaultTransformer(mixed $value, Formatter $formatter, WeakMap if ($value::class === stdClass::class) { return array_map( - fn (mixed $value) => $this->doNormalize($value, $formatter, $references), + fn (mixed $value) => $this->doTransform($value, $references), (array)$value ); } @@ -158,16 +145,23 @@ private function defaultTransformer(mixed $value, Formatter $formatter, WeakMap $key = $this->keyTransformers->transformKey($key, $attributes); - $transformed[$key] = $this->doNormalize($subValue, $formatter, $references, $attributes); + $transformed[$key] = $this->doTransform($subValue, $references, $attributes); } return $transformed; } if (is_iterable($value)) { - return (function () use ($value, $formatter, $references) { + if (is_array($value)) { + return array_map( + fn (mixed $value) => $this->doTransform($value, $references), + $value + ); + } + + return (function () use ($value, $references) { foreach ($value as $key => $item) { - yield $key => $this->doNormalize($item, $formatter, $references); + yield $key => $this->doTransform($item, $references); } })(); }