From 88a2fc2dd058c6e62a376711837d3ea95f1981e8 Mon Sep 17 00:00:00 2001 From: Mike Yudin Date: Sun, 14 Apr 2024 08:44:40 -0400 Subject: [PATCH 1/3] Add join table to cacheKey name to allow for multiple many-to-many relationships to the same associated entity. --- src/EventListener/LogRevisionsListener.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/EventListener/LogRevisionsListener.php b/src/EventListener/LogRevisionsListener.php index 71917d0e..ee41c43a 100644 --- a/src/EventListener/LogRevisionsListener.php +++ b/src/EventListener/LogRevisionsListener.php @@ -464,7 +464,8 @@ private function getInsertRevisionSQL(EntityManagerInterface $em, ClassMetadata */ private function getInsertJoinTableRevisionSQL(ClassMetadata $class, ClassMetadata $targetClass, array $assoc): string { - $cacheKey = $class->name.'.'.$targetClass->name; + $cacheKey = $class->name.'.'.$targetClass->name.'.'.$assoc['joinTable']['name']; + if (!isset($this->insertJoinTableRevisionSQL[$cacheKey]) && isset($assoc['relationToSourceKeyColumns'], $assoc['relationToTargetKeyColumns'], $assoc['joinTable']['name'])) { $placeholders = ['?', '?']; From 04498b1628fec973aae52b2716089c42f02c2ec6 Mon Sep 17 00:00:00 2001 From: Mike Yudin Date: Sun, 14 Apr 2024 10:14:22 -0400 Subject: [PATCH 2/3] Add Tests to ensure an entity can have multiple relationships to the same target entity. Tests and closes #614 --- .../ManyToManyMultipleRelationshipEntity.php | 93 +++++++++++++++++++ .../ManyToManyMultipleTargetEntity.php | 38 ++++++++ tests/RelationTest.php | 44 +++++++++ 3 files changed, 175 insertions(+) create mode 100644 tests/Fixtures/Relation/ManyToManyMultipleRelationshipEntity.php create mode 100644 tests/Fixtures/Relation/ManyToManyMultipleTargetEntity.php diff --git a/tests/Fixtures/Relation/ManyToManyMultipleRelationshipEntity.php b/tests/Fixtures/Relation/ManyToManyMultipleRelationshipEntity.php new file mode 100644 index 00000000..9aa04e15 --- /dev/null +++ b/tests/Fixtures/Relation/ManyToManyMultipleRelationshipEntity.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\EntityAuditBundle\Tests\Fixtures\Relation; + +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; +use Doctrine\DBAL\Types\Types; +use Doctrine\ORM\Mapping as ORM; + +#[ORM\Entity] +class ManyToManyMultipleRelationshipEntity +{ + /** + * @var int|null + */ + #[ORM\Id] + #[ORM\Column(type: Types::INTEGER)] + #[ORM\GeneratedValue] + protected $id; + + /** + * @var string|null + */ + #[ORM\Column(type: Types::STRING)] + protected $title; + + /** + * @var Collection + */ + #[ORM\ManyToMany(targetEntity: ManyToManyMultipleTargetEntity::class)] + #[ORM\JoinTable(name: 'many_to_many_primary_target')] + protected $primaryTargets = []; + + /** + * @var Collection + */ + #[ORM\ManyToMany(targetEntity: ManyToManyMultipleTargetEntity::class)] + #[ORM\JoinTable(name: 'many_to_many_secondary_target')] + protected $secondaryTargets; + + public function __construct() + { + $this->primaryTargets = new ArrayCollection(); + $this->secondaryTargets = new ArrayCollection(); + } + + + public function getId(): ?int + { + return $this->id; + } + + public function getTitle(): ?string + { + return $this->title; + } + + public function setTitle(string $title): void + { + $this->title = $title; + } + + public function getPrimaryTargets(): ArrayCollection|Collection|array + { + return $this->primaryTargets; + } + + public function addPrimaryTarget(ManyToManyMultipleTargetEntity $target): void + { + $this->primaryTargets[] = $target; + } + + public function getSecondaryTargets(): ArrayCollection|Collection + { + return $this->secondaryTargets; + } + + public function addSecondaryTarget(ManyToManyMultipleTargetEntity $target): void + { + $this->secondaryTargets[] = $target; + } +} diff --git a/tests/Fixtures/Relation/ManyToManyMultipleTargetEntity.php b/tests/Fixtures/Relation/ManyToManyMultipleTargetEntity.php new file mode 100644 index 00000000..98050cbf --- /dev/null +++ b/tests/Fixtures/Relation/ManyToManyMultipleTargetEntity.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\EntityAuditBundle\Tests\Fixtures\Relation; + +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; +use Doctrine\DBAL\Types\Types; +use Doctrine\ORM\Mapping as ORM; + +#[ORM\Entity] +class ManyToManyMultipleTargetEntity +{ + /** + * @var int|null + */ + #[ORM\Id] + #[ORM\Column(type: Types::INTEGER)] + #[ORM\GeneratedValue] + protected $id; + + + public function getId(): ?int + { + return $this->id; + } + +} diff --git a/tests/RelationTest.php b/tests/RelationTest.php index cfcf3aa4..5a209d83 100644 --- a/tests/RelationTest.php +++ b/tests/RelationTest.php @@ -22,6 +22,8 @@ use Sonata\EntityAuditBundle\Tests\Fixtures\Relation\DataLegalEntity; use Sonata\EntityAuditBundle\Tests\Fixtures\Relation\DataPrivateEntity; use Sonata\EntityAuditBundle\Tests\Fixtures\Relation\FoodCategory; +use Sonata\EntityAuditBundle\Tests\Fixtures\Relation\ManyToManyMultipleRelationshipEntity; +use Sonata\EntityAuditBundle\Tests\Fixtures\Relation\ManyToManyMultipleTargetEntity; use Sonata\EntityAuditBundle\Tests\Fixtures\Relation\OneToOneAuditedEntity; use Sonata\EntityAuditBundle\Tests\Fixtures\Relation\OneToOneMasterEntity; use Sonata\EntityAuditBundle\Tests\Fixtures\Relation\OneToOneNotAuditedEntity; @@ -65,6 +67,8 @@ final class RelationTest extends BaseTest DataLegalEntity::class, DataPrivateEntity::class, DataContainerEntity::class, + ManyToManyMultipleRelationshipEntity::class, + ManyToManyMultipleTargetEntity::class, ]; protected $auditedEntities = [ @@ -87,6 +91,8 @@ final class RelationTest extends BaseTest DataLegalEntity::class, DataPrivateEntity::class, DataContainerEntity::class, + ManyToManyMultipleRelationshipEntity::class, + ManyToManyMultipleTargetEntity::class, ]; public function testUndefinedIndexesInUOWForRelations(): void @@ -358,6 +364,44 @@ public function testManyToMany(): void static::assertCount(1, $audited->getOwnedInverse()); } + + public function testManyToManyMultipleRelationshipSameTargetEntity(): void + { + $em = $this->getEntityManager(); + $auditReader = $this->getAuditManager()->createAuditReader($em); + + // create an entity that has multiple many-to-many relationships to the same target entity. + + $targetOne = new ManyToManyMultipleTargetEntity(); + $targetTwo = new ManyToManyMultipleTargetEntity(); + + $manyToMany = new ManyToManyMultipleRelationshipEntity(); + $manyToMany->setTitle('manyToMany#1'); + $manyToMany->addPrimaryTarget($targetOne); + $manyToMany->addSecondaryTarget($targetTwo); + + $em->persist($targetOne); + $em->persist($targetTwo); + $em->persist($manyToMany); + + $em->flush(); // #1 + + $manyToManyId = $manyToMany->getId(); + static::assertNotNull($manyToManyId); + + $audited = $auditReader->find(ManyToManyMultipleRelationshipEntity::class, $manyToManyId, 1); + + static::assertNotNull($audited); + + // ensure that there is an audited entry for the primaryTargets property + static::assertInstanceOf(Collection::class, $audited->getPrimaryTargets()); + static::assertCount(1, $audited->getPrimaryTargets()); + + // ensure that there is an audited entry for the secondaryTargets property + static::assertInstanceOf(Collection::class, $audited->getSecondaryTargets()); + static::assertCount(1, $audited->getSecondaryTargets()); + } + /** * @group mysql */ From f6f1f1178838f3ab3ef6c06220def18191290ea8 Mon Sep 17 00:00:00 2001 From: Mike Yudin Date: Sun, 14 Apr 2024 10:20:43 -0400 Subject: [PATCH 3/3] Run CS Fixer to lint. --- tests/RelationTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/RelationTest.php b/tests/RelationTest.php index 5a209d83..8ec3e291 100644 --- a/tests/RelationTest.php +++ b/tests/RelationTest.php @@ -364,7 +364,6 @@ public function testManyToMany(): void static::assertCount(1, $audited->getOwnedInverse()); } - public function testManyToManyMultipleRelationshipSameTargetEntity(): void { $em = $this->getEntityManager();