Skip to content

Commit

Permalink
Add more tests and fix php <8 compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
Zuruuh committed Dec 13, 2023
1 parent 2aa7a43 commit 510d4b0
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 108 deletions.
32 changes: 30 additions & 2 deletions lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,22 @@
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Query;
use Doctrine\ORM\UnitOfWork;
use ReflectionClass;
use ReflectionException;

use function array_fill_keys;
use function array_key_exists;
use function array_keys;
use function array_map;
use function assert;
use function count;
use function is_array;
use function key;
use function ltrim;
use function spl_object_id;

use const PHP_VERSION_ID;

/**
* The ObjectHydrator constructs an object graph out of an SQL result set.
*
Expand Down Expand Up @@ -564,8 +570,30 @@ protected function hydrateRowData(array $row, array &$result)

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

if (PHP_VERSION_ID >= 80000) {
$obj = $class->newInstanceArgs($args);
} else {
$constructor = $class->getConstructor();
$unnamedArgs = [];

$constructorArguments = $constructor->getParameters();
$constructorArgumentsCount = count($constructorArguments);

foreach ($constructorArguments as $argument) {
if (array_key_exists($argument->getName(), $args)) {
$unnamedArgs[$argument->getPosition()] = $args[$argument->getName()];
} elseif (array_key_exists($argument->getPosition(), $args)) {
$unnamedArgs[$argument->getPosition()] = $args[$argument->getPosition()];
} else {
$unnamedArgs[$argument->getPosition()] = $argument->getDefaultValue();
}
}

$obj = $class->newInstanceArgs($unnamedArgs);
}

if ($scalarCount === 0 && count($rowData['newObjects']) === 1) {
$result[$resultKey] = $obj;
Expand Down
200 changes: 94 additions & 106 deletions tests/Doctrine/Tests/ORM/Functional/NewOperatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1076,69 +1076,85 @@ public function testClassCantBeInstantiatedException(): void
$this->_em->createQuery($dql)->getResult();
}

public function testQueryWithOnlyNamedArgumentsInOrder(): void
/** @return array<string, string> */
public static function provideQueriesWithNamedArguments(): array
{
$dql = '
SELECT
new Doctrine\Tests\Models\CMS\CmsUserDTO(
name: u.name,
email: e.email,
address: a.city,
)
FROM
Doctrine\Tests\Models\CMS\CmsUser u
JOIN
u.email e
JOIN
u.address a
ORDER BY
u.name';

$query = $this->_em->createQuery($dql);
$result = $query->getResult();

self::assertCount(3, $result);

self::assertInstanceOf(CmsUserDTO::class, $result[0]);
self::assertInstanceOf(CmsUserDTO::class, $result[1]);
self::assertInstanceOf(CmsUserDTO::class, $result[2]);

self::assertEquals($this->fixtures[0]->name, $result[0]->name);
self::assertEquals($this->fixtures[1]->name, $result[1]->name);
self::assertEquals($this->fixtures[2]->name, $result[2]->name);

self::assertEquals($this->fixtures[0]->email->email, $result[0]->email);
self::assertEquals($this->fixtures[1]->email->email, $result[1]->email);
self::assertEquals($this->fixtures[2]->email->email, $result[2]->email);

self::assertEquals($this->fixtures[0]->address->city, $result[0]->address);
self::assertEquals($this->fixtures[1]->address->city, $result[1]->address);
self::assertEquals($this->fixtures[2]->address->city, $result[2]->address);

self::assertNull($result[0]->phonenumbers);
self::assertNull($result[1]->phonenumbers);
self::assertNull($result[2]->phonenumbers);
return [
'Only named arguments in order' => [
'query' => '
SELECT
new Doctrine\Tests\Models\CMS\CmsUserDTO(
name: u.name,
email: e.email,
address: a.city,
)
FROM
Doctrine\Tests\Models\CMS\CmsUser u
JOIN
u.email e
JOIN
u.address a
ORDER BY
u.name',
],
'Only named arguments not in order' => [
'query' => '
SELECT
new Doctrine\Tests\Models\CMS\CmsUserDTO(
email: e.email,
name: u.name,
address: a.city,
)
FROM
Doctrine\Tests\Models\CMS\CmsUser u
JOIN
u.email e
JOIN
u.address a
ORDER BY
u.name',
],
'Both named and unnamed arguments' => [
'query' => '
SELECT
new Doctrine\Tests\Models\CMS\CmsUserDTO(
u.name,
address: a.city,
email: e.email,
)
FROM
Doctrine\Tests\Models\CMS\CmsUser u
JOIN
u.email e
JOIN
u.address a
ORDER BY
u.name',
],
'Both named and unnamed arguments without trailling comma' => [
'query' => '
SELECT
new Doctrine\Tests\Models\CMS\CmsUserDTO(
u.name,
address: a.city,
email: e.email
)
FROM
Doctrine\Tests\Models\CMS\CmsUser u
JOIN
u.email e
JOIN
u.address a
ORDER BY
u.name',
],
];
}

