Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/2.17.x' into 3.0.x
Browse files Browse the repository at this point in the history
  • Loading branch information
greg0ire committed Oct 21, 2023
2 parents ad519a5 + 16028e4 commit 1fef319
Show file tree
Hide file tree
Showing 17 changed files with 130 additions and 65 deletions.
32 changes: 18 additions & 14 deletions docs/en/reference/architecture.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,34 @@ performance it is also recommended that you use APC with PHP.
Doctrine ORM Packages
-------------------

Doctrine ORM is divided into three main packages.
Doctrine ORM is divided into four main packages.

- Common
- DBAL (includes Common)
- ORM (includes DBAL+Common)
- `Collections <https://www.doctrine-project.org/projects/doctrine-collections/en/stable/index.html>`_
- `Event Manager <https://www.doctrine-project.org/projects/doctrine-event-manager/en/stable/index.html>`_
- `Persistence <https://www.doctrine-project.org/projects/doctrine-persistence/en/stable/index.html>`_
- `DBAL <https://www.doctrine-project.org/projects/doctrine-dbal/en/stable/index.html>`_
- ORM (depends on DBAL+Persistence+Collections)

This manual mainly covers the ORM package, sometimes touching parts
of the underlying DBAL and Common packages. The Doctrine code base
of the underlying DBAL and Persistence packages. The Doctrine code base
is split in to these packages for a few reasons and they are to...


- ...make things more maintainable and decoupled
- ...allow you to use the code in Doctrine Common without the ORM
or DBAL
- ...allow you to use the code in Doctrine Persistence and Collections
without the ORM or DBAL
- ...allow you to use the DBAL without the ORM

The Common Package
~~~~~~~~~~~~~~~~~~
Collection, Event Manager and Persistence
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The Common package contains highly reusable components that have no
dependencies beyond the package itself (and PHP, of course). The
root namespace of the Common package is ``Doctrine\Common``.
The Collection, Event Manager and Persistence packages contain highly
reusable components that have no dependencies beyond the packages
themselves (and PHP, of course). The root namespace of the Persistence
package is ``Doctrine\Persistence``. The root namespace of the
Collection package is ``Doctrine\Common\Collections``, for historical
reasons. The root namespace of the Event Manager package is just
``Doctrine\Common``, also for historical reasons.

The DBAL Package
~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -199,5 +205,3 @@ typical implementation of the
to keep track of all the things that need to be done the next time
``flush`` is invoked. You usually do not directly interact with a
``UnitOfWork`` but with the ``EntityManager`` instead.


