Skip to content

Commit 19e1a64

Browse files
authored
Merge pull request #12014 from greg0ire/3.5.x
Merge 3.4.1 up into 3.5.x
2 parents bbde41f + 082e776 commit 19e1a64

21 files changed

+158
-466
lines changed

UPGRADE.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ As a consequence, the following methods are deprecated and will be removed in 4.
2222
* `Doctrine\ORM\Configuration::setRejectIdCollisionInIdentityMap()`
2323
* `Doctrine\ORM\Configuration::isRejectIdCollisionInIdentityMapEnabled()`
2424

25+
# Upgrade to 3.4.1
26+
27+
## BC BREAK: You can no longer use the `.*` notation to get all fields of an entity in a DTO
28+
29+
This feature was introduced in 3.4.0, and introduces several issues, so we
30+
decide to remove it before it is used too widely.
31+
2532
# Upgrade to 3.4
2633

2734
## Discriminator Map class duplicates

docs/en/reference/dql-doctrine-query-language.rst

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,7 @@ And then use the ``NEW`` DQL keyword :
588588
$query = $em->createQuery('SELECT NEW CustomerDTO(c.name, e.email, a.city, SUM(o.value)) FROM Customer c JOIN c.email e JOIN c.address a JOIN c.orders o GROUP BY c');
589589
$users = $query->getResult(); // array of CustomerDTO
590590
591-
You can also nest several DTO :
591+
You can also nest several DTO :
592592

593593
.. code-block:: php
594594
@@ -684,18 +684,6 @@ You can hydrate an entity nested in a DTO :
684684
685685
// CustomerDTO => {name : 'DOE', email: null, address : {city: 'New York', zip: '10011', address: 'Abbey Road'}
686686
687-
In a Dto, if you want add all fields of an entity, you can use ``.*`` :
688-
689-
.. code-block:: php
690-
691-
<?php
692-
$query = $em->createQuery('SELECT NEW NAMED CustomerDTO(c.name, NEW NAMED AddressDTO(a.*) AS address) FROM Customer c JOIN c.address a');
693-
$users = $query->getResult(); // array of CustomerDTO
694-
695-
// CustomerDTO => {name : 'DOE', email: null, city: null, address: {id: 18, city: 'New York', zip: '10011'}}
696-
697-
It's recommended to use named arguments DTOs with the ``.*`` notation because argument order is not guaranteed.
698-
699687
Using INDEX BY
700688
~~~~~~~~~~~~~~
701689

@@ -1719,14 +1707,13 @@ Select Expressions
17191707

17201708
.. code-block:: php
17211709
1722-
SelectExpression ::= (IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration | PartialObjectExpression | "(" Subselect ")" | CaseExpression | NewObjectExpression) [["AS"] ["HIDDEN"] AliasResultVariable]
1723-
SimpleSelectExpression ::= (StateFieldPathExpression | IdentificationVariable | FunctionDeclaration | AggregateExpression | "(" Subselect ")" | ScalarExpression) [["AS"] AliasResultVariable]
1710+
SelectExpression ::= (IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration | PartialObjectExpression | "(" Subselect ")" | CaseExpression | NewObjectExpression) [["AS"] ["HIDDEN"] AliasResultVariable]
1711+
SimpleSelectExpression ::= (StateFieldPathExpression | IdentificationVariable | FunctionDeclaration | AggregateExpression | "(" Subselect ")" | ScalarExpression) [["AS"] AliasResultVariable]
17241712
PartialObjectExpression ::= "PARTIAL" IdentificationVariable "." PartialFieldSet
17251713
PartialFieldSet ::= "{" SimpleStateField {"," SimpleStateField}* "}"
17261714
NewObjectExpression ::= "NEW" AbstractSchemaName "(" NewObjectArg {"," NewObjectArg}* ")"
1727-
NewObjectArg ::= ((ScalarExpression | "(" Subselect ")" | NewObjectExpression | EntityAsDtoArgumentExpression) ["AS" AliasResultVariable]) | AllFieldsExpression
1715+
NewObjectArg ::= (ScalarExpression | "(" Subselect ")" | NewObjectExpression | EntityAsDtoArgumentExpression) ["AS" AliasResultVariable]
17281716
EntityAsDtoArgumentExpression ::= IdentificationVariable
1729-
AllFieldsExpression ::= IdentificationVariable ".*"
17301717
17311718
Conditional Expressions
17321719
~~~~~~~~~~~~~~~~~~~~~~~

