Skip to content

Commit 4b0c119

Browse files
authored
Merge pull request #11875 from doctrine/3.3.x
Merge 3.3.x up into 3.4.x
2 parents 0ef5610 + daf0f82 commit 4b0c119

File tree

12 files changed

+324
-47
lines changed

12 files changed

+324
-47
lines changed

.github/workflows/coding-standards.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@ on:
2424

2525
jobs:
2626
coding-standards:
27-
uses: "doctrine/.github/.github/workflows/coding-standards.yml@7.2.1"
27+
uses: "doctrine/.github/.github/workflows/coding-standards.yml@7.2.2"

.github/workflows/documentation.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@ on:
1717
jobs:
1818
documentation:
1919
name: "Documentation"
20-
uses: "doctrine/.github/.github/workflows/documentation.yml@7.2.1"
20+
uses: "doctrine/.github/.github/workflows/documentation.yml@7.2.2"

.github/workflows/release-on-milestone-closed.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77

88
jobs:
99
release:
10-
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@7.2.1"
10+
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@7.2.2"
1111
secrets:
1212
GIT_AUTHOR_EMAIL: ${{ secrets.GIT_AUTHOR_EMAIL }}
1313
GIT_AUTHOR_NAME: ${{ secrets.GIT_AUTHOR_NAME }}

src/Internal/Hydration/AbstractHydrator.php

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@
1818
use LogicException;
1919
use ReflectionClass;
2020

21+
use function array_key_exists;
2122
use function array_map;
2223
use function array_merge;
2324
use function count;
2425
use function end;
2526
use function in_array;
2627
use function is_array;
28+
use function ksort;
2729

