diff --git a/src/InterfaceResolver.php b/src/InterfaceResolver.php new file mode 100644 index 00000000..d161d1f3 --- /dev/null +++ b/src/InterfaceResolver.php @@ -0,0 +1,12 @@ +get(FunctionDefinitionRepository::class), $settings->customConstructors ), + $settings->interfaceResolver, ); $builder = new CasterProxyNodeBuilder($builder); diff --git a/src/Library/Settings.php b/src/Library/Settings.php index 028556c2..cb12d7b1 100644 --- a/src/Library/Settings.php +++ b/src/Library/Settings.php @@ -4,6 +4,7 @@ namespace CuyZ\Valinor\Library; +use CuyZ\Valinor\InterfaceResolver; use CuyZ\Valinor\Mapper\Object\Constructor; use CuyZ\Valinor\Mapper\Object\DynamicConstructor; use CuyZ\Valinor\Mapper\Tree\Message\ErrorMessage; @@ -59,6 +60,9 @@ final class Settings /** @var array */ public array $transformerAttributes = []; + /** @var InterfaceResolver|null */ + public ?InterfaceResolver $interfaceResolver = null; + public function __construct() { $this->inferredMapping[DateTimeInterface::class] = static fn () => DateTimeImmutable::class; diff --git a/src/Mapper/Tree/Builder/InterfaceNodeBuilder.php b/src/Mapper/Tree/Builder/InterfaceNodeBuilder.php index 17b5a449..7109db34 100644 --- a/src/Mapper/Tree/Builder/InterfaceNodeBuilder.php +++ b/src/Mapper/Tree/Builder/InterfaceNodeBuilder.php @@ -6,6 +6,7 @@ use CuyZ\Valinor\Definition\FunctionsContainer; use CuyZ\Valinor\Definition\Repository\ClassDefinitionRepository; +use CuyZ\Valinor\InterfaceResolver; use CuyZ\Valinor\Mapper\Object\Arguments; use CuyZ\Valinor\Mapper\Object\ArgumentsValues; use CuyZ\Valinor\Mapper\Object\Exception\InvalidSource; @@ -27,6 +28,7 @@ public function __construct( private ObjectImplementations $implementations, private ClassDefinitionRepository $classDefinitionRepository, private FunctionsContainer $constructors, + private InterfaceResolver $interfaceResolver, ) {} public function build(Shell $shell, RootNodeBuilder $rootBuilder): TreeNode @@ -53,6 +55,19 @@ public function build(Shell $shell, RootNodeBuilder $rootBuilder): TreeNode if (! $this->implementations->has($className)) { if ($type instanceof InterfaceType || $this->classDefinitionRepository->for($type)->isAbstract) { + if ($this->interfaceResolver){ + $value = $shell->value(); + $resolver_props = []; + foreach($this->interfaceResolver->getResolverProps($className) as $prop){ + $resolver_props[$prop] = $value[$prop]; + unset($value[$prop]); + } + $resolvedClassName = $this->interfaceResolver->resolve($className, $resolver_props); + if ($resolvedClassName !== null) { + $shell = $shell->withType(new NativeClassType($resolvedClassName))->withValue($value); + return $this->delegate->build($shell, $rootBuilder); + } + } throw new CannotResolveObjectType($className); } diff --git a/src/MapperBuilder.php b/src/MapperBuilder.php index 48ffecc2..fef485ed 100644 --- a/src/MapperBuilder.php +++ b/src/MapperBuilder.php @@ -4,6 +4,7 @@ namespace CuyZ\Valinor; +use CuyZ\Valinor\InterfaceResolver; use CuyZ\Valinor\Library\Container; use CuyZ\Valinor\Library\Settings; use CuyZ\Valinor\Mapper\ArgumentsMapper; @@ -530,6 +531,19 @@ public function registerTransformer(callable|string $transformer, int $priority return $clone; } + /** + * @param string $factoryClass + * @return void + */ + public function withInterfaceResolver(InterfaceResolver $resolver): self + { + + $clone = clone $this; + $clone->settings->interfaceResolver = $resolver; + + return $clone->registerTransformer([$resolver, 'transform']); + } + /** * Warms up the injected cache implementation with the provided class names. *