From a670d98ed4333d6e840639355c9918696036f0e1 Mon Sep 17 00:00:00 2001
From: Priyadi Iman Nurcahyo <1102197+priyadi@users.noreply.github.com>
Date: Tue, 24 Sep 2024 09:54:44 +0700
Subject: [PATCH 1/2] chore: cleanup property path classes
---
CHANGELOG.md | 1 +
psalm.xml | 4 +-
...thAwarePropertyTypeExtractorException.php} | 5 +-
.../ObjectToObjectMetadataFactory.php | 11 ++--
...solver.php => PropertyMetadataFactory.php} | 22 +++----
...ropertyPathAwarePropertyTypeExtractor.php} | 61 +++++++++++++------
tests/src/Fixtures/MapPropertyPath/Book.php | 6 +-
.../src/Fixtures/MapPropertyPath/Library.php | 2 +-
tests/src/Fixtures/MapPropertyPath/Shelf.php | 2 +-
.../IntegrationTest/MapPropertyPathTest.php | 17 +++---
10 files changed, 70 insertions(+), 61 deletions(-)
rename src/Transformer/Exception/{PropertyPathResolverException.php => PropertyPathAwarePropertyTypeExtractorException.php} (82%)
rename src/Transformer/ObjectToObjectMetadata/Implementation/Util/{PropertyMetadataResolver.php => PropertyMetadataFactory.php} (96%)
rename src/Transformer/ObjectToObjectMetadata/Implementation/Util/{PropertyPathResolver.php => PropertyPathAwarePropertyTypeExtractor.php} (59%)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 79717e9..185beec 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,7 @@
* feat: property path support in `Map` attributes
* fix: writing using property path
* fix: data collector output for property path
+* chore: cleanup property path classes
## 1.8.0
diff --git a/psalm.xml b/psalm.xml
index cbfa928..a09e026 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -72,14 +72,14 @@
-
+
-
+
diff --git a/src/Transformer/Exception/PropertyPathResolverException.php b/src/Transformer/Exception/PropertyPathAwarePropertyTypeExtractorException.php
similarity index 82%
rename from src/Transformer/Exception/PropertyPathResolverException.php
rename to src/Transformer/Exception/PropertyPathAwarePropertyTypeExtractorException.php
index 74098e2..e04a084 100644
--- a/src/Transformer/Exception/PropertyPathResolverException.php
+++ b/src/Transformer/Exception/PropertyPathAwarePropertyTypeExtractorException.php
@@ -18,11 +18,8 @@
/**
* @internal
*/
-class PropertyPathResolverException extends \LogicException implements ExceptionInterface
+class PropertyPathAwarePropertyTypeExtractorException extends \LogicException implements ExceptionInterface
{
- /**
- * @param class-string $class
- */
public function __construct(string $message, string $class, string $propertyPath)
{
$message = \sprintf('%s, root class: "%s", property path: "%s"', $message, $class, $propertyPath);
diff --git a/src/Transformer/ObjectToObjectMetadata/Implementation/ObjectToObjectMetadataFactory.php b/src/Transformer/ObjectToObjectMetadata/Implementation/ObjectToObjectMetadataFactory.php
index 93c9f92..dfd22b0 100644
--- a/src/Transformer/ObjectToObjectMetadata/Implementation/ObjectToObjectMetadataFactory.php
+++ b/src/Transformer/ObjectToObjectMetadata/Implementation/ObjectToObjectMetadataFactory.php
@@ -21,7 +21,7 @@
use Rekalogika\Mapper\Transformer\Exception\InternalClassUnsupportedException;
use Rekalogika\Mapper\Transformer\Exception\SourceClassNotInInheritanceMapException;
use Rekalogika\Mapper\Transformer\ObjectToObjectMetadata\Implementation\Util\PropertyMappingResolver;
-use Rekalogika\Mapper\Transformer\ObjectToObjectMetadata\Implementation\Util\PropertyMetadataResolver;
+use Rekalogika\Mapper\Transformer\ObjectToObjectMetadata\Implementation\Util\PropertyMetadataFactory;
use Rekalogika\Mapper\Transformer\ObjectToObjectMetadata\ObjectToObjectMetadata;
use Rekalogika\Mapper\Transformer\ObjectToObjectMetadata\ObjectToObjectMetadataFactoryInterface;
use Rekalogika\Mapper\Transformer\ObjectToObjectMetadata\PropertyMapping;
@@ -38,7 +38,8 @@
*/
final readonly class ObjectToObjectMetadataFactory implements ObjectToObjectMetadataFactoryInterface
{
- private PropertyMetadataResolver $propertyMetadataResolver;
+ private PropertyMetadataFactory $propertyMetadataFactory;
+
private PropertyMappingResolver $propertyMappingResolver;
public function __construct(
@@ -51,7 +52,7 @@ public function __construct(
private ProxyFactoryInterface $proxyFactory,
TypeResolverInterface $typeResolver,
) {
- $this->propertyMetadataResolver = new PropertyMetadataResolver(
+ $this->propertyMetadataFactory = new PropertyMetadataFactory(
propertyReadInfoExtractor: $propertyReadInfoExtractor,
propertyWriteInfoExtractor: $propertyWriteInfoExtractor,
propertyTypeExtractor: $propertyTypeExtractor,
@@ -192,14 +193,14 @@ public function createObjectToObjectMetadata(
// generate source & target property metadata
- $sourcePropertyMetadata = $this->propertyMetadataResolver
+ $sourcePropertyMetadata = $this->propertyMetadataFactory
->createSourcePropertyMetadata(
class: $sourceClass,
property: $sourceProperty,
allowsDynamicProperties: $sourceAllowsDynamicProperties,
);
- $targetPropertyMetadata = $this->propertyMetadataResolver
+ $targetPropertyMetadata = $this->propertyMetadataFactory
->createTargetPropertyMetadata(
class: $targetClass,
property: $targetProperty,
diff --git a/src/Transformer/ObjectToObjectMetadata/Implementation/Util/PropertyMetadataResolver.php b/src/Transformer/ObjectToObjectMetadata/Implementation/Util/PropertyMetadataFactory.php
similarity index 96%
rename from src/Transformer/ObjectToObjectMetadata/Implementation/Util/PropertyMetadataResolver.php
rename to src/Transformer/ObjectToObjectMetadata/Implementation/Util/PropertyMetadataFactory.php
index 8e77479..03a6644 100644
--- a/src/Transformer/ObjectToObjectMetadata/Implementation/Util/PropertyMetadataResolver.php
+++ b/src/Transformer/ObjectToObjectMetadata/Implementation/Util/PropertyMetadataFactory.php
@@ -33,18 +33,18 @@
/**
* @internal
*/
-final readonly class PropertyMetadataResolver
+final readonly class PropertyMetadataFactory
{
- private PropertyPathResolver $propertyPathResolver;
+ private PropertyTypeExtractorInterface $propertyTypeExtractor;
public function __construct(
private PropertyReadInfoExtractorInterface $propertyReadInfoExtractor,
private PropertyWriteInfoExtractorInterface $propertyWriteInfoExtractor,
- private PropertyTypeExtractorInterface $propertyTypeExtractor,
+ PropertyTypeExtractorInterface $propertyTypeExtractor,
private TypeResolverInterface $typeResolver,
) {
- $this->propertyPathResolver = new PropertyPathResolver(
- propertyTypeExtractor: $propertyTypeExtractor,
+ $this->propertyTypeExtractor = new PropertyPathAwarePropertyTypeExtractor(
+ decorated: $propertyTypeExtractor,
);
}
@@ -57,10 +57,7 @@ public function createSourcePropertyMetadata(
bool $allowsDynamicProperties,
): SourcePropertyMetadata {
if ($this->isPropertyPath($property)) {
- $types = $this->propertyPathResolver->resolvePropertyPath(
- class: $class,
- propertyPath: $property,
- );
+ $types = array_values($this->propertyTypeExtractor->getTypes($class, $property) ?? []);
return new SourcePropertyMetadata(
readMode: ReadMode::PropertyPath,
@@ -106,10 +103,7 @@ public function createTargetPropertyMetadata(
bool $allowsDynamicProperties,
): TargetPropertyMetadata {
if ($this->isPropertyPath($property)) {
- $types = $this->propertyPathResolver->resolvePropertyPath(
- class: $class,
- propertyPath: $property,
- );
+ $types = array_values($this->propertyTypeExtractor->getTypes($class, $property) ?? []);
return new TargetPropertyMetadata(
readMode: ReadMode::PropertyPath,
@@ -318,7 +312,6 @@ private function processPropertyWriteInfo(
/**
* @param class-string $class
- * @return boolean
*/
private function sourceAllowsTargetDelete(
string $class,
@@ -347,7 +340,6 @@ class: $class,
/**
* @param class-string $class
- * @return boolean
*/
private function targetAllowsDelete(
string $class,
diff --git a/src/Transformer/ObjectToObjectMetadata/Implementation/Util/PropertyPathResolver.php b/src/Transformer/ObjectToObjectMetadata/Implementation/Util/PropertyPathAwarePropertyTypeExtractor.php
similarity index 59%
rename from src/Transformer/ObjectToObjectMetadata/Implementation/Util/PropertyPathResolver.php
rename to src/Transformer/ObjectToObjectMetadata/Implementation/Util/PropertyPathAwarePropertyTypeExtractor.php
index ffe5b76..67c5cdb 100644
--- a/src/Transformer/ObjectToObjectMetadata/Implementation/Util/PropertyPathResolver.php
+++ b/src/Transformer/ObjectToObjectMetadata/Implementation/Util/PropertyPathAwarePropertyTypeExtractor.php
@@ -13,30 +13,48 @@
namespace Rekalogika\Mapper\Transformer\ObjectToObjectMetadata\Implementation\Util;
-use Rekalogika\Mapper\Transformer\Exception\PropertyPathResolverException;
+use Rekalogika\Mapper\Transformer\Exception\PropertyPathAwarePropertyTypeExtractorException;
use Symfony\Component\PropertyAccess\PropertyPath;
use Symfony\Component\PropertyAccess\PropertyPathIteratorInterface;
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
use Symfony\Component\PropertyInfo\Type;
+use Symfony\Component\TypeInfo\Type as TypeInfoType;
/**
* @internal
*/
-final readonly class PropertyPathResolver
+final readonly class PropertyPathAwarePropertyTypeExtractor implements PropertyTypeExtractorInterface
{
public function __construct(
- private PropertyTypeExtractorInterface $propertyTypeExtractor,
+ private PropertyTypeExtractorInterface $decorated,
) {}
/**
- * @param class-string $class
- * @return list
+ * @param array $context
*/
- public function resolvePropertyPath(
+ public function getType(
string $class,
- string $propertyPath,
- ): array {
- $propertyPathObject = new PropertyPath($propertyPath);
+ string $property,
+ array $context = [],
+ ): TypeInfoType {
+ throw new \BadMethodCallException('Not implemented');
+ }
+
+ /**
+ * @param array $context
+ * @return null|array
+ */
+ #[\Override]
+ public function getTypes(
+ string $class,
+ string $property,
+ array $context = [],
+ ): ?array {
+ if (!$this->isPropertyPath($property)) {
+ return $this->decorated->getTypes($class, $property, $context);
+ }
+
+ $propertyPathObject = new PropertyPath($property);
/** @var \Iterator&PropertyPathIteratorInterface */
$iterator = $propertyPathObject->getIterator();
@@ -55,10 +73,10 @@ public function resolvePropertyPath(
if ($types !== null) {
if (\count($types) > 1) {
- throw new PropertyPathResolverException(
+ throw new PropertyPathAwarePropertyTypeExtractorException(
message: \sprintf('Cannot proceed because property "%s" has multiple types in class "%s"', $propertyPathPart, $currentClass ?? 'unknown'),
class: $class,
- propertyPath: $propertyPath,
+ propertyPath: $property,
);
}
@@ -71,33 +89,38 @@ class: $class,
$types = $currentType?->getCollectionValueTypes();
} else {
if ($currentClass === null) {
- throw new PropertyPathResolverException(
+ throw new PropertyPathAwarePropertyTypeExtractorException(
message: \sprintf('Trying to resolve path "%s", but the current node is not an object', $propertyPathPart),
class: $class,
- propertyPath: $propertyPath,
+ propertyPath: $property,
);
}
$currentPath .= '.' . $propertyPathPart;
- $types = $this->propertyTypeExtractor
- ->getTypes($currentClass, $propertyPathPart);
+ $types = $this->decorated
+ ->getTypes($currentClass, $propertyPathPart, $context);
}
if ($types === null) {
- throw new PropertyPathResolverException(
+ throw new PropertyPathAwarePropertyTypeExtractorException(
message: \sprintf('Property "%s" not found in class "%s"', $propertyPathPart, $currentClass ?? 'unknown'),
class: $class,
- propertyPath: $propertyPath,
+ propertyPath: $property,
);
} elseif (\count($types) === 0) {
- throw new PropertyPathResolverException(
+ throw new PropertyPathAwarePropertyTypeExtractorException(
message: \sprintf('Cannot determine the type of property "%s" in class "%s"', $propertyPathPart, $currentClass ?? 'unknown'),
class: $class,
- propertyPath: $propertyPath,
+ propertyPath: $property,
);
}
}
return array_values($types ?? []);
}
+
+ private function isPropertyPath(string $property): bool
+ {
+ return str_contains($property, '.') || str_contains($property, '[');
+ }
}
diff --git a/tests/src/Fixtures/MapPropertyPath/Book.php b/tests/src/Fixtures/MapPropertyPath/Book.php
index bc46585..e1f6653 100644
--- a/tests/src/Fixtures/MapPropertyPath/Book.php
+++ b/tests/src/Fixtures/MapPropertyPath/Book.php
@@ -23,7 +23,7 @@ final class Book
/**
* @var Collection
*/
- private Collection $chapters;
+ private readonly Collection $chapters;
public function __construct()
{
@@ -70,8 +70,4 @@ public function getParts(): Collection
{
return new ArrayCollection();
}
-
- public function addPart(Chapter|Section $chapter): void {}
-
- public function removePart(Chapter|Section $chapter): void {}
}
diff --git a/tests/src/Fixtures/MapPropertyPath/Library.php b/tests/src/Fixtures/MapPropertyPath/Library.php
index 9ec9194..fbf94a9 100644
--- a/tests/src/Fixtures/MapPropertyPath/Library.php
+++ b/tests/src/Fixtures/MapPropertyPath/Library.php
@@ -21,7 +21,7 @@ final class Library
/**
* @var Collection
*/
- private Collection $shelves;
+ private readonly Collection $shelves;
private ?string $name = null;
diff --git a/tests/src/Fixtures/MapPropertyPath/Shelf.php b/tests/src/Fixtures/MapPropertyPath/Shelf.php
index e0ce466..87cf79f 100644
--- a/tests/src/Fixtures/MapPropertyPath/Shelf.php
+++ b/tests/src/Fixtures/MapPropertyPath/Shelf.php
@@ -23,7 +23,7 @@ final class Shelf
/**
* @var Collection
*/
- private Collection $books;
+ private readonly Collection $books;
private ?int $number = null;
diff --git a/tests/src/IntegrationTest/MapPropertyPathTest.php b/tests/src/IntegrationTest/MapPropertyPathTest.php
index 269a118..d6af7f4 100644
--- a/tests/src/IntegrationTest/MapPropertyPathTest.php
+++ b/tests/src/IntegrationTest/MapPropertyPathTest.php
@@ -23,8 +23,8 @@
use Rekalogika\Mapper\Tests\Fixtures\MapPropertyPath\Shelf;
use Rekalogika\Mapper\Tests\Fixtures\MapPropertyPathDto\BookDto;
use Rekalogika\Mapper\Tests\Fixtures\MapPropertyPathDto\ChapterDto;
-use Rekalogika\Mapper\Transformer\Exception\PropertyPathResolverException;
-use Rekalogika\Mapper\Transformer\ObjectToObjectMetadata\Implementation\Util\PropertyPathResolver;
+use Rekalogika\Mapper\Transformer\Exception\PropertyPathAwarePropertyTypeExtractorException;
+use Rekalogika\Mapper\Transformer\ObjectToObjectMetadata\Implementation\Util\PropertyPathAwarePropertyTypeExtractor;
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
use Symfony\Component\PropertyInfo\Type;
@@ -33,9 +33,9 @@ class MapPropertyPathTest extends FrameworkTestCase
/**
* @param class-string $class
* @param list|class-string $expected
- * @dataProvider propertyPathResolverDataProvider
+ * @dataProvider propertyPathAwarePropertyTypeExtractorDataProvider
*/
- public function testPropertyPathResolver(
+ public function testPropertyPathAwarePropertyTypeExtractor(
string $class,
string $path,
array|string $expected,
@@ -44,8 +44,7 @@ public function testPropertyPathResolver(
$this->expectException($expected);
}
- $propertyTypeExtractor = $this->get(PropertyTypeExtractorInterface::class);
- $propertyPathResolver = new PropertyPathResolver($propertyTypeExtractor);
+ $propertyTypeExtractor = new PropertyPathAwarePropertyTypeExtractor($this->get(PropertyTypeExtractorInterface::class));
$chapter = new Chapter();
@@ -58,7 +57,7 @@ public function testPropertyPathResolver(
$library = new Library();
$library->addShelf($shelf);
- $type = $propertyPathResolver->resolvePropertyPath($class, $path);
+ $type = $propertyTypeExtractor->getTypes($class, $path);
$this->assertEquals($expected, $type);
}
@@ -66,7 +65,7 @@ public function testPropertyPathResolver(
/**
* @return iterable|class-string}>
*/
- public static function propertyPathResolverDataProvider(): iterable
+ public static function propertyPathAwarePropertyTypeExtractorDataProvider(): iterable
{
yield [
Book::class,
@@ -141,7 +140,7 @@ class: Chapter::class,
yield [
Chapter::class,
'book.shelf.library.foo',
- PropertyPathResolverException::class,
+ PropertyPathAwarePropertyTypeExtractorException::class,
];
yield [
From fb9f088df46d0d2ae1945b92a9c2b1b05edf0aa6 Mon Sep 17 00:00:00 2001
From: Priyadi Iman Nurcahyo <1102197+priyadi@users.noreply.github.com>
Date: Tue, 24 Sep 2024 09:59:11 +0700
Subject: [PATCH 2/2] 6.4 compat
---
.../Util/PropertyPathAwarePropertyTypeExtractor.php | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/Transformer/ObjectToObjectMetadata/Implementation/Util/PropertyPathAwarePropertyTypeExtractor.php b/src/Transformer/ObjectToObjectMetadata/Implementation/Util/PropertyPathAwarePropertyTypeExtractor.php
index 67c5cdb..004f752 100644
--- a/src/Transformer/ObjectToObjectMetadata/Implementation/Util/PropertyPathAwarePropertyTypeExtractor.php
+++ b/src/Transformer/ObjectToObjectMetadata/Implementation/Util/PropertyPathAwarePropertyTypeExtractor.php
@@ -31,12 +31,13 @@ public function __construct(
/**
* @param array $context
+ * @return TypeInfoType
*/
public function getType(
string $class,
string $property,
array $context = [],
- ): TypeInfoType {
+ ) {
throw new \BadMethodCallException('Not implemented');
}