public function testQueryWithOnlyNamedArgumentsNotInOrder(): void
/** @dataProvider provideQueriesWithNamedArguments */
public function testQueryWithNamedArguments(string $query): void
{
$dql = '
SELECT
new Doctrine\Tests\Models\CMS\CmsUserDTO(
email: e.email,
name: u.name,
address: a.city,
)
FROM
Doctrine\Tests\Models\CMS\CmsUser u
JOIN
u.email e
JOIN
u.address a
ORDER BY
u.name';

$query = $this->_em->createQuery($dql);
$query = $this->_em->createQuery($query);
$result = $query->getResult();

self::assertCount(3, $result);
Expand All @@ -1164,14 +1180,14 @@ public function testQueryWithOnlyNamedArgumentsNotInOrder(): void
self::assertNull($result[2]->phonenumbers);
}

public function testQueryWithNamedAndUnnamedArguments(): void
public function testQueryWithUnnamedArgumentAfterNamedArgument(): void
{
$dql = '
SELECT
new Doctrine\Tests\Models\CMS\CmsUserDTO(
u.name,
address: a.city,
email: e.email,
u.name,
)
FROM
Doctrine\Tests\Models\CMS\CmsUser u
Expand All @@ -1182,40 +1198,20 @@ public function testQueryWithNamedAndUnnamedArguments(): void
ORDER BY
u.name';

$query = $this->_em->createQuery($dql);
$result = $query->getResult();

self::assertCount(3, $result);

self::assertInstanceOf(CmsUserDTO::class, $result[0]);
self::assertInstanceOf(CmsUserDTO::class, $result[1]);
self::assertInstanceOf(CmsUserDTO::class, $result[2]);

self::assertEquals($this->fixtures[0]->name, $result[0]->name);
self::assertEquals($this->fixtures[1]->name, $result[1]->name);
self::assertEquals($this->fixtures[2]->name, $result[2]->name);

self::assertEquals($this->fixtures[0]->email->email, $result[0]->email);
self::assertEquals($this->fixtures[1]->email->email, $result[1]->email);
self::assertEquals($this->fixtures[2]->email->email, $result[2]->email);

self::assertEquals($this->fixtures[0]->address->city, $result[0]->address);
self::assertEquals($this->fixtures[1]->address->city, $result[1]->address);
self::assertEquals($this->fixtures[2]->address->city, $result[2]->address);
$query = $this->_em->createQuery($dql);
$this->expectException(QueryException::class);
$this->expectExceptionMessage('[Syntax Error] Cannot specify unnamed arguments after named ones.');

self::assertNull($result[0]->phonenumbers);
self::assertNull($result[1]->phonenumbers);
self::assertNull($result[2]->phonenumbers);
$query->getResult();
}

public function testQueryWithNamedAndUnnamedArgumentsWithoutTraillingComma(): void
public function testQueryWithNamedArgumentsWithoutOptionalParameters(): void
{
$dql = '
SELECT
new Doctrine\Tests\Models\CMS\CmsUserDTO(
u.name,
address: a.city,
email: e.email
email: e.email,
)
FROM
Doctrine\Tests\Models\CMS\CmsUser u
Expand All @@ -1226,18 +1222,16 @@ public function testQueryWithNamedAndUnnamedArgumentsWithoutTraillingComma(): vo
ORDER BY
u.name';

$query = $this->_em->createQuery($dql);
$query = $this->_em->createQuery($dql);
$result = $query->getResult();

self::assertCount(3, $result);

self::assertInstanceOf(CmsUserDTO::class, $result[0]);
self::assertInstanceOf(CmsUserDTO::class, $result[1]);
self::assertInstanceOf(CmsUserDTO::class, $result[2]);

self::assertEquals($this->fixtures[0]->name, $result[0]->name);
self::assertEquals($this->fixtures[1]->name, $result[1]->name);
self::assertEquals($this->fixtures[2]->name, $result[2]->name);
self::assertNull($result[0]->name);
self::assertNull($result[1]->name);
self::assertNull($result[2]->name);

self::assertEquals($this->fixtures[0]->email->email, $result[0]->email);
self::assertEquals($this->fixtures[1]->email->email, $result[1]->email);
Expand All @@ -1252,29 +1246,23 @@ public function testQueryWithNamedAndUnnamedArgumentsWithoutTraillingComma(): vo
self::assertNull($result[2]->phonenumbers);
}

public function testQueryWithUnnamedArgumentAfterNamedArgument(): void
public function testQueryWithNamedArgumentsMissingRequiredArguments(): void
{

$dql = '
SELECT
new Doctrine\Tests\Models\CMS\CmsUserDTO(
address: a.city,
email: e.email,
u.name,
new ' . ClassWithTooMuchArgs::class . '(
bar: u.name,
)
FROM
Doctrine\Tests\Models\CMS\CmsUser u
JOIN
u.email e
JOIN
u.address a
ORDER BY
u.name';
';

$query = $this->_em->createQuery($dql);
$this->expectException(QueryException::class);
$this->expectExceptionMessage('[Syntax Error] Cannot specify unnamed arguments after named ones.');
$this->expectExceptionMessage('Number of arguments does not match with "Doctrine\Tests\ORM\Functional\ClassWithTooMuchArgs" constructor declaration.');
$result = $query->getResult();

$query->getResult();
}
}

Expand Down

0 comments on commit 510d4b0

Please sign in to comment.