From 1667f93c32daa4706f67277177705928a4da5f1d Mon Sep 17 00:00:00 2001 From: patrykbaszak Date: Wed, 18 Oct 2023 21:48:46 +0200 Subject: [PATCH] . --- output.yaml | 92 +++++++++++++++ src/Command/CreateConfig.php | 27 +++++ src/Config.php | 35 ++++-- src/Reflection/AttributeReflection.php | 15 ++- src/Reflection/ClassReflection.php | 12 ++ src/Reflection/PropertyReflection.php | 13 ++- src/Reflection/ReflectionFactory.php | 4 +- src/Reflection/Type/ClassType.php | 42 ++++++- src/Reflection/Type/CollectionType.php | 17 ++- src/Reflection/Type/SimpleObjectType.php | 50 ++++++++ src/Reflection/Type/Type.php | 138 ++++++++++++++--------- src/Reflection/Type/TypeFactory.php | 119 ++++++++++++++++--- src/Reflection/Type/TypeInterface.php | 8 +- 13 files changed, 484 insertions(+), 88 deletions(-) create mode 100644 output.yaml create mode 100644 src/Command/CreateConfig.php diff --git a/output.yaml b/output.yaml new file mode 100644 index 0000000..ed5e053 --- /dev/null +++ b/output.yaml @@ -0,0 +1,92 @@ +main: PBaszak\DedicatedMapper\Tests\assets\Dummy +classes: + PBaszak\DedicatedMapper\Tests\assets\Dummy: + attributes: { } + className: PBaszak\DedicatedMapper\Tests\assets\Dummy + options: { } + properties: + id: + attributes: + - + class: Symfony\Component\Validator\Constraints\NotBlank + arguments: { } + instance: "\\Symfony\\Component\\Validator\\Constraints\\NotBlank::__set_state(array(\n 'payload' => NULL,\n 'message' => 'This value should not be blank.',\n 'allowNull' => false,\n 'normalizer' => NULL,\n))" + - + class: Symfony\Component\Serializer\Annotation\Groups + arguments: + - test + instance: "\\Symfony\\Component\\Serializer\\Annotation\\Groups::__set_state(array(\n 'groups' => \n array (\n 0 => 'test',\n ),\n))" + name: id + options: { } + type: + types: + - string + innerType: null + nullable: false + union: false + intersection: false + class: false + collection: false + simpleObject: false + name: + attributes: + - + class: Symfony\Component\Validator\Constraints\Length + arguments: + min: 3 + max: 255 + instance: "\\Symfony\\Component\\Validator\\Constraints\\Length::__set_state(array(\n 'payload' => NULL,\n 'maxMessage' => 'This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less.',\n 'minMessage' => 'This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more.',\n 'exactMessage' => 'This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters.',\n 'charsetMessage' => 'This value does not match the expected {{ charset }} charset.',\n 'max' => 255,\n 'min' => 3,\n 'charset' => 'UTF-8',\n 'normalizer' => NULL,\n 'countUnit' => 'codepoints',\n))" + - + class: Symfony\Component\Serializer\Annotation\Groups + arguments: + - test + instance: "\\Symfony\\Component\\Serializer\\Annotation\\Groups::__set_state(array(\n 'groups' => \n array (\n 0 => 'test',\n ),\n))" + name: name + options: { } + type: + types: + - string + innerType: null + nullable: false + union: false + intersection: false + class: false + collection: false + simpleObject: false + description: + attributes: { } + name: description + options: { } + type: + types: + - string + innerType: null + nullable: false + union: false + intersection: false + class: false + collection: false + simpleObject: false + _embedded: + attributes: + - + class: Symfony\Component\Validator\Constraints\Valid + arguments: { } + instance: "\\Symfony\\Component\\Validator\\Constraints\\Valid::__set_state(array(\n 'payload' => NULL,\n 'traverse' => true,\n))" + - + class: Symfony\Component\Serializer\Annotation\Groups + arguments: + - test + instance: "\\Symfony\\Component\\Serializer\\Annotation\\Groups::__set_state(array(\n 'groups' => \n array (\n 0 => 'test',\n ),\n))" + name: _embedded + options: { } + type: + types: + - PBaszak\DedicatedMapper\Tests\assets\EmbeddedDTO + innerType: null + nullable: false + union: false + intersection: false + class: true + collection: false + simpleObject: false diff --git a/src/Command/CreateConfig.php b/src/Command/CreateConfig.php new file mode 100644 index 0000000..c59ce31 --- /dev/null +++ b/src/Command/CreateConfig.php @@ -0,0 +1,27 @@ +reflect()->export(), 256, 4)); + + return Command::SUCCESS; + } +} diff --git a/src/Config.php b/src/Config.php index d526985..99c5bf8 100644 --- a/src/Config.php +++ b/src/Config.php @@ -4,19 +4,23 @@ namespace PBaszak\DedicatedMapper; +use LogicException; use PBaszak\DedicatedMapper\Reflection\ClassReflection; use PBaszak\DedicatedMapper\Reflection\ReflectionFactory; +use PBaszak\DedicatedMapper\Reflection\Type\ClassType; +use PBaszak\DedicatedMapper\Reflection\Type\TypeFactory; class Config { - /** @var array */ - protected array $usedFiles = []; - protected ClassReflection $classReflection; + /** + * @var array + */ + protected array $classes; /** * @param class-string $className */ - public function __construct(private string $className) + public function __construct(protected string $className) { if (!class_exists($this->className, false)) { throw new \InvalidArgumentException( @@ -27,30 +31,37 @@ public function __construct(private string $className) public function reflect(): self { - $this->classReflection = (new ReflectionFactory())->createClassReflection($this->className, null); + ClassType::$classTypes = []; + (new TypeFactory(new ReflectionFactory()))->createClassType( + new \ReflectionClass($this->className), + null + ); + + $this->classes = ClassType::$classTypes; return $this; } - public function getClassReflection(): ClassReflection + public function getMainClassType(): ClassType { - return $this->classReflection; + return $this->classes[$this->className]; } public function export(): array { + if (!isset($this->classes)) { + throw new LogicException('Class reflection is not set. You need to call reflect() method first.'); + } + return [ - 'className' => $this->className, - 'classReflection' => $this->classReflection, - 'usedFiles' => $this->usedFiles, + 'main' => $this->className, + 'classes' => array_map(fn (ClassType $class) => $class->toArray(), $this->classes), ]; } public static function import(array $data): self { $config = new self($data['className']); - $config->classReflection = $data['classReflection']; - $config->usedFiles = $data['usedFiles']; return $config; } diff --git a/src/Reflection/AttributeReflection.php b/src/Reflection/AttributeReflection.php index 2b1a1e6..9ba1c78 100644 --- a/src/Reflection/AttributeReflection.php +++ b/src/Reflection/AttributeReflection.php @@ -10,6 +10,18 @@ class AttributeReflection { + public function toArray(): array + { + return array_map( + fn (object $attribute) => [ + 'class' => $attribute->class, + 'arguments' => $attribute->arguments, + 'instance' => var_export($attribute->instance, true), + ], + $this->attributes->getArrayCopy() + ); + } + public function __construct( /** * @var ClassReflection|CollectionType|PropertyReflection|SimpleObjectType $parent each attribute must have resource @@ -20,7 +32,8 @@ public function __construct( * @var ArrayObject $attributes */ protected ArrayObject $attributes, - ) {} + ) { + } /** * @return ClassReflection|CollectionType|PropertyReflection|SimpleObjectType diff --git a/src/Reflection/ClassReflection.php b/src/Reflection/ClassReflection.php index 2af3d14..dd48a00 100644 --- a/src/Reflection/ClassReflection.php +++ b/src/Reflection/ClassReflection.php @@ -6,10 +6,22 @@ use ArrayObject; use PBaszak\DedicatedMapper\Reflection\Type\ClassType; +use PBaszak\DedicatedMapper\Utils\ToArrayTrait; use ReflectionClass; +use Serializable; class ClassReflection { + public function toArray(): array + { + return [ + 'attributes' => $this->attributes->toArray(), + 'className' => $this->reflection?->getName(), + 'options' => $this->options->toArray(), + 'properties' => array_map(fn (PropertyReflection $property) => $property->toArray(), $this->properties->getArrayCopy()), + ]; + } + public function __construct( /** * @var null|\ReflectionClass $reflection `null` is available for reversed mapping diff --git a/src/Reflection/PropertyReflection.php b/src/Reflection/PropertyReflection.php index a3f1325..f36f150 100644 --- a/src/Reflection/PropertyReflection.php +++ b/src/Reflection/PropertyReflection.php @@ -5,9 +5,20 @@ namespace PBaszak\DedicatedMapper\Reflection; use PBaszak\DedicatedMapper\Reflection\Type\TypeInterface; +use PBaszak\DedicatedMapper\Utils\ToArrayTrait; class PropertyReflection { + public function toArray(): array + { + return [ + 'attributes' => $this->attributes->toArray(), + 'name' => $this->name, + 'options' => $this->options->toArray(), + 'type' => $this->type->toArray(), + ]; + } + public function __construct( /** * @var ClassReflection $parent each property must have parent class @@ -103,4 +114,4 @@ public function getReflectionParameter(): ?\ReflectionParameter { return $this->reflectionParameter; } -} \ No newline at end of file +} diff --git a/src/Reflection/ReflectionFactory.php b/src/Reflection/ReflectionFactory.php index 8331d90..2e47017 100644 --- a/src/Reflection/ReflectionFactory.php +++ b/src/Reflection/ReflectionFactory.php @@ -7,6 +7,7 @@ use ArrayObject; use PBaszak\DedicatedMapper\Attribute\ApplyToCollectionItems; use PBaszak\DedicatedMapper\Reflection\Type\ClassType; +use PBaszak\DedicatedMapper\Reflection\Type\TypeFactory; use PBaszak\DedicatedMapper\Reflection\Type\TypeInterface; use PBaszak\DedicatedMapper\Utils\GetParametersFromObject; use ReflectionClass; @@ -49,8 +50,7 @@ public function createPropertyReflection(\ReflectionProperty $reflection, ClassR $attributes = new AttributeReflection($instance, $this->getAttributesFromReflection($reflection)); $ref->getProperty('attributes')->setValue($instance, $attributes); $ref->getProperty('options')->setValue($instance, new Options()); - - // type + $ref->getProperty('type')->setValue($instance, (new TypeFactory($this))->createType($instance)); return $instance; } diff --git a/src/Reflection/Type/ClassType.php b/src/Reflection/Type/ClassType.php index 2b1e391..1964f2f 100644 --- a/src/Reflection/Type/ClassType.php +++ b/src/Reflection/Type/ClassType.php @@ -9,11 +9,49 @@ class ClassType implements TypeInterface { + public static array $classTypes = []; + + /** + * @param class-string $class + */ + public static function isClassTypeExists(string $class): bool + { + return isset(self::$classTypes[$class]); + } + + public static function storeClassType(ClassType $instance): void + { + $class = $instance->getReflection()->getReflection()?->getName(); + if (!class_exists($class, false)) { + throw new \InvalidArgumentException(sprintf('Class %s does not exists', $class)); + } + self::$classTypes[$class] = $instance; + } + + public static function supports(Type $type): bool + { + foreach ($type->getTypes() as $t) { + if (class_exists($t, false)) { + return true; + } + } + } + + public static function create(Type $type): TypeInterface + { + + } + + public function toArray(): array + { + return $this->reflection?->toArray(); + } + public function __construct( /** - * @var null|ClassReflection $reflection if `null`, then it is root class + * @var ClassReflection $reflection */ - protected null|ClassReflection $reflection = null, + protected ClassReflection $reflection, /** * @var PropertyReflection|TypeInterface|null $parent if `null`, then it is root class diff --git a/src/Reflection/Type/CollectionType.php b/src/Reflection/Type/CollectionType.php index f6f02d4..101d50a 100644 --- a/src/Reflection/Type/CollectionType.php +++ b/src/Reflection/Type/CollectionType.php @@ -7,9 +7,23 @@ use ArrayObject; use PBaszak\DedicatedMapper\Reflection\AttributeReflection; use PBaszak\DedicatedMapper\Reflection\PropertyReflection; +use PBaszak\DedicatedMapper\Utils\ToArrayTrait; class CollectionType implements TypeInterface { + public function toArray(): array + { + return [ + 'children' => array_map(fn (TypeInterface $child) => $child->toArray(), $this->children->getArrayCopy()), + 'attributes' => $this->attributes->toArray(), + ]; + } + + public static function supports(PropertyReflection $property, Type $type, int $depth): bool + { + return $type->isCollection(); + } + public function __construct( /** * @var null|PropertyReflection|TypeInterface $parent @@ -26,7 +40,8 @@ public function __construct( * @var AttributeReflection $attributes */ protected AttributeReflection $attributes, - ) {} + ) { + } /** * @return null|PropertyReflection|TypeInterface diff --git a/src/Reflection/Type/SimpleObjectType.php b/src/Reflection/Type/SimpleObjectType.php index f0deaf8..b66335d 100644 --- a/src/Reflection/Type/SimpleObjectType.php +++ b/src/Reflection/Type/SimpleObjectType.php @@ -4,12 +4,62 @@ namespace PBaszak\DedicatedMapper\Reflection\Type; +use PBaszak\DedicatedMapper\Attribute\ApplyToCollectionItems; +use PBaszak\DedicatedMapper\Attribute\SimpleObject; use PBaszak\DedicatedMapper\Reflection\AttributeReflection; use PBaszak\DedicatedMapper\Reflection\PropertyReflection; +use PBaszak\DedicatedMapper\Utils\NativeSimpleObject; use ReflectionClass; class SimpleObjectType implements TypeInterface { + public const NATIVE_SIMPLE_OBJECTS = [ + \ArrayIterator::class => [], + \ArrayObject::class => [], + \DateTime::class => ['staticConstructor' => NativeSimpleObject::class.'::DateTimeConstructor'], + \DateTimeImmutable::class => ['staticConstructor' => NativeSimpleObject::class.'::DateTimeConstructor'], + \DateTimeZone::class => ['staticConstructor' => NativeSimpleObject::class.'::DateTimeZoneConstructor'], + \DateInterval::class => [], + ]; + + public function toArray(): array + { + return [ + 'type' => $this->type->toArray(), + 'attributes' => $this->attributes->toArray(), + 'collection' => $this->collection?->toArray(), + ]; + } + + public static function supports(PropertyReflection $property, Type $type, int $depth): bool + { + if (!$type->isClass()) { + return false; + } + + foreach ($type->getTypes() as $t) { + if (class_exists($t, false)) { + if (isset(self::NATIVE_SIMPLE_OBJECTS[$t])) { + return true; + } + $reflection = new ReflectionClass($t); + if ($reflection->getAttributes(SimpleObject::class)) { + return true; + } + } + } + + $index = 0; + $attributes = $property->getAttributes(); + do { + $attr = $attributes->getAttributes(SimpleObject::class); + $attributes = $attributes->getAttributes(ApplyToCollectionItems::class)[0] ?? null; + $index++; + } while ($index <= $depth && !empty($attributes?->getAttributes(ApplyToCollectionItems::class))); + + return !empty($attr); + } + public function __construct( /** * @var CollectionType|PropertyReflection $parent diff --git a/src/Reflection/Type/Type.php b/src/Reflection/Type/Type.php index cec10c8..78f4b78 100644 --- a/src/Reflection/Type/Type.php +++ b/src/Reflection/Type/Type.php @@ -5,62 +5,90 @@ namespace PBaszak\DedicatedMapper\Reflection\Type; use PBaszak\DedicatedMapper\Reflection\PropertyReflection; +use PBaszak\DedicatedMapper\Utils\ToArrayTrait; use phpDocumentor\Reflection\Type as PhpDocumentorType; use ReflectionType; class Type implements TypeInterface { - public function __construct( - /** - * @var PropertyReflection|TypeInterface $parent each type must have resource - */ - protected PropertyReflection|TypeInterface $parent, - - /** - * @var array $types - */ - protected array $types, - - /** - * @var bool $nullable - */ - protected bool $nullable, - - /** - * @var bool $union - */ - protected bool $union, - - /** - * @var bool $intersection - */ - protected bool $intersection, - - /** - * @var bool $class - */ - protected bool $class, - - /** - * @var bool $collection - */ - protected bool $collection, - - /** - * @var bool $simpleObject - */ - protected bool $simpleObject, - - /** - * @var null|ReflectionType $reflectionType - */ - protected null|ReflectionType $reflectionType = null, - - /** - * @var null|PhpDocumentorType $phpDocumentorReflectionType - */ - protected null|PhpDocumentorType $phpDocumentorReflectionType = null, - ) {} + /** + * @var PropertyReflection|TypeInterface $parent each type must have resource + */ + protected PropertyReflection|TypeInterface $parent; + + /** + * @var array $types + */ + protected array $types; + + /** + * @var null|TypeInterface $innerType + */ + protected ?TypeInterface $innerType = null; + + /** + * @var bool $nullable + */ + protected bool $nullable = false; + + /** + * @var bool $union + */ + protected bool $union = false; + + /** + * @var bool $intersection + */ + protected bool $intersection = false; + + /** + * @var bool $class + */ + protected bool $class = false; + + /** + * @var bool $collection + */ + protected bool $collection = false; + + /** + * @var bool $simpleObject + */ + protected bool $simpleObject = false; + + /** + * @var null|ReflectionType $reflectionType + */ + protected null|ReflectionType $reflectionType = null; + + /** + * @var null|PhpDocumentorType $phpDocumentorReflectionType + */ + protected null|PhpDocumentorType $phpDocumentorReflectionType = null; + + public function toArray(): array + { + return [ + 'types' => $this->types, + 'innerType' => $this->innerType?->toArray(), + 'nullable' => $this->nullable, + 'union' => $this->union, + 'intersection' => $this->intersection, + 'class' => $this->class, + 'collection' => $this->collection, + 'simpleObject' => $this->simpleObject, + ]; + } + + public static function supports(PropertyReflection $property, self $type, int $depth): bool + { + return true; + } + + public static function create(PropertyReflection|TypeInterface $parent, Type $type): TypeInterface + { + return $type; + } /** * @return CollectionType|PropertyReflection|SimpleObjectType @@ -78,6 +106,14 @@ public function getTypes(): array return $this->types; } + /** + * @return null|TypeInterface + */ + public function getInnerType(): null|TypeInterface + { + return $this->innerType; + } + /** * @return bool */ diff --git a/src/Reflection/Type/TypeFactory.php b/src/Reflection/Type/TypeFactory.php index 5f57465..d87884c 100644 --- a/src/Reflection/Type/TypeFactory.php +++ b/src/Reflection/Type/TypeFactory.php @@ -4,18 +4,34 @@ namespace PBaszak\DedicatedMapper\Reflection\Type; +use PBaszak\DedicatedMapper\Attribute\SimpleObject; use PBaszak\DedicatedMapper\Reflection\PropertyReflection; use PBaszak\DedicatedMapper\Reflection\ReflectionFactory; use phpDocumentor\Reflection\DocBlock\Tags\Var_; use phpDocumentor\Reflection\DocBlockFactory; -use phpDocumentor\Reflection\Type; +use phpDocumentor\Reflection\Type as PhpDocumentorType; +use phpDocumentor\Reflection\Types\AbstractList; +use phpDocumentor\Reflection\Types\Compound; use phpDocumentor\Reflection\Types\ContextFactory; -use ReflectionType; +use phpDocumentor\Reflection\Types\Intersection; +use phpDocumentor\Reflection\Types\Null_; +use phpDocumentor\Reflection\Types\Nullable; +use ReflectionIntersectionType; +use ReflectionNamedType; +use ReflectionUnionType; +use RuntimeException; class TypeFactory { protected ReflectionFactory $reflectionFactory; + public const AVAILABLE_TYPES_BY_PRIORITY = [ + CollectionType::class, + SimpleObjectType::class, + ClassType::class, + Type::class, + ]; + public function __construct(ReflectionFactory $reflectionFactory = null) { $this->reflectionFactory = $reflectionFactory ?? new ReflectionFactory(); @@ -29,21 +45,18 @@ public function createClassType(\ReflectionClass $reflection, null|PropertyRefle $ref->getProperty('reflection')->setValue($instance, $this->reflectionFactory->createClassReflection($reflection->getName(), $instance)); $ref->getProperty('parent')->setValue($instance, $parent); + ClassType::storeClassType($instance); + return $instance; } - - // public function createCollectionType(null|PropertyReflection|TypeInterface $parent): CollectionType - // { - - // } - protected function createType(PropertyReflection $propertyInstanceWithoutType, int $depth = 0): Type + public function createType(PropertyReflection $propertyInstanceWithoutType, int $depth = 0, ?Type $parentInstance = null): TypeInterface { if (null === ($ref = $propertyInstanceWithoutType->getReflection())) { throw new \Exception('Reflection is null.'); } - $type = $ref->getType(); + $type = 0 === $depth ? $ref->getType() : null; $phpDocumentatorType = null; if (false !== ($docComment = $ref->getDocComment())) { /** @var Var_[] $varTags */ @@ -52,15 +65,89 @@ protected function createType(PropertyReflection $propertyInstanceWithoutType, i (new ContextFactory)->createFromReflector($ref) )->getTagsByName('var'); + /** @var null|PhpDocumentorType $phpDocumentatorType */ $phpDocumentatorType = $varTags[0]->getType() ?? null; + if ($phpDocumentatorType && $depth > 0) { + for ($i = 0; $i > $depth; $i++) { + /** @var AbstractList $phpDocumentatorType It means that we are in collection type */ + $phpDocumentatorType = $phpDocumentatorType->getValueType(); + } + } } - } - /** - * @return object{"types": string[], "innerTypes": string[]} - */ - protected function extractTypes(ReflectionType $ref, Type $phpDocumentatorType): object - { - + if (null === $type && null === $phpDocumentatorType) { + throw new RuntimeException('Property has no type. Docblock `@var` or typehint is required.'); + } + + $ref = new \ReflectionClass(Type::class); + /** @var Type $instance */ + $instance = $ref->newInstanceWithoutConstructor(); + $ref->getProperty('reflectionType')->setValue($instance, $type); + $ref->getProperty('phpDocumentorReflectionType')->setValue($instance, $phpDocumentatorType); + $ref->getProperty('parent')->setValue($instance, $parentInstance ?? $propertyInstanceWithoutType); + + $types = []; + if (null !== $type) { + if ($type->allowsNull()) { + $types[] = 'null'; + $ref->getProperty('nullable')->setValue($instance, true); + } + if ($type instanceof ReflectionNamedType) { + $types[] = $type->getName(); + if (class_exists($type->getName(), false)) { + $ref->getProperty('class')->setValue($instance, true); + } + } + if ($type instanceof ReflectionUnionType) { + $types = array_merge($types, array_map(fn (ReflectionNamedType $t) => $t->getName(), $type->getTypes())); + $ref->getProperty('union')->setValue($instance, true); + } + if ($type instanceof ReflectionIntersectionType) { + $types = array_merge($types, array_map(fn (ReflectionNamedType $t) => $t->getName(), $type->getTypes())); + $ref->getProperty('intersection')->setValue($instance, true); + } + } + if (null !== $phpDocumentatorType) { + if ($phpDocumentatorType instanceof Nullable || $phpDocumentatorType instanceof Null_) { + $types[] = 'null'; + $ref->getProperty('nullable')->setValue($instance, true); + $phpDocumentatorType = $phpDocumentatorType->getActualType(); + } + if ($phpDocumentatorType instanceof Compound) { + $types = array_merge($types, array_map(fn (PhpDocumentorType $t) => (string) $t, $phpDocumentatorType->getIterator()->getArrayCopy())); + $ref->getProperty('union')->setValue($instance, true); + } elseif ($phpDocumentatorType instanceof Intersection) { + $types = array_merge($types, array_map(fn (PhpDocumentorType $t) => (string) $t, $phpDocumentatorType->getIterator()->getArrayCopy())); + $ref->getProperty('intersection')->setValue($instance, true); + } elseif ($phpDocumentatorType instanceof AbstractList) { + if (method_exists($phpDocumentatorType, 'getFqsen')) { + $fqsen = $phpDocumentatorType->getFqsen(); + if ($fqsen && class_exists((string) $fqsen, false)) { + $ref->getProperty('class')->setValue($instance, true); + } + } + $types[] = $fqsen ? (string) $fqsen : 'array'; + $ref->getProperty('collection')->setValue($instance, true); + $ref->getProperty('innerTypes')->setValue($instance, $this->createType($propertyInstanceWithoutType, $depth + 1, $instance)); + } else { + $t = (string) $phpDocumentatorType; + if (class_exists($t, false)) { + $types[] = $t; + $ref->getProperty('class')->setValue($instance, true); + } + } + } + + $types = array_unique($types); + $ref->getProperty('types')->setValue($instance, $types); + + foreach (self::AVAILABLE_TYPES_BY_PRIORITY as $typeClass) { + if ($typeClass::supports($instance, $depth)) { + $instance = $typeClass::create($instance); + break; + } + } + + return $instance; } } diff --git a/src/Reflection/Type/TypeInterface.php b/src/Reflection/Type/TypeInterface.php index 3ef2639..62c85e4 100644 --- a/src/Reflection/Type/TypeInterface.php +++ b/src/Reflection/Type/TypeInterface.php @@ -4,7 +4,11 @@ namespace PBaszak\DedicatedMapper\Reflection\Type; +use PBaszak\DedicatedMapper\Reflection\PropertyReflection; + interface TypeInterface { - -} \ No newline at end of file + public function toArray(): array; + public static function supports(Type $type): bool; + public static function create(Type $type): TypeInterface; +}