Skip to content

Commit

Permalink
fix bugs
Browse files Browse the repository at this point in the history
nested dto are not in good argument order
dto with only dto does'nt work
  • Loading branch information
eltharin committed Feb 18, 2025
1 parent c9557c5 commit 13469f6
Show file tree
Hide file tree
Showing 8 changed files with 312 additions and 39 deletions.
34 changes: 21 additions & 13 deletions src/Internal/Hydration/AbstractHydrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@
use LogicException;
use ReflectionClass;

use function array_key_exists;
use function array_map;
use function array_merge;
use function count;
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
Expand Down Expand Up @@ -263,6 +265,15 @@ protected function gatherRowData(array $data, array &$id, array &$nonemptyCompon
{
$rowData = ['data' => [], 'newObjects' => []];

foreach ($this->rsm->newObjectMappings as $mapping) {
$this->rsm->newObject[$mapping['objIndex']] = ['className' => $mapping['className']];
}

foreach ($this->rsm->newObject as $objIndex => $newObject) {
$rowData['newObjects'][$objIndex]['class'] = new ReflectionClass($newObject['className']);
$rowData['newObjects'][$objIndex]['args'] = [];
}

foreach ($data as $key => $value) {
$cacheKeyInfo = $this->hydrateColumnInfo($key);
if ($cacheKeyInfo === null) {
Expand All @@ -282,7 +293,6 @@ protected function gatherRowData(array $data, array &$id, array &$nonemptyCompon
$value = $this->buildEnum($value, $cacheKeyInfo['enumType']);
}

$rowData['newObjects'][$objIndex]['class'] = $cacheKeyInfo['class'];
$rowData['newObjects'][$objIndex]['args'][$argIndex] = $value;
break;

Expand Down Expand Up @@ -336,21 +346,20 @@ protected function gatherRowData(array $data, array &$id, array &$nonemptyCompon
}
}

foreach ($this->resultSetMapping()->nestedNewObjectArguments as $objIndex => ['ownerIndex' => $ownerIndex, 'argIndex' => $argIndex]) {
if (! isset($rowData['newObjects'][$ownerIndex . ':' . $argIndex])) {
continue;
$nestedEntities = [];
foreach ($this->resultSetMapping()->nestedNewObjectArguments as ['ownerIndex' => $ownerIndex, 'argIndex' => $argIndex, 'argAlias' => $argAlias]) {

Check warning on line 350 in src/Internal/Hydration/AbstractHydrator.php

View workflow job for this annotation

GitHub Actions / coding-standards / Coding Standards (PHP: 8.4)

Line exceeds 120 characters; contains 154 characters
if (array_key_exists($argAlias, $rowData['newObjects'])) {
ksort($rowData['newObjects'][$argAlias]['args']);
$rowData['newObjects'][$ownerIndex]['args'][$argIndex] = $rowData['newObjects'][$argAlias]['class']->newInstanceArgs($rowData['newObjects'][$argAlias]['args']);

Check warning on line 353 in src/Internal/Hydration/AbstractHydrator.php

View workflow job for this annotation

GitHub Actions / coding-standards / Coding Standards (PHP: 8.4)

Line exceeds 120 characters; contains 176 characters
unset($rowData['newObjects'][$argAlias]);
} else {
throw new LogicException(sprintf("%s does not exist", $argAlias);

Check failure on line 356 in src/Internal/Hydration/AbstractHydrator.php

View workflow job for this annotation

GitHub Actions / Static Analysis with PHPStan (default, phpstan.neon)

Syntax error, unexpected ';', expecting ')' on line 356

Check failure on line 356 in src/Internal/Hydration/AbstractHydrator.php

View workflow job for this annotation

GitHub Actions / Static Analysis with PHPStan (3.8.2, phpstan-dbal3.neon)

Syntax error, unexpected ';', expecting ')' on line 356
}

$newObject = $rowData['newObjects'][$ownerIndex . ':' . $argIndex];
unset($rowData['newObjects'][$ownerIndex . ':' . $argIndex]);

$obj = $newObject['class']->newInstanceArgs($newObject['args']);

$rowData['newObjects'][$ownerIndex]['args'][$argIndex] = $obj;
}

foreach ($rowData['newObjects'] as $objIndex => $newObject) {
$obj = $newObject['class']->newInstanceArgs($newObject['args']);
ksort($rowData['newObjects'][$objIndex]['args']);
$obj = $rowData['newObjects'][$objIndex]['class']->newInstanceArgs($rowData['newObjects'][$objIndex]['args']);

Check warning on line 362 in src/Internal/Hydration/AbstractHydrator.php

View workflow job for this annotation

GitHub Actions / coding-standards / Coding Standards (PHP: 8.4)

Line exceeds 120 characters; contains 122 characters

$rowData['newObjects'][$objIndex]['obj'] = $obj;
}
Expand Down Expand Up @@ -454,7 +463,6 @@ protected function hydrateColumnInfo(string $key): array|null
'type' => Type::getType($this->rsm->typeMappings[$key]),
'argIndex' => $mapping['argIndex'],
'objIndex' => $mapping['objIndex'],
'class' => new ReflectionClass($mapping['className']),
'enumType' => $this->rsm->enumMappings[$key] ?? null,
];

Expand Down
9 changes: 7 additions & 2 deletions src/Query/AST/NewObjectExpression.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

use Doctrine\ORM\Query\SqlWalker;

use function func_get_arg;
use function func_num_args;

/**
* NewObjectExpression ::= "NEW" IdentificationVariable "(" NewObjectArg {"," NewObjectArg}* ")"
*
Expand All @@ -18,8 +21,10 @@ public function __construct(public string $className, public array $args)
{
}

public function dispatch(SqlWalker $walker): string
public function dispatch(SqlWalker $walker /*, string|null $parentAlias = null */): string
{
return $walker->walkNewObject($this);
$parentAlias = func_num_args() > 1 ? func_get_arg(1) : null;

return $walker->walkNewObject($this, $parentAlias);
}
}
6 changes: 5 additions & 1 deletion src/Query/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -1854,7 +1854,11 @@ public function NewObjectArg(string|null &$fieldAlias = null): mixed

if ($this->lexer->isNextToken(TokenType::T_AS)) {
$this->match(TokenType::T_AS);
$fieldAlias = $this->AliasIdentificationVariable();
$this->match(TokenType::T_IDENTIFIER);

assert($this->lexer->token !== null);

$fieldAlias = $this->lexer->token->value;
}

return $expression;
Expand Down
7 changes: 7 additions & 0 deletions src/Query/ResultSetMapping.php
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,13 @@ class ResultSetMapping
*/
public array $newObjectMappings = [];

/**
* Maps object Ids in the result set to classnames.
*
* @phpstan-var array<string|int, array<string, mixed>>
*/
public array $newObject = [];

/**
* Maps last argument for new objects in order to initiate object construction
*
Expand Down
28 changes: 7 additions & 21 deletions src/Query/SqlWalker.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,8 @@
use function array_keys;
use function array_map;
use function array_merge;
use function array_pop;
use function assert;
use function count;
use function end;
use function implode;
use function in_array;
use function is_array;
Expand Down Expand Up @@ -84,13 +82,6 @@ class SqlWalker
*/
private int $newObjectCounter = 0;

/**
* Contains nesting levels of new objects arguments
*
* @phpstan-var array<int, array{0: string|int, 1: int}>
*/
private array $newObjectStack = [];

private readonly EntityManagerInterface $em;
private readonly Connection $conn;

Expand Down Expand Up @@ -1507,14 +1498,7 @@ public function walkParenthesisExpression(AST\ParenthesisExpression $parenthesis
public function walkNewObject(AST\NewObjectExpression $newObjectExpression, string|null $newObjectResultAlias = null): string
{
$sqlSelectExpressions = [];
$objOwner = $objOwnerIdx = null;

if ($this->newObjectStack !== []) {
[$objOwner, $objOwnerIdx] = end($this->newObjectStack);
$objIndex = $objOwner . ':' . $objOwnerIdx;
} else {
$objIndex = $newObjectResultAlias ?: $this->newObjectCounter++;
}
$objIndex = $newObjectResultAlias ?: $this->newObjectCounter++;

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

switch (true) {
case $e instanceof AST\NewObjectExpression:
$this->newObjectStack[] = [$objIndex, $argIndex];
$sqlSelectExpressions[] = $e->dispatch($this);
array_pop($this->newObjectStack);
$this->rsm->nestedNewObjectArguments[$columnAlias] = ['ownerIndex' => $objIndex, 'argIndex' => $argIndex];
$sqlSelectExpressions[] = $e->dispatch($this, $columnAlias);
$this->rsm->nestedNewObjectArguments[$columnAlias] = ['ownerIndex' => $objIndex, 'argIndex' => $argIndex, 'argAlias' => $columnAlias];
break;

case $e instanceof AST\Subselect:
Expand Down Expand Up @@ -1582,6 +1564,10 @@ public function walkNewObject(AST\NewObjectExpression $newObjectExpression, stri
];
}

$this->rsm->newObject[$objIndex] = [
'className' => $newObjectExpression->className,
];

return implode(', ', $sqlSelectExpressions);
}

Expand Down
2 changes: 1 addition & 1 deletion tests/Tests/Models/CMS/CmsAddressDTO.php
Original file line number Diff line number Diff line change
Expand Up @@ -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|null $other = null)
{
}
}
17 changes: 17 additions & 0 deletions tests/Tests/Models/CMS/CmsDumbDTO.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\Models\CMS;

class CmsDumbDTO
{
public function __construct(
public mixed $val1 = null,
public mixed $val2 = null,
public mixed $val3 = null,
public mixed $val4 = null,
public mixed $val5 = null,
) {
}
}
Loading

0 comments on commit 13469f6

Please sign in to comment.