From b952dac339dc18f22211d39e7e65ddee28d3d96c Mon Sep 17 00:00:00 2001 From: Marius Klocke Date: Tue, 20 Feb 2018 22:33:19 +0100 Subject: [PATCH 1/2] Add a failing test for issue 7062 --- .../ORM/Functional/Ticket/GH7062Test.php | 212 ++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 tests/Doctrine/Tests/ORM/Functional/Ticket/GH7062Test.php diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7062Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7062Test.php new file mode 100644 index 000000000..1d7a2d7cb --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7062Test.php @@ -0,0 +1,212 @@ +setUpEntitySchema( + [ + GH7062Team::class, + GH7062Season::class, + GH7062Ranking::class, + GH7062RankingPosition::class + ] + ); + } + + /** + * @group 7062 + */ + public function testEntityWithAssociationKeyIdentityCanBeUpdated() : void + { + $this->createInitialRankingWithRelatedEntities(); + $this->modifyRanking(); + $this->verifyRanking(); + } + + private function createInitialRankingWithRelatedEntities() : void + { + $team = new GH7062Team(self::TEAM_ID); + $season = new GH7062Season(self::SEASON_ID); + + $season->ranking = new GH7062Ranking($season, [$team]); + + $this->_em->persist($team); + $this->_em->persist($season); + $this->_em->flush(); + $this->_em->clear(); + + foreach ($season->ranking->positions as $position) { + self::assertSame(0, $position->points); + } + } + + private function modifyRanking() : void + { + /** @var GH7062Ranking $ranking */ + $ranking = $this->_em->find(GH7062Ranking::class, self::SEASON_ID); + + foreach ($ranking->positions as $position) { + $position->points += 3; + } + + $this->_em->flush(); + $this->_em->clear(); + } + + private function verifyRanking() : void + { + /** @var GH7062Season $season */ + $season = $this->_em->find(GH7062Season::class, self::SEASON_ID); + self::assertInstanceOf(GH7062Season::class, $season); + + $ranking = $season->ranking; + self::assertInstanceOf(GH7062Ranking::class, $ranking); + + foreach ($ranking->positions as $position) { + self::assertSame(3, $position->points); + } + } +} + +/** + * Simple Entity whose identity is defined through another Entity (Season) + * + * @Entity + * @Table(name="soccer_rankings") + */ +class GH7062Ranking +{ + /** + * @Id + * @OneToOne(targetEntity=GH7062Season::class, inversedBy="ranking") + * @JoinColumn(name="season", referencedColumnName="id") + * + * @var GH7062Season + */ + public $season; + + /** + * @OneToMany(targetEntity=GH7062RankingPosition::class, mappedBy="ranking", cascade={"all"}) + * + * @var Collection|GH7062RankingPosition[] + */ + public $positions; + + /** + * @param GH7062Team[] $teams + */ + public function __construct(GH7062Season $season, array $teams) + { + $this->season = $season; + $this->positions = new ArrayCollection(); + + foreach ($teams as $team) { + $this->positions[] = new GH7062RankingPosition($this, $team); + } + } +} + +/** + * Entity which serves as a identity provider for other entities + * + * @Entity + * @Table(name="soccer_seasons") + */ +class GH7062Season +{ + /** + * @Id + * @Column(type="string") + * + * @var string + */ + public $id; + + /** + * @OneToOne(targetEntity=GH7062Ranking::class, mappedBy="season", cascade={"all"}) + * + * @var GH7062Ranking|null + */ + public $ranking; + + public function __construct(string $id) + { + $this->id = $id; + } +} + +/** + * Entity which serves as a identity provider for other entities + * + * @Entity + * @Table(name="soccer_teams") + */ +class GH7062Team +{ + /** + * @Id + * @Column(type="string") + * + * @var string + */ + public $id; + + public function __construct(string $id) + { + $this->id = $id; + } +} + +/** + * Entity whose identity is defined through two other entities + * + * @Entity + * @Table(name="soccer_ranking_positions") + */ +class GH7062RankingPosition +{ + /** + * @Id + * @ManyToOne(targetEntity=GH7062Ranking::class, inversedBy="positions") + * @JoinColumn(name="season", referencedColumnName="season") + * + * @var GH7062Ranking + */ + public $ranking; + + /** + * @Id + * @ManyToOne(targetEntity=GH7062Team::class) + * @JoinColumn(name="team_id", referencedColumnName="id") + * + * @var GH7062Team + */ + public $team; + + /** + * @Column(type="integer") + * + * @var int + */ + public $points; + + public function __construct(GH7062Ranking $ranking, GH7062Team $team) + { + $this->ranking = $ranking; + $this->team = $team; + $this->points = 0; + } +} From d47c1f3e9b3c6a9b6df8de760fbfb7a33f13d2e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Cobucci?= Date: Sun, 25 Feb 2018 22:35:46 +0100 Subject: [PATCH 2/2] Fix basic entity persister type resolver Which was using the wrong way to fetch the field type and using the association type instead of the column type. --- .../Persisters/Entity/BasicEntityPersister.php | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php index 2797a76e9..14344d9f6 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php @@ -37,6 +37,8 @@ use Doctrine\ORM\Query; use Doctrine\ORM\UnitOfWork; use Doctrine\ORM\Utility\IdentifierFlattener; use Doctrine\ORM\Utility\PersisterHelper; +use function array_merge; +use function reset; /** * A BasicEntityPersister maps an entity to a single table in a relational database. @@ -459,20 +461,13 @@ class BasicEntityPersister implements EntityPersister ); $targetMapping = $this->em->getClassMetadata($this->class->associationMappings[$idField]['targetEntity']); + $targetType = PersisterHelper::getTypeOfField($targetMapping->identifier[0], $targetMapping, $this->em); - switch (true) { - case (isset($targetMapping->fieldMappings[$targetMapping->identifier[0]])): - $types[] = $targetMapping->fieldMappings[$targetMapping->identifier[0]]['type']; - break; - - case (isset($targetMapping->associationMappings[$targetMapping->identifier[0]])): - $types[] = $targetMapping->associationMappings[$targetMapping->identifier[0]]['type']; - break; - - default: - throw ORMException::unrecognizedField($targetMapping->identifier[0]); + if ($targetType === []) { + throw ORMException::unrecognizedField($targetMapping->identifier[0]); } + $types[] = reset($targetType); } if ($versioned) {