Skip to content

Commit

Permalink
Keep the declared mapping information when using attribute overrides (
Browse files Browse the repository at this point in the history
#11135)

When using `AttributeOverride` to override mapping information inherited from a parent class (a mapped superclass), make sure to keep information about where the field was originally declared.

This is important for `private` fields: Without the correct `declared` information, it will lead to errors when cached mapping information is loaded, reflection wakes up and looks for the private field in the wrong class.
  • Loading branch information
mpdude authored Jan 12, 2024
1 parent 3dd3d38 commit a8632ac
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 0 deletions.
4 changes: 4 additions & 0 deletions lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -2558,6 +2558,10 @@ public function setAttributeOverride($fieldName, array $overrideMapping)
$overrideMapping['id'] = $mapping['id'];
}

if (isset($mapping['declared'])) {
$overrideMapping['declared'] = $mapping['declared'];
}

if (! isset($overrideMapping['type'])) {
$overrideMapping['type'] = $mapping['type'];
}
Expand Down
73 changes: 73 additions & 0 deletions tests/Doctrine/Tests/ORM/Functional/Ticket/GH11135Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\ORM\Functional\Ticket;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Tests\OrmFunctionalTestCase;

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

$this->setUpEntitySchema([
GH11135MappedSuperclass::class,
GH11135EntityWithOverride::class,
GH11135EntityWithoutOverride::class,
]);
}

public function testOverrideInheritsDeclaringClass(): void
{
$cm1 = $this->_em->getClassMetadata(GH11135EntityWithOverride::class);
$cm2 = $this->_em->getClassMetadata(GH11135EntityWithoutOverride::class);

self::assertSame($cm1->getFieldMapping('id')['declared'], $cm2->getFieldMapping('id')['declared']);
self::assertSame($cm1->getAssociationMapping('ref')['declared'], $cm2->getAssociationMapping('ref')['declared']);
}
}

/**
* @ORM\MappedSuperclass
*/
class GH11135MappedSuperclass
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue
*
* @var int
*/
private $id;

/**
* @ORM\ManyToOne(targetEntity="GH11135EntityWithoutOverride")
*
* @var GH11135EntityWithoutOverride
*/
private $ref;
}

/**
* @ORM\Entity()
* @ORM\AttributeOverrides({
* @ORM\AttributeOverride(name="id", column=@ORM\Column(name="id_overridden"))
* })
* @ORM\AssociationOverrides({
* @ORM\AssociationOverride(name="ref", joinColumns=@ORM\JoinColumn(name="ref_overridden", referencedColumnName="id"))
* })
*/
class GH11135EntityWithOverride extends GH11135MappedSuperclass
{
}

/**
* @ORM\Entity()
*/
class GH11135EntityWithoutOverride extends GH11135MappedSuperclass
{
}
26 changes: 26 additions & 0 deletions tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
use Doctrine\Tests\Models\DDC6412\DDC6412File;
use Doctrine\Tests\Models\DDC964\DDC964Admin;
use Doctrine\Tests\Models\DDC964\DDC964Guest;
use Doctrine\Tests\Models\DirectoryTree\AbstractContentItem;
use Doctrine\Tests\Models\DirectoryTree\Directory;
use Doctrine\Tests\Models\Routing\RoutingLeg;
use Doctrine\Tests\Models\TypedProperties;
use Doctrine\Tests\ORM\Mapping\TypedFieldMapper\CustomIntAsStringTypedFieldMapper;
Expand Down Expand Up @@ -1186,6 +1188,30 @@ public function testInvalidOverrideAttributeFieldTypeException(): void
$cm->setAttributeOverride('name', ['type' => 'date']);
}

public function testAttributeOverrideKeepsDeclaringClass(): void
{
$cm = new ClassMetadata(Directory::class);
$cm->mapField(['fieldName' => 'id', 'type' => 'integer', 'declared' => AbstractContentItem::class]);
$cm->setAttributeOverride('id', ['columnName' => 'new_id']);

$mapping = $cm->getFieldMapping('id');

self::assertArrayHasKey('declared', $mapping);
self::assertSame(AbstractContentItem::class, $mapping['declared']);
}

public function testAssociationOverrideKeepsDeclaringClass(): void
{
$cm = new ClassMetadata(Directory::class);
$cm->mapManyToOne(['fieldName' => 'parentDirectory', 'targetEntity' => Directory::class, 'cascade' => ['remove'], 'declared' => Directory::class]);
$cm->setAssociationOverride('parentDirectory', ['cascade' => '']);

$mapping = $cm->getAssociationMapping('parentDirectory');

self::assertArrayHasKey('declared', $mapping);
self::assertSame(Directory::class, $mapping['declared']);
}

/** @group DDC-1955 */
public function testInvalidEntityListenerClassException(): void
{
Expand Down

0 comments on commit a8632ac

Please sign in to comment.