Skip to content

Commit

Permalink
feat: introduce normalizer
Browse files Browse the repository at this point in the history
  • Loading branch information
romm committed Aug 29, 2023
1 parent f3f3429 commit fd2c0f8
Show file tree
Hide file tree
Showing 16 changed files with 843 additions and 71 deletions.
9 changes: 8 additions & 1 deletion src/Definition/FunctionsContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,20 @@

namespace CuyZ\Valinor\Definition;

use Countable;
use CuyZ\Valinor\Definition\Repository\FunctionDefinitionRepository;
use IteratorAggregate;
use Traversable;

use function array_keys;
use function count;

/**
* @internal
*
* @implements IteratorAggregate<string|int, FunctionObject>
*/
final class FunctionsContainer implements IteratorAggregate
final class FunctionsContainer implements IteratorAggregate, Countable
{
/** @var array<FunctionObject> */
private array $functions = [];
Expand Down Expand Up @@ -50,4 +52,9 @@ private function function(string|int $key): FunctionObject
$this->callables[$key]
);
}

public function count(): int
{
return count($this->callables);
}
}
81 changes: 21 additions & 60 deletions src/Library/Container.php → src/Library/MapperContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,11 @@

namespace CuyZ\Valinor\Library;

use CuyZ\Valinor\Cache\ChainCache;
use CuyZ\Valinor\Cache\KeySanitizerCache;
use CuyZ\Valinor\Cache\RuntimeCache;
use CuyZ\Valinor\Cache\Warmup\RecursiveCacheWarmupService;
use CuyZ\Valinor\Definition\FunctionsContainer;
use CuyZ\Valinor\Definition\Repository\AttributesRepository;
use CuyZ\Valinor\Definition\Repository\Cache\CacheClassDefinitionRepository;
use CuyZ\Valinor\Definition\Repository\Cache\CacheFunctionDefinitionRepository;
use CuyZ\Valinor\Definition\Repository\ClassDefinitionRepository;
use CuyZ\Valinor\Definition\Repository\FunctionDefinitionRepository;
use CuyZ\Valinor\Definition\Repository\Reflection\NativeAttributesRepository;
use CuyZ\Valinor\Definition\Repository\Reflection\ReflectionClassDefinitionRepository;
use CuyZ\Valinor\Definition\Repository\Reflection\ReflectionFunctionDefinitionRepository;
use CuyZ\Valinor\Mapper\ArgumentsMapper;
use CuyZ\Valinor\Mapper\Object\Factory\CacheObjectBuilderFactory;
use CuyZ\Valinor\Mapper\Object\Factory\CollisionObjectBuilderFactory;
Expand All @@ -30,14 +22,14 @@
use CuyZ\Valinor\Mapper\Tree\Builder\ArrayNodeBuilder;
use CuyZ\Valinor\Mapper\Tree\Builder\CasterNodeBuilder;
use CuyZ\Valinor\Mapper\Tree\Builder\CasterProxyNodeBuilder;
use CuyZ\Valinor\Mapper\Tree\Builder\ObjectNodeBuilder;
use CuyZ\Valinor\Mapper\Tree\Builder\ErrorCatcherNodeBuilder;
use CuyZ\Valinor\Mapper\Tree\Builder\InterfaceNodeBuilder;
use CuyZ\Valinor\Mapper\Tree\Builder\IterableNodeBuilder;
use CuyZ\Valinor\Mapper\Tree\Builder\ListNodeBuilder;
use CuyZ\Valinor\Mapper\Tree\Builder\NativeClassNodeBuilder;
use CuyZ\Valinor\Mapper\Tree\Builder\NodeBuilder;
use CuyZ\Valinor\Mapper\Tree\Builder\ObjectImplementations;
use CuyZ\Valinor\Mapper\Tree\Builder\NativeClassNodeBuilder;
use CuyZ\Valinor\Mapper\Tree\Builder\ObjectNodeBuilder;
use CuyZ\Valinor\Mapper\Tree\Builder\RootNodeBuilder;
use CuyZ\Valinor\Mapper\Tree\Builder\ScalarNodeBuilder;
use CuyZ\Valinor\Mapper\Tree\Builder\ShapedArrayNodeBuilder;
Expand All @@ -48,8 +40,6 @@
use CuyZ\Valinor\Mapper\TypeArgumentsMapper;
use CuyZ\Valinor\Mapper\TypeTreeMapper;
use CuyZ\Valinor\Type\ClassType;
use CuyZ\Valinor\Type\Parser\Factory\LexingTypeParserFactory;
use CuyZ\Valinor\Type\Parser\Factory\TypeParserFactory;
use CuyZ\Valinor\Type\Parser\TypeParser;
use CuyZ\Valinor\Type\ScalarType;
use CuyZ\Valinor\Type\Types\ArrayType;
Expand All @@ -64,24 +54,27 @@
use function count;

