diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b87922..aaeab35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +1.4.1 +===== + +* (improvement) Avoid using deprecated Doctrine internals when resolving class names. + + 1.4.0 ===== diff --git a/composer.json b/composer.json index 09352ac..6c5e796 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,7 @@ "require-dev": { "21torr/janus": "^1.5.1", "bamarni/composer-bin-plugin": "^1.8.2", - "doctrine/common": "^3.5", + "doctrine/orm": "^3.0", "phpunit/phpunit": "^12.2.5", "roave/security-advisories": "dev-latest" }, diff --git a/src/Normalizer/SimpleNormalizer.php b/src/Normalizer/SimpleNormalizer.php index 61c1d70..6bd02da 100644 --- a/src/Normalizer/SimpleNormalizer.php +++ b/src/Normalizer/SimpleNormalizer.php @@ -2,7 +2,8 @@ namespace Torr\SimpleNormalizer\Normalizer; -use Doctrine\Common\Util\ClassUtils; +use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Mapping\ClassMetadataFactory; use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; use Symfony\Component\DependencyInjection\ServiceLocator; use Torr\SimpleNormalizer\Exception\ObjectTypeNotSupportedException; @@ -23,6 +24,8 @@ */ class SimpleNormalizer { + private readonly ?ClassMetadataFactory $doctrineMetadata; + /** * @param ServiceLocator $objectNormalizers */ @@ -30,7 +33,11 @@ public function __construct ( private readonly ServiceLocator $objectNormalizers, private readonly bool $isDebug = false, private readonly ?ValidJsonVerifier $validJsonVerifier = null, - ) {} + ?EntityManagerInterface $entityManager = null, + ) + { + $this->doctrineMetadata = $entityManager?->getMetadataFactory(); + } /** */ @@ -104,12 +111,7 @@ private function recursiveNormalize (mixed $value, array $context = []) : mixed try { - $className = $value::class; - - if (class_exists(ClassUtils::class)) - { - $className = ClassUtils::getRealClass($className); - } + $className = $this->normalizeClassName($value::class); $normalizer = $this->objectNormalizers->get($className); \assert($normalizer instanceof SimpleObjectNormalizerInterface); @@ -131,6 +133,26 @@ private function recursiveNormalize (mixed $value, array $context = []) : mixed )); } + /** + * Normalizes the class name + * + * @param class-string $className + * + * @return class-string + */ + private function normalizeClassName (string $className) : string + { + // if there is no doctrine, just return + if (null === $this->doctrineMetadata) + { + return $className; + } + + return $this->doctrineMetadata->hasMetadataFor($className) + ? $this->doctrineMetadata->getMetadataFor($className)->getName() + : $className; + } + /** * The actual customized normalization logic for arrays, that recursively normalizes the value. * It must never call one of the public methods above and just normalizes the value. diff --git a/tests/Fixture/DummyVONormalizer.php b/tests/Fixture/DummyVONormalizer.php new file mode 100644 index 0000000..259c650 --- /dev/null +++ b/tests/Fixture/DummyVONormalizer.php @@ -0,0 +1,26 @@ +returnValue; + } + + public static function getNormalizedType () : string + { + return DummyVO::class; + } +} diff --git a/tests/Normalizer/SimpleNormalizerTest.php b/tests/Normalizer/SimpleNormalizerTest.php index d2043b3..5986dd5 100644 --- a/tests/Normalizer/SimpleNormalizerTest.php +++ b/tests/Normalizer/SimpleNormalizerTest.php @@ -2,13 +2,16 @@ namespace Tests\Torr\SimpleNormalizer\Normalizer; +use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\ORM\Mapping\ClassMetadataFactory; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\DependencyInjection\ServiceLocator; use Tests\Torr\SimpleNormalizer\Fixture\DummyVO; +use Tests\Torr\SimpleNormalizer\Fixture\DummyVONormalizer; use Torr\SimpleNormalizer\Exception\IncompleteNormalizationException; use Torr\SimpleNormalizer\Normalizer\SimpleNormalizer; -use Torr\SimpleNormalizer\Normalizer\SimpleObjectNormalizerInterface; use Torr\SimpleNormalizer\Normalizer\Validator\ValidJsonVerifier; /** @@ -124,27 +127,103 @@ public function testInvalidNestedNormalizer () : void ]); } + /** + */ + public function testWithoutEntityManager () : void + { + $locator = $this->createMock(ServiceLocator::class); + + $locator->expects(self::once()) + ->method("get") + ->with(DummyVO::class) + ->willReturn(new DummyVONormalizer(5)); + + $normalizer = new SimpleNormalizer( + objectNormalizers: $locator, + isDebug: true, + validJsonVerifier: new ValidJsonVerifier(), + ); + + $normalizer->normalize(new DummyVO(5)); + } + + /** + */ + public function testWithEntityManagerButNoMapping () : void + { + $metadataFactory = $this->createMock(ClassMetadataFactory::class); + $metadataFactory + ->expects(self::once()) + ->method("hasMetadataFor") + ->with(DummyVO::class) + ->willReturn(false); + + $entityManager = $this->createMock(EntityManagerInterface::class); + $entityManager->method("getMetadataFactory")->willReturn($metadataFactory); + + $locator = $this->createMock(ServiceLocator::class); + + $locator->expects(self::once()) + ->method("get") + ->with(DummyVO::class) + ->willReturn(new DummyVONormalizer(5)); + + $normalizer = new SimpleNormalizer( + objectNormalizers: $locator, + isDebug: true, + validJsonVerifier: new ValidJsonVerifier(), + entityManager: $entityManager, + ); + + $normalizer->normalize(new DummyVO(5)); + } + + /** + */ + public function testWithEntityManagerWithMapping () : void + { + $classMetaData = new ClassMetadata("SomeClass"); + + $metadataFactory = $this->createMock(ClassMetadataFactory::class); + $metadataFactory + ->expects(self::once()) + ->method("hasMetadataFor") + ->with(DummyVO::class) + ->willReturn(true); + + $metadataFactory + ->expects(self::once()) + ->method("getMetadataFor") + ->with(DummyVO::class) + ->willReturn($classMetaData); + + $entityManager = $this->createMock(EntityManagerInterface::class); + $entityManager->method("getMetadataFactory")->willReturn($metadataFactory); + + $locator = $this->createMock(ServiceLocator::class); + + $locator->expects(self::once()) + ->method("get") + ->with("SomeClass") + ->willReturn(new DummyVONormalizer(5)); + + $normalizer = new SimpleNormalizer( + objectNormalizers: $locator, + isDebug: true, + validJsonVerifier: new ValidJsonVerifier(), + entityManager: $entityManager, + ); + + $normalizer->normalize(new DummyVO(5)); + } + /** * @return ServiceLocator */ private function createNormalizerObjectNormalizers (mixed $returnValue) : ServiceLocator { return new ServiceLocator([ - DummyVO::class => static fn () => new readonly class($returnValue) implements SimpleObjectNormalizerInterface { - public function __construct ( - private mixed $returnValue, - ) {} - - public function normalize (object $value, array $context, SimpleNormalizer $normalizer) : mixed - { - return $this->returnValue; - } - - public static function getNormalizedType () : string - { - return DummyVO::class; - } - }, + DummyVO::class => static fn () => new DummyVONormalizer($returnValue), ]); } }