2830
/**
2931
* Base class for all hydrators. A hydrator is a class that provides some form
@@ -263,6 +265,17 @@ protected function gatherRowData(array $data, array &$id, array &$nonemptyCompon
263265
{
264266
$rowData = ['data' => [], 'newObjects' => []];
265267

268+
foreach ($this->rsm->newObjectMappings as $mapping) {
269+
if (! array_key_exists($mapping['objIndex'], $this->rsm->newObject)) {
270+
$this->rsm->newObject[$mapping['objIndex']] = $mapping['className'];
271+
}
272+
}
273+
274+
foreach ($this->rsm->newObject as $objIndex => $newObject) {
275+
$rowData['newObjects'][$objIndex]['class'] = new ReflectionClass($newObject);
276+
$rowData['newObjects'][$objIndex]['args'] = [];
277+
}
278+
266279
foreach ($data as $key => $value) {
267280
$cacheKeyInfo = $this->hydrateColumnInfo($key);
268281
if ($cacheKeyInfo === null) {
@@ -282,7 +295,6 @@ protected function gatherRowData(array $data, array &$id, array &$nonemptyCompon
282295
$value = $this->buildEnum($value, $cacheKeyInfo['enumType']);
283296
}
284297

285-
$rowData['newObjects'][$objIndex]['class'] = $cacheKeyInfo['class'];
286298
$rowData['newObjects'][$objIndex]['args'][$argIndex] = $value;
287299
break;
288300

@@ -336,21 +348,17 @@ protected function gatherRowData(array $data, array &$id, array &$nonemptyCompon
336348
}
337349
}
338350

339-
foreach ($this->resultSetMapping()->nestedNewObjectArguments as $objIndex => ['ownerIndex' => $ownerIndex, 'argIndex' => $argIndex]) {
340-
if (! isset($rowData['newObjects'][$ownerIndex . ':' . $argIndex])) {
341-
continue;
351+
foreach ($this->resultSetMapping()->nestedNewObjectArguments as ['ownerIndex' => $ownerIndex, 'argIndex' => $argIndex, 'argAlias' => $argAlias]) {
352+
if (array_key_exists($argAlias, $rowData['newObjects'])) {
353+
ksort($rowData['newObjects'][$argAlias]['args']);
354+
$rowData['newObjects'][$ownerIndex]['args'][$argIndex] = $rowData['newObjects'][$argAlias]['class']->newInstanceArgs($rowData['newObjects'][$argAlias]['args']);
355+
unset($rowData['newObjects'][$argAlias]);
342356
}
343-
344-
$newObject = $rowData['newObjects'][$ownerIndex . ':' . $argIndex];
345-
unset($rowData['newObjects'][$ownerIndex . ':' . $argIndex]);
346-
347-
$obj = $newObject['class']->newInstanceArgs($newObject['args']);
348-
349-
$rowData['newObjects'][$ownerIndex]['args'][$argIndex] = $obj;
350357
}
351358

352359
foreach ($rowData['newObjects'] as $objIndex => $newObject) {
353-
$obj = $newObject['class']->newInstanceArgs($newObject['args']);
360+
ksort($rowData['newObjects'][$objIndex]['args']);
361+
$obj = $rowData['newObjects'][$objIndex]['class']->newInstanceArgs($rowData['newObjects'][$objIndex]['args']);
354362

355363
$rowData['newObjects'][$objIndex]['obj'] = $obj;
356364
}
@@ -454,7 +462,6 @@ protected function hydrateColumnInfo(string $key): array|null
454462
'type' => Type::getType($this->rsm->typeMappings[$key]),
455463
'argIndex' => $mapping['argIndex'],
456464
'objIndex' => $mapping['objIndex'],
457-
'class' => new ReflectionClass($mapping['className']),
458465
'enumType' => $this->rsm->enumMappings[$key] ?? null,
459466
];
460467

src/Query/AST/NewObjectExpression.php

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,28 @@
66

77
use Doctrine\ORM\Query\SqlWalker;
88

9+
use function func_get_arg;
10+
use function func_num_args;
11+
912
/**
1013
* NewObjectExpression ::= "NEW" IdentificationVariable "(" NewObjectArg {"," NewObjectArg}* ")"
1114
*
1215
* @link www.doctrine-project.org
1316
*/
1417
class NewObjectExpression extends Node
1518
{
16-
/** @param mixed[] $args */
19+
/**
20+
* @param class-string $className
21+
* @param mixed[] $args
22+
*/
1723
public function __construct(public string $className, public array $args)
1824
{
1925
}
2026

21-
public function dispatch(SqlWalker $walker): string
27+
public function dispatch(SqlWalker $walker /*, string|null $parentAlias = null */): string
2228
{
23-
return $walker->walkNewObject($this);
29+
$parentAlias = func_num_args() > 1 ? func_get_arg(1) : null;
30+
31+
return $walker->walkNewObject($this, $parentAlias);
2432
}
2533
}

src/Query/Parser.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1767,6 +1767,7 @@ public function NewObjectExpression(): AST\NewObjectExpression
17671767
$useNamedArguments = true;
17681768
}
17691769

1770+
/** @var class-string $className */
17701771
$className = $this->AbstractSchemaName(); // note that this is not yet validated
17711772
$token = $this->lexer->token;
17721773

@@ -1854,7 +1855,11 @@ public function NewObjectArg(string|null &$fieldAlias = null): mixed
18541855

18551856
if ($this->lexer->isNextToken(TokenType::T_AS)) {
18561857
$this->match(TokenType::T_AS);
1857-
$fieldAlias = $this->AliasIdentificationVariable();
1858+
$this->match(TokenType::T_IDENTIFIER);
1859+
1860+
assert($this->lexer->token !== null);
1861+
1862+
$fieldAlias = $this->lexer->token->value;
18581863
}
18591864

18601865
return $expression;

src/Query/ResultSetMapping.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,13 @@ class ResultSetMapping
159159
*/
160160
public array $newObjectMappings = [];
161161

162+
/**
163+
* Maps object Ids in the result set to classnames.
164+
*
165+
* @phpstan-var array<string|int, class-string>
166+
*/
167+
public array $newObject = [];
168+
162169
/**
163170
* Maps last argument for new objects in order to initiate object construction
164171
*

src/Query/SqlWalker.php

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,8 @@
2424
use function array_keys;
2525
use function array_map;
2626
use function array_merge;
27-
use function array_pop;
2827
use function assert;
2928
use function count;
30-
use function end;
3129
use function implode;
3230
use function in_array;
3331
use function is_array;
@@ -84,13 +82,6 @@ class SqlWalker
8482
*/
8583
private int $newObjectCounter = 0;
8684

