Skip to content

Commit

Permalink
error corrections
Browse files Browse the repository at this point in the history
  • Loading branch information
eltharin committed Jul 3, 2024
1 parent dbfe47b commit 2c24349
Show file tree
Hide file tree
Showing 15 changed files with 377 additions and 17 deletions.
10 changes: 4 additions & 6 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,10 @@
<code><![CDATA[return $rowData;]]></code>
<code><![CDATA[return $rowData;]]></code>
</ReferenceConstraintViolation>
<PossiblyUndefinedArrayOffset>
<code><![CDATA[$newObject['args']]]></code>
<code><![CDATA[$newObject['args']]]></code>
</PossiblyUndefinedArrayOffset>
</file>
<file src="src/Internal/Hydration/ArrayHydrator.php">
<PossiblyInvalidArgument>
Expand All @@ -228,9 +232,6 @@
<code><![CDATA[$result[$resultKey]]]></code>
<code><![CDATA[$result[$resultKey]]]></code>
</PossiblyNullArrayAssignment>
<PossiblyUndefinedArrayOffset>
<code><![CDATA[$newObject['args']]]></code>
</PossiblyUndefinedArrayOffset>
<ReferenceConstraintViolation>
<code><![CDATA[$result]]></code>
</ReferenceConstraintViolation>
Expand Down Expand Up @@ -265,9 +266,6 @@
<code><![CDATA[setValue]]></code>
<code><![CDATA[setValue]]></code>
</PossiblyNullReference>
<PossiblyUndefinedArrayOffset>
<code><![CDATA[$newObject['args']]]></code>
</PossiblyUndefinedArrayOffset>
</file>
<file src="src/Mapping/AssociationMapping.php">
<LessSpecificReturnStatement>
Expand Down
34 changes: 32 additions & 2 deletions src/Internal/Hydration/AbstractHydrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,9 @@ abstract protected function hydrateAllData(): mixed;
* @psalm-return array{
* data: array<array-key, array>,
* newObjects?: array<array-key, array{
* class: mixed,
* args?: array
* class: ReflectionClass,
* args: array,
* obj: object
* }>,
* scalars?: array
* }
Expand Down Expand Up @@ -281,6 +282,10 @@ protected function gatherRowData(array $data, array &$id, array &$nonemptyCompon
$value = $this->buildEnum($value, $cacheKeyInfo['enumType']);
}

if (! isset($rowData['newObjects'])) {
$rowData['newObjects'] = [];
}

$rowData['newObjects'][$objIndex]['class'] = $cacheKeyInfo['class'];
$rowData['newObjects'][$objIndex]['args'][$argIndex] = $value;
break;
Expand Down Expand Up @@ -335,6 +340,31 @@ protected function gatherRowData(array $data, array &$id, array &$nonemptyCompon
}
}

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

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

View check run for this annotation

Codecov / codecov/patch

src/Internal/Hydration/AbstractHydrator.php#L345

Added line #L345 was not covered by tests
}

$newObject = $rowData['newObjects'][$objIndex];
unset($rowData['newObjects'][$objIndex]);

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

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

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

$rowData['newObjects'][$objIndex]['obj'] = $obj;
}
}

return $rowData;
}

Expand Down
5 changes: 2 additions & 3 deletions src/Internal/Hydration/ArrayHydrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,8 @@ protected function hydrateRowData(array $row, array &$result): void
$scalarCount = (isset($rowData['scalars']) ? count($rowData['scalars']) : 0);

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

if (count($args) === $scalarCount || ($scalarCount === 0 && count($rowData['newObjects']) === 1)) {
$result[$resultKey] = $obj;
Expand Down
4 changes: 1 addition & 3 deletions src/Internal/Hydration/ObjectHydrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -552,9 +552,7 @@ protected function hydrateRowData(array $row, array &$result): void
$scalarCount = (isset($rowData['scalars']) ? count($rowData['scalars']) : 0);

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

if ($scalarCount === 0 && count($rowData['newObjects']) === 1) {
$result[$resultKey] = $obj;
Expand Down
6 changes: 6 additions & 0 deletions src/Query/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -1674,6 +1674,12 @@ public function NewObjectArg(): mixed
return $expression;
}

if ($token->type === TokenType::T_NEW) {
$expression = $this->NewObjectExpression();

Check failure on line 1678 in src/Query/Parser.php

View workflow job for this annotation

GitHub Actions / coding-standards / Coding Standards (8.3)

Useless variable $expression.

return $expression;
}

return $this->ScalarExpression();
}

Expand Down
29 changes: 29 additions & 0 deletions src/Query/ResultSetMapping.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Doctrine\ORM\Query;

use function array_merge;
use function count;

/**
Expand Down Expand Up @@ -152,6 +153,13 @@ class ResultSetMapping
*/
public array $newObjectMappings = [];

/**
* Maps last argument for new objects in order to initiate object construction
*
* @psalm-var array<int|string, array{ownerIndex: string|int, argIndex: int|string}>
*/
public array $nestedNewObjectArguments = [];

