Skip to content

Commit

Permalink
second review
Browse files Browse the repository at this point in the history
  • Loading branch information
eltharin committed Aug 26, 2024
1 parent ce472bb commit f6ac22b
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 5 deletions.
19 changes: 16 additions & 3 deletions docs/en/reference/dql-doctrine-query-language.rst
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ you can use named arguments or variadic arguments, add ``WithNamedArguments`` to
}
}
And then you can select the fields you want in the order you want :
And then you can select the fields you want in the order you want, and the ORM will try to match argument names with the selected field names :

.. code-block:: php
Expand All @@ -639,7 +639,7 @@ And then you can select the fields you want in the order you want :
// CustomerDTO => {name : 'SMITH', email: null, city: 'London', value: null}
you can also aliases column :
ORM will also look column aliases before columns names :

.. code-block:: php
Expand All @@ -648,7 +648,20 @@ you can also aliases column :
$users = $query->getResult(); // array of CustomerDTO
// CustomerDTO => {name : 'DOE', email: null, city: null, value: 'New York 10011'}
For aliases a field you can use SQL notation with `AS` keyword, or the PHP named arguments notation :

.. code-block:: php
<?php
$query = $em->createQuery('SELECT NEW CustomerDTO(name: c.name, value: CONCAT(a.city, ' ' , a.zip)) FROM Customer c JOIN c.address a');
$users = $query->getResult(); // array of CustomerDTO
// CustomerDTO => {name : 'DOE', email: null, city: null, value: 'New York 10011'}
Be careful, if two fields have the same name/alias, second will erase first.
If you put an argument name empty (for functions) or not in constructor argument list, ORM will throw an error.

Using INDEX BY
~~~~~~~~~~~~~~

Expand Down
2 changes: 1 addition & 1 deletion src/Internal/Hydration/AbstractHydrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ abstract protected function hydrateAllData(): mixed;
* newObjects?: array<array-key, array{
* class: ReflectionClass,
* args: array,
* argNames?: <array-key, string>,
* argNames?: array<array-key, string>,
* obj: object
* }>,
* scalars?: array
Expand Down
10 changes: 9 additions & 1 deletion src/Query/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -1774,6 +1774,7 @@ public function NewObjectExpression(): AST\NewObjectExpression
*/
public function NewObjectArg(string|null &$fieldAlias = null): mixed
{
$namedArg = false;
$fieldAlias = null;

assert($this->lexer->lookahead !== null);
Expand All @@ -1784,6 +1785,13 @@ public function NewObjectArg(string|null &$fieldAlias = null): mixed

$expression = null;

if ($token->type === TokenType::T_IDENTIFIER && $peek->value === ':') {
$fieldAlias = $this->AliasIdentificationVariable();
$this->lexer->moveNext();
$namedArg = true;
$token = $this->lexer->lookahead;
}

if ($token->type === TokenType::T_OPEN_PARENTHESIS && $peek->type === TokenType::T_SELECT) {

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

View workflow job for this annotation

GitHub Actions / Static Analysis with Psalm (3.8.2)

PossiblyNullPropertyFetch

src/Query/Parser.php:1795:13: PossiblyNullPropertyFetch: Cannot get property on possibly null variable $token of type Doctrine\Common\Lexer\Token<Doctrine\ORM\Query\TokenType, string>|null (see https://psalm.dev/082)

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

View workflow job for this annotation

GitHub Actions / Static Analysis with Psalm (default)

PossiblyNullPropertyFetch

src/Query/Parser.php:1795:13: PossiblyNullPropertyFetch: Cannot get property on possibly null variable $token of type Doctrine\Common\Lexer\Token<Doctrine\ORM\Query\TokenType, string>|null (see https://psalm.dev/082)
$this->match(TokenType::T_OPEN_PARENTHESIS);
$expression = $this->Subselect();
Expand All @@ -1794,7 +1802,7 @@ public function NewObjectArg(string|null &$fieldAlias = null): mixed
$expression = $this->ScalarExpression();
}

if ($this->lexer->isNextToken(TokenType::T_AS)) {
if (! $namedArg && $this->lexer->isNextToken(TokenType::T_AS)) {
$this->match(TokenType::T_AS);
$fieldAlias = $this->AliasIdentificationVariable();
}
Expand Down
66 changes: 66 additions & 0 deletions tests/Tests/ORM/Functional/NewOperatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1298,6 +1298,72 @@ public function testShouldSupportNestedNewOperatorsAndNamedArguments(): void
self::assertSame($this->fixtures[2]->username, $result[2]['cmsUserUsername']);
}

public function testShouldSupportNestedNewOperatorsAndNamedArgumentsWithPhpNotation(): void
{
$dql = '
SELECT
new CmsUserDTONamedArgs(
email: e.email,
addressDto: new CmsAddressDTO(
a.country,
a.city,
a.zip
),
name: u.name
) as user,
u.status,
u.username as cmsUserUsername
FROM
Doctrine\Tests\Models\CMS\CmsUser u
JOIN
u.email e
JOIN
u.address a
ORDER BY
u.name';

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

self::assertCount(3, $result);

self::assertInstanceOf(CmsUserDTONamedArgs::class, $result[0]['user']);
self::assertInstanceOf(CmsUserDTONamedArgs::class, $result[1]['user']);
self::assertInstanceOf(CmsUserDTONamedArgs::class, $result[2]['user']);

self::assertNull($result[0]['user']->address);
self::assertNull($result[1]['user']->address);
self::assertNull($result[2]['user']->address);

self::assertInstanceOf(CmsAddressDTO::class, $result[0]['user']->addressDto);
self::assertInstanceOf(CmsAddressDTO::class, $result[1]['user']->addressDto);
self::assertInstanceOf(CmsAddressDTO::class, $result[2]['user']->addressDto);

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

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

self::assertSame($this->fixtures[0]->address->city, $result[0]['user']->addressDto->city);
self::assertSame($this->fixtures[1]->address->city, $result[1]['user']->addressDto->city);
self::assertSame($this->fixtures[2]->address->city, $result[2]['user']->addressDto->city);

self::assertSame($this->fixtures[0]->address->country, $result[0]['user']->addressDto->country);
self::assertSame($this->fixtures[1]->address->country, $result[1]['user']->addressDto->country);
self::assertSame($this->fixtures[2]->address->country, $result[2]['user']->addressDto->country);

self::assertSame($this->fixtures[0]->status, $result[0]['status']);
self::assertSame($this->fixtures[1]->status, $result[1]['status']);
self::assertSame($this->fixtures[2]->status, $result[2]['status']);

self::assertSame($this->fixtures[0]->username, $result[0]['cmsUserUsername']);
self::assertSame($this->fixtures[1]->username, $result[1]['cmsUserUsername']);
self::assertSame($this->fixtures[2]->username, $result[2]['cmsUserUsername']);
}

public function testShouldSupportNestedNamedArguments(): void
{
$dql = '
Expand Down

0 comments on commit f6ac22b

Please sign in to comment.