From 72695a89c3b1147b89b46b90563ad4e7e6d68377 Mon Sep 17 00:00:00 2001 From: eltharin Date: Fri, 14 Feb 2025 12:11:18 +0100 Subject: [PATCH] add order for args for nested dtos --- src/Internal/Hydration/AbstractHydrator.php | 4 +- tests/Tests/Models/CMS/CmsAddressDTO.php | 2 +- tests/Tests/Models/CMS/CmsDumbDTO.php | 17 ++ .../Tests/ORM/Functional/NewOperatorTest.php | 186 +++++++++++++++++- 4 files changed, 206 insertions(+), 3 deletions(-) create mode 100644 tests/Tests/Models/CMS/CmsDumbDTO.php diff --git a/src/Internal/Hydration/AbstractHydrator.php b/src/Internal/Hydration/AbstractHydrator.php index 0a44d3a02b5..bbd20d9087f 100644 --- a/src/Internal/Hydration/AbstractHydrator.php +++ b/src/Internal/Hydration/AbstractHydrator.php @@ -24,6 +24,7 @@ use function end; use function in_array; use function is_array; +use function ksort; /** * Base class for all hydrators. A hydrator is a class that provides some form @@ -343,13 +344,14 @@ protected function gatherRowData(array $data, array &$id, array &$nonemptyCompon $newObject = $rowData['newObjects'][$ownerIndex . ':' . $argIndex]; unset($rowData['newObjects'][$ownerIndex . ':' . $argIndex]); - + ksort($newObject['args']); $obj = $newObject['class']->newInstanceArgs($newObject['args']); $rowData['newObjects'][$ownerIndex]['args'][$argIndex] = $obj; } foreach ($rowData['newObjects'] as $objIndex => $newObject) { + ksort($newObject['args']); $obj = $newObject['class']->newInstanceArgs($newObject['args']); $rowData['newObjects'][$objIndex]['obj'] = $obj; diff --git a/tests/Tests/Models/CMS/CmsAddressDTO.php b/tests/Tests/Models/CMS/CmsAddressDTO.php index 502644ed25e..c555645d593 100644 --- a/tests/Tests/Models/CMS/CmsAddressDTO.php +++ b/tests/Tests/Models/CMS/CmsAddressDTO.php @@ -6,7 +6,7 @@ class CmsAddressDTO { - public function __construct(public string|null $country = null, public string|null $city = null, public string|null $zip = null, public CmsAddressDTO|string|null $address = null) + public function __construct(public string|null $country = null, public string|null $city = null, public string|null $zip = null, public ?CmsDumbDTO $other = null) { } } diff --git a/tests/Tests/Models/CMS/CmsDumbDTO.php b/tests/Tests/Models/CMS/CmsDumbDTO.php new file mode 100644 index 00000000000..c4feb7ba5f8 --- /dev/null +++ b/tests/Tests/Models/CMS/CmsDumbDTO.php @@ -0,0 +1,17 @@ +fixtures[1]->address->country, $result[1]['user']->address->country); self::assertSame($this->fixtures[2]->address->country, $result[2]['user']->address->country); + self::assertInstanceOf(CmsDumbDTO::class, $result[0]['user']->address->other); + self::assertInstanceOf(CmsDumbDTO::class, $result[1]['user']->address->other); + self::assertInstanceOf(CmsDumbDTO::class, $result[2]['user']->address->other); + + self::assertSame($this->fixtures[0]->address->country, $result[0]['user']->address->other->val1); + self::assertSame($this->fixtures[1]->address->country, $result[1]['user']->address->other->val1); + self::assertSame($this->fixtures[2]->address->country, $result[2]['user']->address->other->val1); + + self::assertSame($this->fixtures[0]->address->city, $result[0]['user']->address->other->val2); + self::assertSame($this->fixtures[1]->address->city, $result[1]['user']->address->other->val2); + self::assertSame($this->fixtures[2]->address->city, $result[2]['user']->address->other->val2); + + self::assertSame($this->fixtures[0]->status, $result[0]['status']); + self::assertSame($this->fixtures[1]->status, $result[1]['status']); + self::assertSame($this->fixtures[2]->status, $result[2]['status']); + + self::assertSame($this->fixtures[0]->username, $result[0]['cmsUserUsername']); + self::assertSame($this->fixtures[1]->username, $result[1]['cmsUserUsername']); + self::assertSame($this->fixtures[2]->username, $result[2]['cmsUserUsername']); + } + + public function testShouldSupportNestedNewOperatorsWithDtoFirst(): void + { + $dql = ' + SELECT + new CmsUserDTO( + u.name, + e.email, + new CmsAddressDTO( + a.country, + a.city, + a.zip + ), + 555812452 + ) as user, + u.status, + u.username as cmsUserUsername + FROM + Doctrine\Tests\Models\CMS\CmsUser u + JOIN + u.email e + JOIN + u.address a + ORDER BY + u.name'; + + $query = $this->getEntityManager()->createQuery($dql); + $result = $query->getResult(); + + self::assertCount(3, $result); + + self::assertInstanceOf(CmsUserDTO::class, $result[0]['user']); + self::assertInstanceOf(CmsUserDTO::class, $result[1]['user']); + self::assertInstanceOf(CmsUserDTO::class, $result[2]['user']); + + self::assertInstanceOf(CmsAddressDTO::class, $result[0]['user']->address); + self::assertInstanceOf(CmsAddressDTO::class, $result[1]['user']->address); + self::assertInstanceOf(CmsAddressDTO::class, $result[2]['user']->address); + + self::assertSame($this->fixtures[0]->name, $result[0]['user']->name); + self::assertSame($this->fixtures[1]->name, $result[1]['user']->name); + self::assertSame($this->fixtures[2]->name, $result[2]['user']->name); + + self::assertSame($this->fixtures[0]->email->email, $result[0]['user']->email); + self::assertSame($this->fixtures[1]->email->email, $result[1]['user']->email); + self::assertSame($this->fixtures[2]->email->email, $result[2]['user']->email); + + self::assertSame($this->fixtures[0]->address->city, $result[0]['user']->address->city); + self::assertSame($this->fixtures[1]->address->city, $result[1]['user']->address->city); + self::assertSame($this->fixtures[2]->address->city, $result[2]['user']->address->city); + + self::assertSame($this->fixtures[0]->address->country, $result[0]['user']->address->country); + self::assertSame($this->fixtures[1]->address->country, $result[1]['user']->address->country); + self::assertSame($this->fixtures[2]->address->country, $result[2]['user']->address->country); + + self::assertSame(555812452, $result[0]['user']->phonenumbers); + self::assertSame(555812452, $result[1]['user']->phonenumbers); + self::assertSame(555812452, $result[2]['user']->phonenumbers); + self::assertSame($this->fixtures[0]->status, $result[0]['status']); self::assertSame($this->fixtures[1]->status, $result[1]['status']); self::assertSame($this->fixtures[2]->status, $result[2]['status']); @@ -1159,6 +1239,110 @@ public function testNamedArguments(): void self::assertSame($this->fixtures[2]->username, $result[2]['cmsUserUsername']); } + public function testShouldSupportNestedNewOperatorsWithNestedDtoNotLast(): void + { + $dql = ' + SELECT + new CmsUserDTO( + u.name, + e.email, + new CmsAddressDTO( + a.country, + a.city, + a.zip, + new CmsDumbDTO( + a.country, + a.city, + new CmsDumbDTO( + a.zip, + 456 + ), + a.zip + ) + ), + 555812452 + ) as user, + u.status, + u.username as cmsUserUsername + FROM + Doctrine\Tests\Models\CMS\CmsUser u + JOIN + u.email e + JOIN + u.address a + ORDER BY + u.name'; + + $query = $this->getEntityManager()->createQuery($dql); + $result = $query->getResult(); + + self::assertCount(3, $result); + + self::assertInstanceOf(CmsUserDTO::class, $result[0]['user']); + self::assertInstanceOf(CmsUserDTO::class, $result[1]['user']); + self::assertInstanceOf(CmsUserDTO::class, $result[2]['user']); + + self::assertSame($this->fixtures[0]->name, $result[0]['user']->name); + self::assertSame($this->fixtures[1]->name, $result[1]['user']->name); + self::assertSame($this->fixtures[2]->name, $result[2]['user']->name); + + self::assertSame($this->fixtures[0]->email->email, $result[0]['user']->email); + self::assertSame($this->fixtures[1]->email->email, $result[1]['user']->email); + self::assertSame($this->fixtures[2]->email->email, $result[2]['user']->email); + + self::assertInstanceOf(CmsAddressDTO::class, $result[0]['user']->address); + self::assertInstanceOf(CmsAddressDTO::class, $result[1]['user']->address); + self::assertInstanceOf(CmsAddressDTO::class, $result[2]['user']->address); + + self::assertSame($this->fixtures[0]->address->country, $result[0]['user']->address->country); + self::assertSame($this->fixtures[1]->address->country, $result[1]['user']->address->country); + self::assertSame($this->fixtures[2]->address->country, $result[2]['user']->address->country); + + self::assertSame($this->fixtures[2]->address->city, $result[2]['user']->address->city); + self::assertSame($this->fixtures[0]->address->city, $result[0]['user']->address->city); + self::assertSame($this->fixtures[1]->address->city, $result[1]['user']->address->city); + + self::assertInstanceOf(CmsDumbDTO::class, $result[0]['user']->address->other); + self::assertInstanceOf(CmsDumbDTO::class, $result[1]['user']->address->other); + self::assertInstanceOf(CmsDumbDTO::class, $result[2]['user']->address->other); + + self::assertSame($this->fixtures[0]->address->country, $result[0]['user']->address->other->val1); + self::assertSame($this->fixtures[1]->address->country, $result[1]['user']->address->other->val1); + self::assertSame($this->fixtures[2]->address->country, $result[2]['user']->address->other->val1); + + self::assertSame($this->fixtures[0]->address->city, $result[0]['user']->address->other->val2); + self::assertSame($this->fixtures[1]->address->city, $result[1]['user']->address->other->val2); + self::assertSame($this->fixtures[2]->address->city, $result[2]['user']->address->other->val2); + + self::assertInstanceOf(CmsDumbDTO::class, $result[0]['user']->address->other->val3); + self::assertInstanceOf(CmsDumbDTO::class, $result[1]['user']->address->other->val3); + self::assertInstanceOf(CmsDumbDTO::class, $result[2]['user']->address->other->val3); + + self::assertSame($this->fixtures[0]->address->zip, $result[0]['user']->address->other->val3->val1); + self::assertSame($this->fixtures[1]->address->zip, $result[1]['user']->address->other->val3->val1); + self::assertSame($this->fixtures[2]->address->zip, $result[2]['user']->address->other->val3->val1); + + self::assertSame(456, $result[0]['user']->address->other->val3->val2); + self::assertSame(456, $result[1]['user']->address->other->val3->val2); + self::assertSame(456, $result[2]['user']->address->other->val3->val2); + + self::assertSame($this->fixtures[0]->address->zip, $result[0]['user']->address->other->val4); + self::assertSame($this->fixtures[1]->address->zip, $result[1]['user']->address->other->val4); + self::assertSame($this->fixtures[2]->address->zip, $result[2]['user']->address->other->val4); + + self::assertSame(555812452, $result[0]['user']->phonenumbers); + self::assertSame(555812452, $result[1]['user']->phonenumbers); + self::assertSame(555812452, $result[2]['user']->phonenumbers); + + self::assertSame($this->fixtures[0]->status, $result[0]['status']); + self::assertSame($this->fixtures[1]->status, $result[1]['status']); + self::assertSame($this->fixtures[2]->status, $result[2]['status']); + + self::assertSame($this->fixtures[0]->username, $result[0]['cmsUserUsername']); + self::assertSame($this->fixtures[1]->username, $result[1]['cmsUserUsername']); + self::assertSame($this->fixtures[2]->username, $result[2]['cmsUserUsername']); + } + public function testVariadicArgument(): void { $dql = <<<'SQL'