2 changes: 1 addition & 1 deletion lib/Doctrine/ORM/Query/AST/ConditionalFactor.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*
* @link www.doctrine-project.org
*/
class ConditionalFactor extends Node
class ConditionalFactor extends Node implements Phase2OptimizableConditional
{
/** @param ConditionalPrimary $conditionalPrimary */
public function __construct(
Expand Down
4 changes: 2 additions & 2 deletions lib/Doctrine/ORM/Query/AST/ConditionalPrimary.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
*
* @link www.doctrine-project.org
*/
class ConditionalPrimary extends Node
class ConditionalPrimary extends Node implements Phase2OptimizableConditional
{
/** @var Node|null */
public $simpleConditionalExpression;

/** @var ConditionalExpression|null */
/** @var ConditionalExpression|Phase2OptimizableConditional|null */
public $conditionalExpression;

public function isSimpleConditionalExpression(): bool
Expand Down
2 changes: 1 addition & 1 deletion lib/Doctrine/ORM/Query/AST/ConditionalTerm.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*
* @link www.doctrine-project.org
*/
class ConditionalTerm extends Node
class ConditionalTerm extends Node implements Phase2OptimizableConditional
{
/** @param mixed[] $conditionalFactors */
public function __construct(public array $conditionalFactors)
Expand Down
2 changes: 1 addition & 1 deletion lib/Doctrine/ORM/Query/AST/HavingClause.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

class HavingClause extends Node
{
/** @param ConditionalExpression $conditionalExpression */
/** @param ConditionalExpression|Phase2OptimizableConditional $conditionalExpression */
public function __construct(public $conditionalExpression)
{
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Doctrine/ORM/Query/AST/Join.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class Join extends Node
final public const JOIN_TYPE_LEFTOUTER = 2;
final public const JOIN_TYPE_INNER = 3;

/** @var ConditionalExpression|null */
/** @var ConditionalExpression|Phase2OptimizableConditional|null */
public $conditionalExpression = null;

/**
Expand Down
17 changes: 17 additions & 0 deletions lib/Doctrine/ORM/Query/AST/Phase2OptimizableConditional.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace Doctrine\ORM\Query\AST;

/**
* Marks types that can be used in place of a ConditionalExpression as a phase
* 2 optimization.
*
* @internal
*
* @psalm-inheritors ConditionalPrimary|ConditionalFactor|ConditionalTerm
*/
interface Phase2OptimizableConditional
{
}
2 changes: 1 addition & 1 deletion lib/Doctrine/ORM/Query/AST/WhenClause.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*/
class WhenClause extends Node
{
/** @param ConditionalExpression $caseConditionExpression */
/** @param ConditionalExpression|Phase2OptimizableConditional $caseConditionExpression */
public function __construct(
public $caseConditionExpression,
public mixed $thenScalarExpression = null,
Expand Down
2 changes: 1 addition & 1 deletion lib/Doctrine/ORM/Query/AST/WhereClause.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*/
class WhereClause extends Node
{
/** @param ConditionalExpression|ConditionalTerm $conditionalExpression */
/** @param ConditionalExpression|Phase2OptimizableConditional $conditionalExpression */
public function __construct(public $conditionalExpression)
{
}
Expand Down
5 changes: 5 additions & 0 deletions lib/Doctrine/ORM/Query/ResultSetMappingBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ protected function addAllClassFields(string $class, string $alias, array $column
}

$this->addFieldResult($alias, $columnAlias, $propertyName);

$enumType = $classMetadata->getFieldMapping($propertyName)['enumType'] ?? null;
if (! empty($enumType)) {
$this->addEnumResult($columnAlias, $enumType);
}
}

foreach ($classMetadata->associationMappings as $associationMapping) {
Expand Down
4 changes: 2 additions & 2 deletions lib/Doctrine/ORM/Query/SqlWalker.php
Original file line number Diff line number Diff line change
Expand Up @@ -865,7 +865,7 @@ private function generateRangeVariableDeclarationSQL(
public function walkJoinAssociationDeclaration(
AST\JoinAssociationDeclaration $joinAssociationDeclaration,
int $joinType = AST\Join::JOIN_TYPE_INNER,
AST\ConditionalPrimary|null $condExpr = null,
AST\ConditionalExpression|AST\Phase2OptimizableConditional|null $condExpr = null,
): string {
$sql = '';

Expand Down Expand Up @@ -1724,7 +1724,7 @@ public function walkWhereClause(AST\WhereClause|null $whereClause): string
* Walk down a ConditionalExpression AST node, thereby generating the appropriate SQL.
*/
public function walkConditionalExpression(
AST\ConditionalExpression|AST\ConditionalPrimary|AST\ConditionalTerm|AST\ConditionalFactor $condExpr,
AST\ConditionalExpression|AST\Phase2OptimizableConditional $condExpr,
): string {
// Phase 2 AST optimization: Skip processing of ConditionalExpression
// if only one ConditionalTerm is defined
Expand Down
6 changes: 1 addition & 5 deletions lib/Doctrine/ORM/Tools/Pagination/WhereInWalker.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

use Doctrine\ORM\Query\AST\ArithmeticExpression;
use Doctrine\ORM\Query\AST\ConditionalExpression;
use Doctrine\ORM\Query\AST\ConditionalFactor;
use Doctrine\ORM\Query\AST\ConditionalPrimary;
use Doctrine\ORM\Query\AST\ConditionalTerm;
use Doctrine\ORM\Query\AST\InListExpression;
Expand Down Expand Up @@ -96,10 +95,7 @@ public function walkSelectStatement(SelectStatement $selectStatement): void
),
],
);
} elseif (
$selectStatement->whereClause->conditionalExpression instanceof ConditionalExpression
|| $selectStatement->whereClause->conditionalExpression instanceof ConditionalFactor
) {
} else {
$tmpPrimary = new ConditionalPrimary();
$tmpPrimary->conditionalExpression = $selectStatement->whereClause->conditionalExpression;
$selectStatement->whereClause->conditionalExpression = new ConditionalTerm(
Expand Down
12 changes: 1 addition & 11 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ parameters:
path: lib/Doctrine/ORM/Query/SqlWalker.php

-
message: "#^Parameter \\#3 \\$condExpr of method Doctrine\\\\ORM\\\\Query\\\\SqlWalker\\:\\:walkJoinAssociationDeclaration\\(\\) expects Doctrine\\\\ORM\\\\Query\\\\AST\\\\ConditionalPrimary\\|null, Doctrine\\\\ORM\\\\Query\\\\AST\\\\ConditionalExpression\\|null given\\.$#"
message: "#^Parameter \\#1 \\$condTerm of method Doctrine\\\\ORM\\\\Query\\\\SqlWalker\\:\\:walkConditionalTerm\\(\\) expects Doctrine\\\\ORM\\\\Query\\\\AST\\\\ConditionalFactor\\|Doctrine\\\\ORM\\\\Query\\\\AST\\\\ConditionalPrimary\\|Doctrine\\\\ORM\\\\Query\\\\AST\\\\ConditionalTerm, Doctrine\\\\ORM\\\\Query\\\\AST\\\\Phase2OptimizableConditional given\\.$#"
count: 1
path: lib/Doctrine/ORM/Query/SqlWalker.php

Expand All @@ -300,16 +300,6 @@ parameters:
count: 1
path: lib/Doctrine/ORM/Tools/Console/Command/MappingDescribeCommand.php

-
message: "#^Instanceof between \\*NEVER\\* and Doctrine\\\\ORM\\\\Query\\\\AST\\\\ConditionalFactor will always evaluate to false\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/Pagination/WhereInWalker.php

-
message: "#^Instanceof between Doctrine\\\\ORM\\\\Query\\\\AST\\\\ConditionalExpression and Doctrine\\\\ORM\\\\Query\\\\AST\\\\ConditionalPrimary will always evaluate to false\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/Pagination/WhereInWalker.php

-
message: "#^Else branch is unreachable because ternary operator condition is always true\\.$#"
count: 1
Expand Down
25 changes: 0 additions & 25 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1002,18 +1002,11 @@
</PossiblyFalseArgument>
<PossiblyInvalidArgument>
<code>$AST</code>
<code>$conditionalExpression</code>
<code>$expr</code>
<code><![CDATA[$this->ConditionalExpression()]]></code>
<code><![CDATA[$this->ConditionalExpression()]]></code>
<code><![CDATA[$this->lexer->getLiteral($token)]]></code>
<code><![CDATA[$this->lexer->getLiteral($token)]]></code>
<code><![CDATA[$this->lexer->getLiteral($token)]]></code>
</PossiblyInvalidArgument>
<PossiblyInvalidPropertyAssignmentValue>
<code><![CDATA[$this->ConditionalExpression()]]></code>
<code><![CDATA[$this->ConditionalExpression()]]></code>
</PossiblyInvalidPropertyAssignmentValue>
<PossiblyNullArgument>
<code>$dql</code>
<code><![CDATA[$this->query->getDQL()]]></code>
Expand Down Expand Up @@ -1046,9 +1039,6 @@
<code><![CDATA[$this->conn->quote((string) $newValue)]]></code>
<code>throw QueryException::invalidLiteral($literal)</code>
</DocblockTypeContradiction>
<InvalidArgument>
<code><![CDATA[$join->conditionalExpression]]></code>
</InvalidArgument>
<PossiblyInvalidArgument>
<code>$expr</code>
</PossiblyInvalidArgument>
Expand Down Expand Up @@ -1208,21 +1198,6 @@
<code>$orderByClause</code>
</PropertyNotSetInConstructor>
</file>
<file src="lib/Doctrine/ORM/Tools/Pagination/WhereInWalker.php">
<DocblockTypeContradiction>
<code><![CDATA[$selectStatement->whereClause->conditionalExpression instanceof ConditionalExpression
|| $selectStatement->whereClause->conditionalExpression instanceof ConditionalFactor]]></code>
<code><![CDATA[$selectStatement->whereClause->conditionalExpression instanceof ConditionalFactor]]></code>
<code><![CDATA[$selectStatement->whereClause->conditionalExpression instanceof ConditionalPrimary]]></code>
</DocblockTypeContradiction>
<PossiblyInvalidPropertyAssignmentValue>
<code><![CDATA[$selectStatement->whereClause->conditionalExpression]]></code>
</PossiblyInvalidPropertyAssignmentValue>
<RedundantConditionGivenDocblockType>
<code><![CDATA[$selectStatement->whereClause->conditionalExpression instanceof ConditionalExpression
|| $selectStatement->whereClause->conditionalExpression instanceof ConditionalFactor]]></code>
</RedundantConditionGivenDocblockType>
</file>
<file src="lib/Doctrine/ORM/Tools/SchemaTool.php">
<ArgumentTypeCoercion>
<code>$classes</code>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\ORM\Functional\Ticket\GH11017;

use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
class GH11017Entity
{
/** @var ?int */
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
public $id;

/** @var GH11017Enum */
#[ORM\Column(type: 'string', enumType: GH11017Enum::class)]
public $field;
}
11 changes: 11 additions & 0 deletions tests/Doctrine/Tests/ORM/Functional/Ticket/GH11017/GH11017Enum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\ORM\Functional\Ticket\GH11017;

enum GH11017Enum: string
{
case FIRST = 'first';
case SECOND = 'second';
}
46 changes: 46 additions & 0 deletions tests/Doctrine/Tests/ORM/Functional/Ticket/GH11017/GH11017Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\ORM\Functional\Ticket\GH11017;

use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\Query\ResultSetMappingBuilder;
use Doctrine\Tests\OrmFunctionalTestCase;

use function sprintf;

class GH11017Test extends OrmFunctionalTestCase
{
protected function setUp(): void
{
parent::setUp();

$this->setUpEntitySchema([
GH11017Entity::class,
]);
}

public function testPostPersistListenerUpdatingObjectFieldWhileOtherInsertPending(): void
{
$entity1 = new GH11017Entity();
$entity1->field = GH11017Enum::FIRST;
$this->_em->persist($entity1);

$this->_em->flush();
$this->_em->clear();

$rsm = new ResultSetMappingBuilder($this->_em, ResultSetMappingBuilder::COLUMN_RENAMING_INCREMENT);
$rsm->addRootEntityFromClassMetadata(GH11017Entity::class, 'e');

$tableName = $this->_em->getClassMetadata(GH11017Entity::class)->getTableName();
$sql = sprintf('SELECT %s FROM %s e WHERE id = :id', $rsm->generateSelectClause(), $tableName);

$query = $this->_em->createNativeQuery($sql, $rsm)
->setParameter('id', $entity1->id);

$entity1Reloaded = $query->getSingleResult(AbstractQuery::HYDRATE_ARRAY);
self::assertNotNull($entity1Reloaded);
self::assertSame($entity1->field, $entity1Reloaded['field']);
}
}

0 comments on commit 1fef319

Please sign in to comment.