87-
/**
88-
* Contains nesting levels of new objects arguments
89-
*
90-
* @phpstan-var array<int, array{0: string|int, 1: int}>
91-
*/
92-
private array $newObjectStack = [];
93-
9485
private readonly EntityManagerInterface $em;
9586
private readonly Connection $conn;
9687

@@ -1507,14 +1498,7 @@ public function walkParenthesisExpression(AST\ParenthesisExpression $parenthesis
15071498
public function walkNewObject(AST\NewObjectExpression $newObjectExpression, string|null $newObjectResultAlias = null): string
15081499
{
15091500
$sqlSelectExpressions = [];
1510-
$objOwner = $objOwnerIdx = null;
1511-
1512-
if ($this->newObjectStack !== []) {
1513-
[$objOwner, $objOwnerIdx] = end($this->newObjectStack);
1514-
$objIndex = $objOwner . ':' . $objOwnerIdx;
1515-
} else {
1516-
$objIndex = $newObjectResultAlias ?: $this->newObjectCounter++;
1517-
}
1501+
$objIndex = $newObjectResultAlias ?: $this->newObjectCounter++;
15181502

15191503
foreach ($newObjectExpression->args as $argIndex => $e) {
15201504
$resultAlias = $this->scalarResultCounter++;
@@ -1523,10 +1507,8 @@ public function walkNewObject(AST\NewObjectExpression $newObjectExpression, stri
15231507

15241508
switch (true) {
15251509
case $e instanceof AST\NewObjectExpression:
1526-
$this->newObjectStack[] = [$objIndex, $argIndex];
1527-
$sqlSelectExpressions[] = $e->dispatch($this);
1528-
array_pop($this->newObjectStack);
1529-
$this->rsm->nestedNewObjectArguments[$columnAlias] = ['ownerIndex' => $objIndex, 'argIndex' => $argIndex];
1510+
$sqlSelectExpressions[] = $e->dispatch($this, $columnAlias);
1511+
$this->rsm->nestedNewObjectArguments[$columnAlias] = ['ownerIndex' => $objIndex, 'argIndex' => $argIndex, 'argAlias' => $columnAlias];
15301512
break;
15311513

15321514
case $e instanceof AST\Subselect:
@@ -1576,12 +1558,13 @@ public function walkNewObject(AST\NewObjectExpression $newObjectExpression, stri
15761558
$this->rsm->addScalarResult($columnAlias, $resultAlias, $fieldType);
15771559

15781560
$this->rsm->newObjectMappings[$columnAlias] = [
1579-
'className' => $newObjectExpression->className,
15801561
'objIndex' => $objIndex,
15811562
'argIndex' => $argIndex,
15821563
];
15831564
}
15841565

1566+
$this->rsm->newObject[$objIndex] = $newObjectExpression->className;
1567+
15851568
return implode(', ', $sqlSelectExpressions);
15861569
}
15871570

tests/Tests/Models/CMS/CmsAddressDTO.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
class CmsAddressDTO
88
{
9-
public function __construct(public string|null $country = null, public string|null $city = null, public string|null $zip = null, public CmsAddressDTO|string|null $address = null)
9+
public function __construct(public string|null $country = null, public string|null $city = null, public string|null $zip = null, public string|null $address = null, public CmsDumbDTO|null $other = null)
1010
{
1111
}
1212
}

tests/Tests/Models/CMS/CmsDumbDTO.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Tests\Models\CMS;
6+
7+
class CmsDumbDTO
8+
{
9+
public function __construct(
10+
public mixed $val1 = null,
11+
public mixed $val2 = null,
12+
public mixed $val3 = null,
13+
public mixed $val4 = null,
14+
public mixed $val5 = null,
15+
) {
16+
}
17+
}

0 commit comments

Comments
 (0)