Skip to content

Commit

Permalink
Merge branch '2.14.x' into 3.0.x
Browse files Browse the repository at this point in the history
* 2.14.x:
  PHPStan 1.8.5, Psalm 4.27.0 (#10033)
  Fix EnumType not being hydrated with HYDRATE_ARRAY (#9995)
  "Strange" return lines in documentation of inheritance-mapping.rst (#10027)
  More strange break lines in inheritance-mapping.rst (#10028)
  Add phpdoc for discriminatorColumn
  • Loading branch information
derrabus committed Sep 22, 2022
2 parents 57054ca + 86000d9 commit a3ec3f3
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 16 deletions.
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@
"doctrine/annotations": "^1.13",
"doctrine/coding-standard": "^10.0",
"phpbench/phpbench": "^1.0",
"phpstan/phpstan": "1.8.2",
"phpstan/phpstan": "1.8.5",
"phpunit/phpunit": "^9.5",
"psr/log": "^1 || ^2 || ^3",
"squizlabs/php_codesniffer": "3.7.1",
"symfony/cache": "^4.4 || ^5.4 || ^6.0",
"vimeo/psalm": "4.26.0"
"vimeo/psalm": "4.27.0"
},
"conflict": {
"doctrine/annotations": "<1.13 || >= 2.0"
Expand Down
12 changes: 6 additions & 6 deletions docs/en/reference/inheritance-mapping.rst
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,9 @@ relationships involving types that employ this mapping strategy are
very performing.

There is a general performance consideration with Single Table
Inheritance: If the target-entity of a many-to-one or one-to-one
association is an STI entity, it is preferable for performance reasons that it
be a leaf entity in the inheritance hierarchy, (ie. have no subclasses).
Inheritance: If the target-entity of a many-to-one or one-to-one
association is an STI entity, it is preferable for performance reasons that it
be a leaf entity in the inheritance hierarchy, (ie. have no subclasses).
Otherwise Doctrine *CANNOT* create proxy instances
of this entity and will *ALWAYS* load the entity eagerly.

Expand Down Expand Up @@ -269,9 +269,9 @@ themselves on access of any subtype fields, so accessing fields of
subtypes after such a query is not safe.

There is a general performance consideration with Class Table
Inheritance: If the target-entity of a many-to-one or one-to-one
association is a CTI entity, it is preferable for performance reasons that it
be a leaf entity in the inheritance hierarchy, (ie. have no subclasses).
Inheritance: If the target-entity of a many-to-one or one-to-one
association is a CTI entity, it is preferable for performance reasons that it
be a leaf entity in the inheritance hierarchy, (ie. have no subclasses).
Otherwise Doctrine *CANNOT* create proxy instances
of this entity and will *ALWAYS* load the entity eagerly.

Expand Down
2 changes: 1 addition & 1 deletion lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,7 @@ protected function registerManaged(ClassMetadata $class, object $entity, array $
*
* @return BackedEnum|array<BackedEnum>
*/
private function buildEnum($value, string $enumType)
protected function buildEnum($value, string $enumType)
{
if (is_array($value)) {
return array_map(
Expand Down
34 changes: 34 additions & 0 deletions lib/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ class ArrayHydrator extends AbstractHydrator

private int $_resultCounter = 0;

/**
* The cache used during enum processing.
*
* @var array<string, mixed>
*/
private array $_enumCache = [];

protected function prepare(): void
{
$this->_isSimpleQuery = count($this->resultSetMapping()->aliasMap) <= 1;
Expand Down Expand Up @@ -71,6 +78,9 @@ protected function hydrateRowData(array $row, array &$result): void

// 2) Now hydrate the data found in the current row.
foreach ($rowData['data'] as $dqlAlias => $data) {
// build enums if exists
$this->processEnums($dqlAlias, $data);

$index = false;

if (isset($this->resultSetMapping()->parentAliasMap[$dqlAlias])) {
Expand Down Expand Up @@ -269,4 +279,28 @@ private function updateResultPointer(

$this->_resultPointers[$dqlAlias] =& $coll[array_key_last($coll)];
}

/** @param mixed[] $data */
private function processEnums(string $dqlAlias, array &$data): void
{
// init cache
if (! isset($this->_enumCache[$dqlAlias])) {
$this->_enumCache[$dqlAlias] = [];

$className = $this->resultSetMapping()->aliasMap[$dqlAlias];
$classMetadata = $this->getClassMetadata($className);

foreach ($classMetadata->fieldMappings as $key => $fieldMapping) {
if (isset($fieldMapping['enumType'])) {
$this->_enumCache[$dqlAlias][$key] = $fieldMapping['enumType'];
}
}
}

foreach ($data as $key => $value) {
if (isset($this->_enumCache[$dqlAlias][$key]) && $value !== null) {
$data[$key] = $this->buildEnum($value, $this->_enumCache[$dqlAlias][$key]);
}
}
}
}
4 changes: 2 additions & 2 deletions lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,7 @@ class ClassMetadataInfo implements ClassMetadata
* READ-ONLY: The definition of the discriminator column used in JOINED and SINGLE_TABLE
* inheritance mappings.
*
* @psalm-var array<string, mixed>|null
* @psalm-var array{name: string, fieldName: string, type: string, length?: int, columnDefinition?: string|null}|null
*/
public $discriminatorColumn;

Expand Down Expand Up @@ -2912,7 +2912,7 @@ public function addEntityListener($eventName, $class, $method)
* @see getDiscriminatorColumn()
*
* @param mixed[]|null $columnDef
* @psalm-param array<string, mixed>|null $columnDef
* @psalm-param array{name: string|null, fieldName?: string, type?: string, length?: int, columnDefinition?: string|null}|null $columnDef
*
* @return void
*
Expand Down
8 changes: 4 additions & 4 deletions lib/Doctrine/ORM/Mapping/Driver/AttributeDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -242,10 +242,10 @@ public function loadMetadataForClass($className, PersistenceClassMetadata $metad

$metadata->setDiscriminatorColumn(
[
'name' => $discrColumnAttribute->name,
'type' => $discrColumnAttribute->type ?: 'string',
'length' => $discrColumnAttribute->length ?: 255,
'columnDefinition' => $discrColumnAttribute->columnDefinition,
'name' => isset($discrColumnAttribute->name) ? (string) $discrColumnAttribute->name : null,
'type' => isset($discrColumnAttribute->type) ? (string) $discrColumnAttribute->type : 'string',
'length' => isset($discrColumnAttribute->length) ? (int) $discrColumnAttribute->length : 255,
'columnDefinition' => isset($discrColumnAttribute->columnDefinition) ? (string) $discrColumnAttribute->columnDefinition : null,
],
);
} else {
Expand Down
5 changes: 5 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ parameters:
message: '~^Match expression does not handle remaining values:~'
path: lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php

# https://github.com/phpstan/phpstan/issues/7292
-
message: '#^Offset class\-string on non\-empty\-array\<class\-string, array\<string, mixed\>\> in isset\(\) always exists and is not nullable\.$#'
path: lib/Doctrine/ORM/UnitOfWork.php

# DBAL 4 compatibility
-
message: '~^Method Doctrine\\ORM\\Query\\AST\\Functions\\TrimFunction::getTrimMode\(\) never returns .* so it can be removed from the return type\.$~'
Expand Down
2 changes: 1 addition & 1 deletion psalm-baseline.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="4.26.0@6998fabb2bf528b65777bf9941920888d23c03ac">
<files psalm-version="4.27.0@faf106e717c37b8c81721845dba9de3d8deed8ff">
<file src="lib/Doctrine/ORM/AbstractQuery.php">
<FalsableReturnStatement occurrences="1">
<code>! $filteredParameters-&gt;isEmpty() ? $filteredParameters-&gt;first() : null</code>
Expand Down
73 changes: 73 additions & 0 deletions tests/Doctrine/Tests/ORM/Hydration/ArrayHydratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
use Doctrine\Tests\Models\CMS\CmsComment;
use Doctrine\Tests\Models\CMS\CmsPhonenumber;
use Doctrine\Tests\Models\CMS\CmsUser;
use Doctrine\Tests\Models\Enums\Card;
use Doctrine\Tests\Models\Enums\Suit;
use Doctrine\Tests\Models\Forum\ForumBoard;
use Doctrine\Tests\Models\Forum\ForumCategory;

Expand Down Expand Up @@ -1216,4 +1218,75 @@ public function testIndexByAndMixedResult(int|string $userEntityKey): void
self::assertArrayHasKey(2, $result);
self::assertEquals(2, $result[2][$userEntityKey]['id']);
}

/** @requires PHP 8.1 */
public function testArrayResultWithEnumField(): void
{
$rsm = new ResultSetMapping();

$rsm->addEntityResult(Card::class, 'c');
$rsm->addFieldResult('c', 'c__id', 'id');
$rsm->addFieldResult('c', 'c__suit', 'suit');
$rsm->addIndexBy('c', 'id');

// Faked result set
$resultSet = [
//row1
[
'c__id' => '1',
'c__suit' => 'H',
],
[
'c__id' => '2',
'c__suit' => 'D',
],
];

$stmt = $this->createResultMock($resultSet);
$hydrator = new ArrayHydrator($this->entityManager);
$result = $hydrator->hydrateAll($stmt, $rsm);

self::assertCount(2, $result);

self::assertEquals(1, $result[1]['id']);
self::assertEquals(Suit::Hearts, $result[1]['suit']);

self::assertEquals(2, $result[2]['id']);
self::assertEquals(Suit::Diamonds, $result[2]['suit']);
}

/** @requires PHP 8.1 */
public function testScalarResultWithEnumField(): void
{
$rsm = new ResultSetMapping();

$rsm->addEntityResult(Card::class, 'c');
$rsm->addScalarResult('c__suit', 'someAlias', 'string');
$rsm->addEnumResult('c__suit', Suit::class);

// Faked result set
$resultSet = [
//row1
[
'c__id' => '1',
'c__suit' => 'C',
],
[
'c__id' => '2',
'c__suit' => 'S',
],
];

$stmt = $this->createResultMock($resultSet);
$hydrator = new ArrayHydrator($this->entityManager);
$result = $hydrator->hydrateAll($stmt, $rsm);

self::assertCount(2, $result);

self::assertCount(1, $result[0]); //assert that in each result we have only one "someAlias" field
self::assertEquals(Suit::Clubs, $result[0]['someAlias']);

self::assertCount(1, $result[1]);
self::assertEquals(Suit::Spades, $result[1]['someAlias']);
}
}

0 comments on commit a3ec3f3

Please sign in to comment.