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 21, 2025
1 parent c9557c5 commit 708bd84
Show file tree
Hide file tree
Showing 8 changed files with 316 additions and 41 deletions.
33 changes: 20 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,17 @@ protected function gatherRowData(array $data, array &$id, array &$nonemptyCompon
{
$rowData = ['data' => [], 'newObjects' => []];

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

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

foreach ($data as $key => $value) {
$cacheKeyInfo = $this->hydrateColumnInfo($key);
if ($cacheKeyInfo === null) {
Expand All @@ -282,7 +295,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 +348,17 @@ 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;
foreach ($this->resultSetMapping()->nestedNewObjectArguments as ['ownerIndex' => $ownerIndex, 'argIndex' => $argIndex, 'argAlias' => $argAlias]) {
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']);
unset($rowData['newObjects'][$argAlias]);
}

$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']);

$rowData['newObjects'][$objIndex]['obj'] = $obj;
}
Expand Down Expand Up @@ -454,7 +462,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
14 changes: 11 additions & 3 deletions src/Query/AST/NewObjectExpression.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,28 @@

use Doctrine\ORM\Query\SqlWalker;

use function func_get_arg;
use function func_num_args;

/**
* NewObjectExpression ::= "NEW" IdentificationVariable "(" NewObjectArg {"," NewObjectArg}* ")"
*
* @link www.doctrine-project.org
*/
class NewObjectExpression extends Node
{
/** @param mixed[] $args */
/**
* @param class-string $className
* @param mixed[] $args
*/
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);
}
}
7 changes: 6 additions & 1 deletion src/Query/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -1767,6 +1767,7 @@ public function NewObjectExpression(): AST\NewObjectExpression
$useNamedArguments = true;
}

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

Expand Down Expand Up @@ -1854,7 +1855,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, class-string>
*/
public array $newObject = [];

/**
* Maps last argument for new objects in order to initiate object construction
*
Expand Down
27 changes: 5 additions & 22 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 @@ -1576,12 +1558,13 @@ public function walkNewObject(AST\NewObjectExpression $newObjectExpression, stri
$this->rsm->addScalarResult($columnAlias, $resultAlias, $fieldType);

$this->rsm->newObjectMappings[$columnAlias] = [
'className' => $newObjectExpression->className,
'objIndex' => $objIndex,
'argIndex' => $argIndex,
];
}

$this->rsm->newObject[$objIndex] = $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 string|null $address = 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 708bd84

Please sign in to comment.