From a1cfe9a517ec78f257f880da88bd07e711d63af5 Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Sun, 26 Dec 2021 01:17:40 +0100 Subject: [PATCH 1/2] Add a test to check proxy initialization --- .../Tests/Functional/Ticket/GH2349Test.php | 36 ++++++++++++++++++ tests/Documents74/GH2349Customer.php | 37 +++++++++++++++++++ tests/Documents74/GH2349Order.php | 26 +++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 tests/Doctrine/ODM/MongoDB/Tests/Functional/Ticket/GH2349Test.php create mode 100644 tests/Documents74/GH2349Customer.php create mode 100644 tests/Documents74/GH2349Order.php diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Functional/Ticket/GH2349Test.php b/tests/Doctrine/ODM/MongoDB/Tests/Functional/Ticket/GH2349Test.php new file mode 100644 index 0000000000..e7ab9acf63 --- /dev/null +++ b/tests/Doctrine/ODM/MongoDB/Tests/Functional/Ticket/GH2349Test.php @@ -0,0 +1,36 @@ +dm->persist($customer); + $this->dm->persist($order); + $this->dm->flush(); + $this->dm->clear(); + + $orderId = GH2349Order::ID; + + $order = $this->dm->getRepository(GH2349Order::class)->find($orderId); + + // Fetch a list of Customers from the DB. Any customer object that was referenced in the above order is still + // a proxy object, however it will not have the defaults set for the un-managed $domainEvents property. + $customers = $this->dm->getRepository(GH2349Customer::class)->findAll(); + + foreach ($customers as $customer) { + self::assertSame([], $customer->getEvents()); // This would trigger an error if unmapped properties are unset + } + } +} diff --git a/tests/Documents74/GH2349Customer.php b/tests/Documents74/GH2349Customer.php new file mode 100644 index 0000000000..0e9a50cf6b --- /dev/null +++ b/tests/Documents74/GH2349Customer.php @@ -0,0 +1,37 @@ +id = self::ID; + $this->name = $name; + } + + public function doSomeUpdate(): void + { + $this->domainEvents[] = 'a new event!'; + } + + public function getEvents(): array + { + return $this->domainEvents; + } +} diff --git a/tests/Documents74/GH2349Order.php b/tests/Documents74/GH2349Order.php new file mode 100644 index 0000000000..fa1d5ce581 --- /dev/null +++ b/tests/Documents74/GH2349Order.php @@ -0,0 +1,26 @@ +id = (string) new ObjectId(self::ID); + $this->customer = $customer; + } +} From f6cc0c177381329167f9d9742e2fa0bec23ee3ad Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Thu, 3 Mar 2022 11:27:53 +0100 Subject: [PATCH 2/2] Skip unmapped fields when generating proxies --- .../Proxy/Factory/StaticProxyFactory.php | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/lib/Doctrine/ODM/MongoDB/Proxy/Factory/StaticProxyFactory.php b/lib/Doctrine/ODM/MongoDB/Proxy/Factory/StaticProxyFactory.php index 9d5e56938b..3dabf94ef0 100644 --- a/lib/Doctrine/ODM/MongoDB/Proxy/Factory/StaticProxyFactory.php +++ b/lib/Doctrine/ODM/MongoDB/Proxy/Factory/StaticProxyFactory.php @@ -14,9 +14,11 @@ use Doctrine\Persistence\NotifyPropertyChanged; use ProxyManager\Factory\LazyLoadingGhostFactory; use ProxyManager\Proxy\GhostObjectInterface; +use ReflectionClass; use ReflectionProperty; use function array_filter; +use function array_merge; use function count; /** @@ -130,6 +132,19 @@ private function createInitializer( * @return array */ private function skippedFieldsFqns(ClassMetadata $metadata): array + { + $skippedIdFieldsFqns = $this->getIdFieldsFqns($metadata); + $skippedNonMappedFieldsFqns = $this->getUnmappedPropertyFqns($metadata); + + return array_merge($skippedIdFieldsFqns, $skippedNonMappedFieldsFqns); + } + + /** + * @param ClassMetadata $metadata + * + * @return array + */ + private function getIdFieldsFqns(ClassMetadata $metadata): array { $idFieldFqcns = []; @@ -140,6 +155,30 @@ private function skippedFieldsFqns(ClassMetadata $metadata): array return $idFieldFqcns; } + /** + * @param ClassMetadata $metadata + * + * @return array + */ + private function getUnmappedPropertyFqns(ClassMetadata $metadata): array + { + $nonMappedFieldFqcns = []; + + $reflectionClass = new ReflectionClass($metadata->getName()); + + foreach ($reflectionClass->getProperties() as $property) { + $propertyName = $property->getName(); + + if ($metadata->hasField($propertyName)) { + continue; + } + + $nonMappedFieldFqcns[] = $this->propertyFqcn($property); + } + + return $nonMappedFieldFqcns; + } + private function propertyFqcn(ReflectionProperty $property): string { if ($property->isPrivate()) {