/** @internal */
final class Container
final class MapperContainer
{
private SharedContainer $shared;

/** @var array<class-string, object> */
private array $services = [];

/** @var array<class-string, callable(): object> */
private array $factories;

public function __construct(Settings $settings)
public function __construct(MapperSettings $settings)
{
$this->shared = SharedContainer::new($settings->cache ?? null);
$this->factories = [
TreeMapper::class => fn () => new TypeTreeMapper(
$this->get(TypeParser::class),
$this->shared->get(TypeParser::class),
$this->get(RootNodeBuilder::class)
),

ArgumentsMapper::class => fn () => new TypeArgumentsMapper(
$this->get(FunctionDefinitionRepository::class),
$this->shared->get(FunctionDefinitionRepository::class),
$this->get(RootNodeBuilder::class)
),

Expand All @@ -102,7 +95,7 @@ public function __construct(Settings $settings)
ShapedArrayType::class => new ShapedArrayNodeBuilder($settings->allowSuperfluousKeys),
ScalarType::class => new ScalarNodeBuilder($settings->enableFlexibleCasting),
ClassType::class => new NativeClassNodeBuilder(
$this->get(ClassDefinitionRepository::class),
$this->shared->get(ClassDefinitionRepository::class),
$this->get(ObjectBuilderFactory::class),
$this->get(ObjectNodeBuilder::class),
$settings->enableFlexibleCasting,
Expand All @@ -111,7 +104,7 @@ public function __construct(Settings $settings)

$builder = new UnionNodeBuilder(
$builder,
$this->get(ClassDefinitionRepository::class),
$this->shared->get(ClassDefinitionRepository::class),
$this->get(ObjectBuilderFactory::class),
$this->get(ObjectNodeBuilder::class),
$settings->enableFlexibleCasting
Expand All @@ -120,7 +113,7 @@ public function __construct(Settings $settings)
$builder = new InterfaceNodeBuilder(
$builder,
$this->get(ObjectImplementations::class),
$this->get(ClassDefinitionRepository::class),
$this->shared->get(ClassDefinitionRepository::class),
$this->get(ObjectBuilderFactory::class),
$this->get(ObjectNodeBuilder::class),
$settings->enableFlexibleCasting
Expand All @@ -133,7 +126,7 @@ public function __construct(Settings $settings)
$builder = new ValueAlteringNodeBuilder(
$builder,
new FunctionsContainer(
$this->get(FunctionDefinitionRepository::class),
$this->shared->get(FunctionDefinitionRepository::class),
$settings->valueModifier
)
);
Expand All @@ -148,22 +141,22 @@ public function __construct(Settings $settings)

ObjectImplementations::class => fn () => new ObjectImplementations(
new FunctionsContainer(
$this->get(FunctionDefinitionRepository::class),
$this->shared->get(FunctionDefinitionRepository::class),
$settings->inferredMapping
),
$this->get(TypeParser::class),
$this->shared->get(TypeParser::class),
),

ObjectBuilderFactory::class => function () use ($settings) {
$constructors = new FunctionsContainer(
$this->get(FunctionDefinitionRepository::class),
$this->shared->get(FunctionDefinitionRepository::class),
$settings->customConstructors
);

$factory = new ReflectionObjectBuilderFactory();
$factory = new ConstructorObjectBuilderFactory($factory, $settings->nativeConstructors, $constructors);
$factory = new DateTimeZoneObjectBuilderFactory($factory, $this->get(FunctionDefinitionRepository::class));
$factory = new DateTimeObjectBuilderFactory($factory, $settings->supportedDateFormats, $this->get(FunctionDefinitionRepository::class));
$factory = new DateTimeZoneObjectBuilderFactory($factory, $this->shared->get(FunctionDefinitionRepository::class));
$factory = new DateTimeObjectBuilderFactory($factory, $settings->supportedDateFormats, $this->shared->get(FunctionDefinitionRepository::class));
$factory = new CollisionObjectBuilderFactory($factory);

if (! $settings->allowPermissiveTypes) {
Expand All @@ -176,45 +169,13 @@ public function __construct(Settings $settings)
return new CacheObjectBuilderFactory($factory, $cache);
},

ClassDefinitionRepository::class => fn () => new CacheClassDefinitionRepository(
new ReflectionClassDefinitionRepository(
$this->get(TypeParserFactory::class),
$this->get(AttributesRepository::class),
),
$this->get(CacheInterface::class)
),

FunctionDefinitionRepository::class => fn () => new CacheFunctionDefinitionRepository(
new ReflectionFunctionDefinitionRepository(
$this->get(TypeParserFactory::class),
$this->get(AttributesRepository::class),
),
$this->get(CacheInterface::class)
),

AttributesRepository::class => fn () => new NativeAttributesRepository(),

TypeParserFactory::class => fn () => new LexingTypeParserFactory(),

TypeParser::class => fn () => $this->get(TypeParserFactory::class)->get(),

RecursiveCacheWarmupService::class => fn () => new RecursiveCacheWarmupService(
$this->get(TypeParser::class),
$this->get(CacheInterface::class),
$this->shared->get(TypeParser::class),
$this->shared->get(CacheInterface::class),
$this->get(ObjectImplementations::class),
$this->get(ClassDefinitionRepository::class),
$this->shared->get(ClassDefinitionRepository::class),
$this->get(ObjectBuilderFactory::class)
),

CacheInterface::class => function () use ($settings) {
$cache = new RuntimeCache();

if (isset($settings->cache)) {
$cache = new ChainCache($cache, new KeySanitizerCache($settings->cache));
}

return $cache;
},
];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use Throwable;

/** @internal */
final class Settings
final class MapperSettings
{
/** @var non-empty-array<non-empty-string> */
public const DEFAULT_SUPPORTED_DATETIME_FORMATS = [
Expand Down
55 changes: 55 additions & 0 deletions src/Library/NormalizerContainer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

declare(strict_types=1);

namespace CuyZ\Valinor\Library;

use CuyZ\Valinor\Definition\FunctionsContainer;
use CuyZ\Valinor\Definition\Repository\FunctionDefinitionRepository;
use CuyZ\Valinor\Normalizer\FunctionsCheckerNormalizer;
use CuyZ\Valinor\Normalizer\Normalizer;
use CuyZ\Valinor\Normalizer\RecursiveNormalizer;

/** @internal */
final class NormalizerContainer
{
private SharedContainer $shared;

/** @var array<class-string, object> */
private array $services = [];

/** @var array<class-string, callable(): object> */
private array $factories;

public function __construct(NormalizerSettings $settings)
{
$this->shared = SharedContainer::new($settings->cache);
$this->factories = [
Normalizer::class => function () use ($settings) {
$functions = new FunctionsContainer(
$this->shared->get(FunctionDefinitionRepository::class),
$settings->sortedHandlers()
);

$normalizer = new RecursiveNormalizer($functions);

return new FunctionsCheckerNormalizer($normalizer, $functions);
},
];
}

public function normalizer(): Normalizer
{
return $this->get(Normalizer::class);
}

/**
* @template T of object
* @param class-string<T> $name
* @return T
*/
private function get(string $name): object
{
return $this->services[$name] ??= call_user_func($this->factories[$name]); // @phpstan-ignore-line
}
}
35 changes: 35 additions & 0 deletions src/Library/NormalizerSettings.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace CuyZ\Valinor\Library;

use Psr\SimpleCache\CacheInterface;

use function krsort;

/** @internal */
final class NormalizerSettings
{
/** @var CacheInterface<mixed>|null */
public ?CacheInterface $cache = null;

/** @var array<int, list<callable>> */
public array $handlers = [];

/**
* @return array<callable>
*/
public function sortedHandlers(): array
{
krsort($this->handlers);

$callables = [];

foreach ($this->handlers as $list) {
$callables = [...$callables, ...$list];
}

return $callables;
}
}
Loading

0 comments on commit fd2c0f8

Please sign in to comment.