diff --git a/composer.json b/composer.json index b9b142a14..5f7a5f662 100644 --- a/composer.json +++ b/composer.json @@ -33,6 +33,7 @@ "doctrine/orm": "~2.1", "jackalope/jackalope-doctrine-dbal": "^1.1.5", "doctrine/phpcr-odm": "^1.3|^2.0", + "ocramius/proxy-manager": "^2.0", "psr/container": "^1.0", "symfony/dependency-injection": "^3.0|^4.0", "symfony/yaml": "^3.3|^4.0", diff --git a/src/EventDispatcher/Subscriber/DoctrineProxySubscriber.php b/src/EventDispatcher/Subscriber/DoctrineProxySubscriber.php index 3e343a4fc..2de700d7d 100644 --- a/src/EventDispatcher/Subscriber/DoctrineProxySubscriber.php +++ b/src/EventDispatcher/Subscriber/DoctrineProxySubscriber.php @@ -8,10 +8,10 @@ use Doctrine\ODM\MongoDB\PersistentCollection as MongoDBPersistentCollection; use Doctrine\ODM\PHPCR\PersistentCollection as PHPCRPersistentCollection; use Doctrine\ORM\PersistentCollection; -use Doctrine\ORM\Proxy\Proxy as ORMProxy; use JMS\Serializer\EventDispatcher\EventDispatcherInterface; use JMS\Serializer\EventDispatcher\EventSubscriberInterface; use JMS\Serializer\EventDispatcher\PreSerializeEvent; +use ProxyManager\Proxy\LazyLoadingInterface; final class DoctrineProxySubscriber implements EventSubscriberInterface { @@ -53,7 +53,7 @@ public function onPreSerialize(PreSerializeEvent $event): void } if (($this->skipVirtualTypeInit && $virtualType) || - (!$object instanceof Proxy && !$object instanceof ORMProxy) + (!$object instanceof Proxy && !$object instanceof LazyLoadingInterface) ) { return; } @@ -68,7 +68,11 @@ public function onPreSerialize(PreSerializeEvent $event): void } } - $object->__load(); + if ($object instanceof LazyLoadingInterface) { + $object->initializeProxy(); + } else { + $object->__load(); + } if (!$virtualType) { $event->setType(get_parent_class($object), $type['params']); @@ -111,6 +115,7 @@ public static function getSubscribedEvents() ['event' => 'serializer.pre_serialize', 'method' => 'onPreSerialize', 'interface' => MongoDBPersistentCollection::class], ['event' => 'serializer.pre_serialize', 'method' => 'onPreSerialize', 'interface' => PHPCRPersistentCollection::class], ['event' => 'serializer.pre_serialize', 'method' => 'onPreSerialize', 'interface' => Proxy::class], + ['event' => 'serializer.pre_serialize', 'method' => 'onPreSerialize', 'interface' => LazyLoadingInterface::class], ]; } } diff --git a/tests/Fixtures/SimpleObjectLazyLoading.php b/tests/Fixtures/SimpleObjectLazyLoading.php new file mode 100644 index 000000000..369c43757 --- /dev/null +++ b/tests/Fixtures/SimpleObjectLazyLoading.php @@ -0,0 +1,69 @@ +__isInitialized__) { + $this->camelCase = 'proxy-boo'; + $this->__isInitialized__ = true; + } + } + + public function __isInitialized() + { + return $this->__isInitialized__; + } + + /** + * {@inheritDoc} + */ + public function setProxyInitializer(?Closure $initializer = null) + { + $this->initializer = $initializer; + } + + /** + * {@inheritDoc} + */ + public function getProxyInitializer(): ?Closure + { + return $this->initializer; + } + + /** + * {@inheritDoc} + */ + public function initializeProxy(): bool + { + if (!$this->__isInitialized__) { + $this->camelCase = 'proxy-boo'; + $this->__isInitialized__ = true; + + return !$this->initializer || call_user_func($this->initializer); + } + + return true; + } + + /** + * {@inheritDoc} + */ + public function isProxyInitialized(): bool + { + return $this->__isInitialized__; + } +} diff --git a/tests/Serializer/EventDispatcher/Subscriber/DoctrineProxySubscriberTest.php b/tests/Serializer/EventDispatcher/Subscriber/DoctrineProxySubscriberTest.php index 00c9e8b54..040632dd4 100644 --- a/tests/Serializer/EventDispatcher/Subscriber/DoctrineProxySubscriberTest.php +++ b/tests/Serializer/EventDispatcher/Subscriber/DoctrineProxySubscriberTest.php @@ -11,6 +11,7 @@ use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Tests\Fixtures\ExclusionStrategy\AlwaysExcludeExclusionStrategy; use JMS\Serializer\Tests\Fixtures\SimpleObject; +use JMS\Serializer\Tests\Fixtures\SimpleObjectLazyLoading; use JMS\Serializer\Tests\Fixtures\SimpleObjectProxy; use Metadata\MetadataFactoryInterface; use PHPUnit\Framework\TestCase; @@ -146,6 +147,15 @@ public function testOnPreSerializeMaintainsParams() self::assertSame(['name' => SimpleObject::class, 'params' => ['baz']], $event->getType()); } + public function testRewritesLazyLoadingClassName() + { + $event = $this->createEvent($obj = new SimpleObjectLazyLoading('a', 'b'), ['name' => get_class($obj), 'params' => []]); + $this->subscriber->onPreSerialize($event); + + self::assertEquals(['name' => get_parent_class($obj), 'params' => []], $event->getType()); + self::assertTrue($obj->__isInitialized()); + } + protected function setUp(): void { $this->subscriber = new DoctrineProxySubscriber();