phpstan-baseline.neon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2811,7 +2811,7 @@ parameters:
28112811
-
28122812
message: '#^Cannot assign new offset to list\<string\>\|string\.$#'
28132813
identifier: offsetAssign.dimType
2814-
count: 3
2814+
count: 2
28152815
path: src/Query/SqlWalker.php
28162816

28172817
-

phpstan.neon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ parameters:
4545
path: src/UnitOfWork.php
4646

4747
-
48-
message: '~^Parameter #1 \$command of method Symfony\\Component\\Console\\Application::add\(\) expects Symfony\\Component\\Console\\Command\\Command, Doctrine\\DBAL\\Tools\\Console\\Command\\ReservedWordsCommand given\.$~'
48+
message: '~^Parameter #2 \$command of static method Doctrine\\ORM\\Tools\\Console\\ConsoleRunner::addCommandToApplication\(\) expects Symfony\\Component\\Console\\Command\\Command, Doctrine\\DBAL\\Tools\\Console\\Command\\ReservedWordsCommand given\.$~'
4949
path: src/Tools/Console/ConsoleRunner.php
5050

5151
-

src/Proxy/ProxyFactory.php

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ public function __serialize(): array
132132
/** @var array<class-string, Closure> */
133133
private array $proxyFactories = [];
134134