/**
* Maps metadata parameter names to the metadata attribute.
*
Expand Down Expand Up @@ -544,4 +552,25 @@ public function addMetaResult(

return $this;
}

public function addNewObjectAsArgument(string|int $alias, string|int $objOwner, int $objOwnerIdx): static
{
$owner = [
'ownerIndex' => $objOwner,
'argIndex' => $objOwnerIdx,
];

if (! isset($this->nestedNewObjectArguments[$owner['ownerIndex']])) {
$this->nestedNewObjectArguments[$alias] = $owner;

return $this;
}

$this->nestedNewObjectArguments = array_merge(
[$alias => $owner],
$this->nestedNewObjectArguments

Check failure on line 571 in src/Query/ResultSetMapping.php

View workflow job for this annotation

GitHub Actions / coding-standards / Coding Standards (8.3)

Multi-line function calls must have a trailing comma after the last parameter.
);

return $this;
}
}
25 changes: 24 additions & 1 deletion src/Query/SqlWalker.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@
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 is_array;
use function is_float;
Expand Down Expand Up @@ -79,6 +81,14 @@ class SqlWalker
*/
private int $newObjectCounter = 0;

Check failure on line 82 in src/Query/SqlWalker.php

View workflow job for this annotation

GitHub Actions / coding-standards / Coding Standards (8.3)

Expected 0 to 1 blank lines after property, found 2.


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

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

Expand Down Expand Up @@ -1459,7 +1469,14 @@ public function walkParenthesisExpression(AST\ParenthesisExpression $parenthesis
public function walkNewObject(AST\NewObjectExpression $newObjectExpression, string|null $newObjectResultAlias = null): string
{
$sqlSelectExpressions = [];
$objIndex = $newObjectResultAlias ?: $this->newObjectCounter++;
$objOwner = $objOwnerIdx = null;

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

foreach ($newObjectExpression->args as $argIndex => $e) {
$resultAlias = $this->scalarResultCounter++;
Expand All @@ -1468,7 +1485,9 @@ 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);
break;

case $e instanceof AST\Subselect:
Expand Down Expand Up @@ -1522,6 +1541,10 @@ public function walkNewObject(AST\NewObjectExpression $newObjectExpression, stri
'objIndex' => $objIndex,
'argIndex' => $argIndex,
];

if ($objOwner !== null && $objOwnerIdx !== null) {
$this->rsm->addNewObjectAsArgument($objIndex, $objOwner, $objOwnerIdx);
}
}

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 function __construct(public string|null $country = null, public string|null $city = null, public string|null $zip = null, public CmsAddressDTO|string|null $address = null)
{
}
}
2 changes: 1 addition & 1 deletion tests/Tests/Models/CMS/CmsUserDTO.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

class CmsUserDTO
{
public function __construct(public string|null $name = null, public string|null $email = null, public string|null $address = null, public int|null $phonenumbers = null)
public function __construct(public string|null $name = null, public string|null $email = null, public CmsAddressDTO|string|null $address = null, public int|null $phonenumbers = null)
{
}
}
17 changes: 17 additions & 0 deletions tests/Tests/Models/DDC6573/DDC6573Currency.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\Models\DDC6573;

final class DDC6573Currency
{
public function __construct(private readonly string $code)
{
}

public function getCode(): string
{
return $this->code;
}
}

Check failure on line 17 in tests/Tests/Models/DDC6573/DDC6573Currency.php

View workflow job for this annotation

GitHub Actions / coding-standards / Coding Standards (8.3)

Expected 1 newline at end of file; 0 found
44 changes: 44 additions & 0 deletions tests/Tests/Models/DDC6573/DDC6573Item.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\Models\DDC6573;

use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\Table;

#[Entity]
#[Table(name: 'ddc6573_items')]
class DDC6573Item
{
/** @var int */
#[Id]
#[Column(type: Types::INTEGER)]
#[GeneratedValue(strategy: 'AUTO')]
public $id;

#[Column(type: Types::STRING)]
public string $name;

#[Column(type: Types::INTEGER)]
public int $priceAmount;

#[Column(type: Types::STRING, length: 3)]
public string $priceCurrency;

public function __construct(string $name, DDC6573Money $price)
{
$this->name = $name;
$this->priceAmount = $price->getAmount();
$this->priceCurrency = $price->getCurrency()->getCode();
}

public function getPrice(): DDC6573Money
{
return new DDC6573Money($this->priceAmount, new DDC6573Currency($this->priceCurrency));
}
}

Check failure on line 44 in tests/Tests/Models/DDC6573/DDC6573Item.php

View workflow job for this annotation

GitHub Actions / coding-standards / Coding Standards (8.3)

Expected 1 newline at end of file; 0 found
24 changes: 24 additions & 0 deletions tests/Tests/Models/DDC6573/DDC6573Money.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\Models\DDC6573;

final class DDC6573Money
{
public function __construct(
private readonly int $amount,
private readonly DDC6573Currency $currency,
) {
}

public function getAmount(): int
{
return $this->amount;
}

public function getCurrency(): DDC6573Currency
{
return $this->currency;
}
}

Check failure on line 24 in tests/Tests/Models/DDC6573/DDC6573Money.php

View workflow job for this annotation

GitHub Actions / coding-standards / Coding Standards (8.3)

Expected 1 newline at end of file; 0 found
Loading

0 comments on commit 2c24349

Please sign in to comment.