135+
private readonly string $proxyDir;
136+
private readonly string $proxyNs;
137+
135138
/**
136139
* Initializes a new instance of the <tt>ProxyFactory</tt> class that is
137140
* connected to the given <tt>EntityManager</tt>.
@@ -143,8 +146,8 @@ public function __serialize(): array
143146
*/
144147
public function __construct(
145148
private readonly EntityManagerInterface $em,
146-
private readonly string $proxyDir,
147-
private readonly string $proxyNs,
149+
string|null $proxyDir = null,
150+
string|null $proxyNs = null,
148151
bool|int $autoGenerate = self::AUTOGENERATE_NEVER,
149152
) {
150153
if (! $proxyDir && ! $em->getConfiguration()->isNativeLazyObjectsEnabled()) {
@@ -159,6 +162,17 @@ public function __construct(
159162
throw ORMInvalidArgumentException::invalidAutoGenerateMode($autoGenerate);
160163
}
161164

165+
if ($proxyDir === null && $em->getConfiguration()->isNativeLazyObjectsEnabled()) {
166+
$proxyDir = '';
167+
}
168+
169+
if ($proxyNs === null && $em->getConfiguration()->isNativeLazyObjectsEnabled()) {
170+
$proxyNs = '';
171+
}
172+
173+
$this->proxyDir = $proxyDir;
174+
$this->proxyNs = $proxyNs;
175+
162176
$this->uow = $em->getUnitOfWork();
163177
$this->autoGenerate = (int) $autoGenerate;
164178
$this->identifierFlattener = new IdentifierFlattener($this->uow, $em->getMetadataFactory());
@@ -171,11 +185,23 @@ public function __construct(
171185
public function getProxy(string $className, array $identifier): object
172186
{
173187
if ($this->em->getConfiguration()->isNativeLazyObjectsEnabled()) {
174-
$classMetadata = $this->em->getClassMetadata($className);
175-
$entityPersister = $this->uow->getEntityPersister($className);
176-
177-
$proxy = $classMetadata->reflClass->newLazyGhost(static function (object $object) use ($identifier, $entityPersister): void {
178-
$entityPersister->loadById($identifier, $object);
188+
$classMetadata = $this->em->getClassMetadata($className);
189+
$entityPersister = $this->uow->getEntityPersister($className);
190+
$identifierFlattener = $this->identifierFlattener;
191+
192+
$proxy = $classMetadata->reflClass->newLazyGhost(static function (object $object) use (
193+
$identifier,
194+
$entityPersister,
195+
$identifierFlattener,
196+
$classMetadata,
197+
): void {
198+
$original = $entityPersister->loadById($identifier, $object);
199+
if ($original === null) {
200+
throw EntityNotFoundException::fromClassNameAndIdentifier(
201+
$classMetadata->getName(),
202+
$identifierFlattener->flattenIdentifier($classMetadata, $identifier),
203+
);
204+
}
179205
}, ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE);
180206

181207
foreach ($identifier as $idField => $value) {

src/Query/AST/AllFieldsExpression.php

Lines changed: 0 additions & 28 deletions
This file was deleted.

src/Query/AST/NewObjectExpression.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class NewObjectExpression extends Node
2020
* @param class-string $className
2121
* @param mixed[] $args
2222
*/
23-
public function __construct(public string $className, public array $args, public bool $hasNamedArgs = false)
23+
public function __construct(public string $className, public array $args)
2424
{
2525
}
2626

src/Query/Parser.php

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,7 +1036,6 @@ public function PathExpression(int $expectedTypes): AST\PathExpression
10361036
assert($this->lexer->token !== null);
10371037
if ($this->lexer->isNextToken(TokenType::T_DOT)) {
10381038
$this->match(TokenType::T_DOT);
1039-
10401039
$this->match(TokenType::T_IDENTIFIER);
10411040

10421041
$field = $this->lexer->token->value;
@@ -1151,20 +1150,6 @@ public function EntityAsDtoArgumentExpression(): AST\EntityAsDtoArgumentExpressi
11511150
return new AST\EntityAsDtoArgumentExpression($expression, $identVariable);
11521151
}
11531152

1154-
/**
1155-
* AllFieldsExpression ::= IdentificationVariable
1156-
*/
1157-
public function AllFieldsExpression(): AST\AllFieldsExpression
1158-
{
1159-
$identVariable = $this->IdentificationVariable();
1160-
assert($this->lexer->token !== null);
1161-
1162-
$this->match(TokenType::T_DOT);
1163-
$this->match(TokenType::T_MULTIPLY);
1164-
1165-
return new AST\AllFieldsExpression($identVariable);
1166-
}
1167-
11681153
/**
11691154
* SelectClause ::= "SELECT" ["DISTINCT"] SelectExpression {"," SelectExpression}
11701155
*/
@@ -1841,7 +1826,7 @@ public function NewObjectExpression(): AST\NewObjectExpression
18411826

18421827
$this->match(TokenType::T_CLOSE_PARENTHESIS);
18431828

1844-
$expression = new AST\NewObjectExpression($className, $args, $useNamedArguments);
1829+
$expression = new AST\NewObjectExpression($className, $args);
18451830

18461831
// Defer NewObjectExpression validation
18471832
$this->deferredNewObjectExpressions[] = [
@@ -1888,7 +1873,7 @@ public function addArgument(array &$args, bool $useNamedArguments): void
18881873
}
18891874

18901875
/**
1891-
* NewObjectArg ::= ((ScalarExpression | "(" Subselect ")" | NewObjectExpression) ["AS" AliasResultVariable]) | AllFieldsExpression
1876+
* NewObjectArg ::= (ScalarExpression | "(" Subselect ")" | NewObjectExpression) ["AS" AliasResultVariable]
18921877
*/
18931878
public function NewObjectArg(string|null &$fieldAlias = null): mixed
18941879
{
@@ -2000,14 +1985,10 @@ public function ScalarExpression(): mixed
20001985
// it is no function, so it must be a field path
20011986
case $lookahead === TokenType::T_IDENTIFIER:
20021987
$this->lexer->peek(); // lookahead => '.'
2003-
$token = $this->lexer->peek(); // lookahead => token after '.'
2004-
$peek = $this->lexer->peek(); // lookahead => token after the token after the '.'
1988+
$this->lexer->peek(); // lookahead => token after '.'
1989+
$peek = $this->lexer->peek(); // lookahead => token after the token after the '.'
20051990
$this->lexer->resetPeek();
20061991

2007-
if ($token->value === '*') {
2008-
return $this->AllFieldsExpression();
2009-
}
2010-
20111992
if ($this->isMathOperator($peek)) {
20121993
return $this->SimpleArithmeticExpression();
20131994
}

src/Query/SqlWalker.php

Lines changed: 9 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1518,17 +1518,11 @@ public function walkNewObject(AST\NewObjectExpression $newObjectExpression, stri
15181518
{
15191519
$sqlSelectExpressions = [];
15201520
$objIndex = $newObjectResultAlias ?: $this->newObjectCounter++;
1521-
$aliasGap = $newObjectExpression->hasNamedArgs ? null : 0;
15221521

15231522
foreach ($newObjectExpression->args as $argIndex => $e) {
1524-
if (! $newObjectExpression->hasNamedArgs) {
1525-
$argIndex += $aliasGap;
1526-
}
1527-
1528-
$resultAlias = $this->scalarResultCounter++;
1529-
$columnAlias = $this->getSQLColumnAlias('sclr');
1530-
$fieldType = 'string';
1531-
$isScalarResult = true;
1523+
$resultAlias = $this->scalarResultCounter++;
1524+
$columnAlias = $this->getSQLColumnAlias('sclr');
1525+
$fieldType = 'string';
15321526

15331527
switch (true) {
15341528
case $e instanceof AST\NewObjectExpression:
@@ -1582,26 +1576,18 @@ public function walkNewObject(AST\NewObjectExpression $newObjectExpression, stri
15821576
$sqlSelectExpressions[] = trim($e->dispatch($this));
15831577
break;
15841578

1585-
case $e instanceof AST\AllFieldsExpression:
1586-
$isScalarResult = false;
1587-
$sqlSelectExpressions[] = $e->dispatch($this, $objIndex, $argIndex, $aliasGap);
1588-
break;
1589-
15901579
default:
15911580
$sqlSelectExpressions[] = trim($e->dispatch($this)) . ' AS ' . $columnAlias;
15921581
break;
15931582
}
15941583

1595-
if ($isScalarResult) {
1596-
$this->scalarResultAliasMap[$resultAlias] = $columnAlias;
1597-
$this->rsm->addScalarResult($columnAlias, $resultAlias, $fieldType);
1584+
$this->scalarResultAliasMap[$resultAlias] = $columnAlias;
1585+
$this->rsm->addScalarResult($columnAlias, $resultAlias, $fieldType);
15981586

1599-
$this->rsm->newObjectMappings[$columnAlias] = [
1600-
'className' => $newObjectExpression->className,
1601-
'objIndex' => $objIndex,
1602-
'argIndex' => $argIndex,
1603-
];
1604-
}
1587+
$this->rsm->newObjectMappings[$columnAlias] = [
1588+
'objIndex' => $objIndex,
1589+
'argIndex' => $argIndex,
1590+
];
16051591
}
16061592

16071593
$this->rsm->newObject[$objIndex] = $newObjectExpression->className;
@@ -2306,42 +2292,6 @@ public function walkResultVariable(string $resultVariable): string
23062292
return $resultAlias;
23072293
}
23082294

2309-
public function walkAllEntityFieldsExpression(AST\AllFieldsExpression $expression, int|string $objIndex, int|string $argIndex, int|null &$aliasGap): string
2310-
{
2311-
$dqlAlias = $expression->identificationVariable;
2312-
$class = $this->getMetadataForDqlAlias($expression->identificationVariable);
2313-
2314-
$sqlParts = [];
2315-
// Select all fields from the queried class
2316-
foreach ($class->fieldMappings as $fieldName => $mapping) {
2317-
$tableName = isset($mapping->inherited)
2318-
? $this->em->getClassMetadata($mapping->inherited)->getTableName()
2319-
: $class->getTableName();
2320-
2321-
$sqlTableAlias = $this->getSQLTableAlias($tableName, $dqlAlias);
2322-
$columnAlias = $this->getSQLColumnAlias($mapping->columnName);
2323-
$quotedColumnName = $this->quoteStrategy->getColumnName($fieldName, $class, $this->platform);
2324-
2325-
$col = $sqlTableAlias . '.' . $quotedColumnName;
2326-
2327-
$type = Type::getType($mapping->type);
2328-
$col = $type->convertToPHPValueSQL($col, $this->platform);
2329-
2330-
$sqlParts[] = $col . ' AS ' . $columnAlias;
2331-
2332-
$this->scalarResultAliasMap[$objIndex][] = $columnAlias;
2333-
2334-
$this->rsm->addScalarResult($columnAlias, $objIndex, $mapping->type);
2335-
2336-
$this->rsm->newObjectMappings[$columnAlias] = [
2337-
'objIndex' => $objIndex,
2338-
'argIndex' => $aliasGap === null ? $fieldName : (int) $argIndex + $aliasGap++,
2339-
];
2340-
}
2341-
2342-
return implode(', ', $sqlParts);
2343-
}
2344-
23452295
/**
23462296
* @return string The list in parentheses of valid child discriminators from the given class
23472297
*
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\ORM\Tools\Console;
6+
7+
use Symfony\Component\Console\Application;
8+
use Symfony\Component\Console\Command\Command;
9+
10+
use function method_exists;
11+
12+
/**
13+
* Forward compatibility with Symfony Console 7.4
14+
*
15+
* @internal
16+
*/
17+
trait ApplicationCompatibility
18+
{
19+
private static function addCommandToApplication(Application $application, Command $command): Command|null
20+
{
21+
if (method_exists(Application::class, 'addCommand')) {
22+
// @phpstan-ignore method.notFound (This method will be added in Symfony 7.4)
23+
return $application->addCommand($command);
24+
}
25+
26+
return $application->add($command);
27+
}
28+
}

0 commit comments

Comments
 (0)