diff --git a/docs/en/reference/attributes-reference.rst b/docs/en/reference/attributes-reference.rst index d537a119ab0..64f15ddbba5 100644 --- a/docs/en/reference/attributes-reference.rst +++ b/docs/en/reference/attributes-reference.rst @@ -926,7 +926,7 @@ Example: #[OneToMany( targetEntity: "Phonenumber", mappedBy: "user", - cascade: ["persist", "remove", "merge"], + cascade: ["persist", "remove"], orphanRemoval: true) ] public $phonenumbers; diff --git a/docs/en/reference/best-practices.rst b/docs/en/reference/best-practices.rst index 002c130d5ce..b6f63a61b7b 100644 --- a/docs/en/reference/best-practices.rst +++ b/docs/en/reference/best-practices.rst @@ -43,7 +43,7 @@ should use events judiciously. Use cascades judiciously ------------------------ -Automatic cascades of the persist/remove/merge/etc. operations are +Automatic cascades of the persist/remove/etc. operations are very handy but should be used wisely. Do NOT simply add all cascades to all associations. Think about which cascades actually do make sense for you for a particular association, given the diff --git a/docs/en/reference/inheritance-mapping.rst b/docs/en/reference/inheritance-mapping.rst index 2bdfd708b8c..7852e6533eb 100644 --- a/docs/en/reference/inheritance-mapping.rst +++ b/docs/en/reference/inheritance-mapping.rst @@ -410,7 +410,6 @@ Example: - @@ -522,7 +521,6 @@ Could be used by an entity that extends a mapped superclass to override a field - diff --git a/docs/en/reference/limitations-and-known-issues.rst b/docs/en/reference/limitations-and-known-issues.rst index cf67c67e3a2..d8b7f19ada8 100644 --- a/docs/en/reference/limitations-and-known-issues.rst +++ b/docs/en/reference/limitations-and-known-issues.rst @@ -65,15 +65,6 @@ Where the ``attribute_name`` column contains the key and The feature request for persistence of primitive value arrays `is described in the DDC-298 ticket `_. -Cascade Merge with Bi-directional Associations -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -There are two bugs now that concern the use of cascade merge in combination with bi-directional associations. -Make sure to study the behavior of cascade merge if you are using it: - -- `DDC-875 `_ Merge can sometimes add the same entity twice into a collection -- `DDC-763 `_ Cascade merge on associated entities can insert too many rows through "Persistence by Reachability" - Custom Persisters ~~~~~~~~~~~~~~~~~ diff --git a/docs/en/reference/working-with-associations.rst b/docs/en/reference/working-with-associations.rst index 2c265679fa1..b5ca716ad07 100644 --- a/docs/en/reference/working-with-associations.rst +++ b/docs/en/reference/working-with-associations.rst @@ -415,7 +415,7 @@ Transitive persistence / Cascade Operations Doctrine ORM provides a mechanism for transitive persistence through cascading of certain operations. Each association to another entity or a collection of entities can be configured to automatically cascade the following operations to the associated entities: -``persist``, ``remove``, ``merge``, ``detach``, ``refresh`` or ``all``. +``persist``, ``remove``, ``detach``, ``refresh`` or ``all``. The main use case for ``cascade: persist`` is to avoid "exposing" associated entities to your PHP application. Continuing with the User-Comment example of this chapter, this is how the creation of a new user and a new diff --git a/docs/en/reference/working-with-objects.rst b/docs/en/reference/working-with-objects.rst index 3dc9378ee15..d7168609a1d 100644 --- a/docs/en/reference/working-with-objects.rst +++ b/docs/en/reference/working-with-objects.rst @@ -372,77 +372,6 @@ automatically without invoking the ``detach`` method: The ``detach`` operation is usually not as frequently needed and used as ``persist`` and ``remove``. -Merging entities ----------------- - -Merging entities refers to the merging of (usually detached) -entities into the context of an EntityManager so that they become -managed again. To merge the state of an entity into an -EntityManager use the ``EntityManager#merge($entity)`` method. The -state of the passed entity will be merged into a managed copy of -this entity and this copy will subsequently be returned. - -Example: - -.. code-block:: php - - merge($detachedEntity); - // $entity now refers to the fully managed copy returned by the merge operation. - // The EntityManager $em now manages the persistence of $entity as usual. - - -The semantics of the merge operation, applied to an entity X, are -as follows: - - -- If X is a detached entity, the state of X is copied onto a - pre-existing managed entity instance X' of the same identity. -- If X is a new entity instance, a new managed copy X' will be - created and the state of X is copied onto this managed instance. -- If X is a removed entity instance, an InvalidArgumentException - will be thrown. -- If X is a managed entity, it is ignored by the merge operation, - however, the merge operation is cascaded to entities referenced by - relationships from X if these relationships have been mapped with - the cascade element value MERGE or ALL (see ":ref:`transitive-persistence`"). -- For all entities Y referenced by relationships from X having the - cascade element value MERGE or ALL, Y is merged recursively as Y'. - For all such Y referenced by X, X' is set to reference Y'. (Note - that if X is managed then X is the same object as X'.) -- If X is an entity merged to X', with a reference to another - entity Y, where cascade=MERGE or cascade=ALL is not specified, then - navigation of the same association from X' yields a reference to a - managed object Y' with the same persistent identity as Y. - -The ``merge`` operation will throw an ``OptimisticLockException`` -if the entity being merged uses optimistic locking through a -version field and the versions of the entity being merged and the -managed copy don't match. This usually means that the entity has -been modified while being detached. - -The ``merge`` operation is usually not as frequently needed and -used as ``persist`` and ``remove``. The most common scenario for -the ``merge`` operation is to reattach entities to an EntityManager -that come from some cache (and are therefore detached) and you want -to modify and persist such an entity. - -.. warning:: - - If you need to perform multiple merges of entities that share certain subparts - of their object-graphs and cascade merge, then you have to call ``EntityManager#clear()`` between the - successive calls to ``EntityManager#merge()``. Otherwise you might end up with - multiple copies of the "same" object in the database, however with different ids. - -.. note:: - - If you load some detached entities from a cache and you do - not need to persist or delete them or otherwise make use of them - without the need for persistence services there is no need to use - ``merge``. I.e. you can simply pass detached objects from a cache - directly to the view. - Synchronization with the Database --------------------------------- @@ -553,7 +482,7 @@ during development. .. note:: Do not invoke ``flush`` after every change to an entity - or every single invocation of persist/remove/merge/... This is an + or every single invocation of persist/remove/... This is an anti-pattern and unnecessarily reduces the performance of your application. Instead, form units of work that operate on your objects and call ``flush`` when you are done. While serving a diff --git a/docs/en/reference/xml-mapping.rst b/docs/en/reference/xml-mapping.rst index 12930597b85..bb2eed19d1c 100644 --- a/docs/en/reference/xml-mapping.rst +++ b/docs/en/reference/xml-mapping.rst @@ -692,7 +692,6 @@ specified by their respective tags: - ```` -- ```` - ```` - ```` - ```` diff --git a/docs/en/tutorials/override-field-association-mappings-in-subclasses.rst b/docs/en/tutorials/override-field-association-mappings-in-subclasses.rst index 8d36b30ef66..cd5e19cbd80 100644 --- a/docs/en/tutorials/override-field-association-mappings-in-subclasses.rst +++ b/docs/en/tutorials/override-field-association-mappings-in-subclasses.rst @@ -66,7 +66,7 @@ which has mapping metadata that is overridden by the attribute above: #[Column(name: 'trait_foo', type: 'integer', length: 100, nullable: true, unique: true)] protected int $foo; - #[OneToOne(targetEntity: Bar::class, cascade: ['persist', 'merge'])] + #[OneToOne(targetEntity: Bar::class, cascade: ['persist'])] #[JoinColumn(name: 'example_trait_bar_id', referencedColumnName: 'id')] protected Bar|null $bar = null; } diff --git a/doctrine-mapping.xsd b/doctrine-mapping.xsd index 058825b11aa..5d6dfc812fa 100644 --- a/doctrine-mapping.xsd +++ b/doctrine-mapping.xsd @@ -35,7 +35,6 @@ - diff --git a/lib/Doctrine/ORM/Mapping/AssociationMapping.php b/lib/Doctrine/ORM/Mapping/AssociationMapping.php index 3fbeecbc23c..e3a899661dc 100644 --- a/lib/Doctrine/ORM/Mapping/AssociationMapping.php +++ b/lib/Doctrine/ORM/Mapping/AssociationMapping.php @@ -20,7 +20,7 @@ abstract class AssociationMapping implements ArrayAccess /** * The names of persistence operations to cascade on the association. * - * @var list<'persist'|'remove'|'detach'|'merge'|'refresh'|'all'> + * @var list<'persist'|'remove'|'detach'|'refresh'|'all'> */ public array $cascade = []; @@ -240,7 +240,6 @@ final public function offsetGet($offset): mixed 'isCascadePersist' => $this->isCascadePersist(), 'isCascadeRefresh' => $this->isCascadeRefresh(), 'isCascadeDetach' => $this->isCascadeDetach(), - 'isCascadeMerge' => $this->isCascadeMerge(), default => property_exists($this, $offset) ? $this->$offset : throw new OutOfRangeException(sprintf( 'Unknown property "%s" on class %s', $offset, @@ -296,11 +295,6 @@ final public function isCascadeRefresh(): bool return in_array('refresh', $this->cascade, true); } - final public function isCascadeMerge(): bool - { - return in_array('merge', $this->cascade, true); - } - final public function isCascadeDetach(): bool { return in_array('detach', $this->cascade, true); diff --git a/lib/Doctrine/ORM/Mapping/Builder/AssociationBuilder.php b/lib/Doctrine/ORM/Mapping/Builder/AssociationBuilder.php index 50817b4c39b..ea9e13c53b1 100644 --- a/lib/Doctrine/ORM/Mapping/Builder/AssociationBuilder.php +++ b/lib/Doctrine/ORM/Mapping/Builder/AssociationBuilder.php @@ -60,14 +60,6 @@ public function cascadeRemove(): static return $this; } - /** @return $this */ - public function cascadeMerge(): static - { - $this->mapping['cascade'][] = 'merge'; - - return $this; - } - /** @return $this */ public function cascadeDetach(): static { diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadata.php b/lib/Doctrine/ORM/Mapping/ClassMetadata.php index 9fb4b187809..7306266ce27 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadata.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadata.php @@ -1349,7 +1349,7 @@ protected function _validateAndCompleteAssociationMapping(array $mapping): Assoc // Cascades $cascades = isset($mapping['cascade']) ? array_map('strtolower', $mapping['cascade']) : []; - $allCascades = ['remove', 'persist', 'refresh', 'merge', 'detach']; + $allCascades = ['remove', 'persist', 'refresh', 'detach']; if (in_array('all', $cascades, true)) { $cascades = $allCascades; } elseif (count($cascades) !== count(array_intersect($cascades, $allCascades))) { diff --git a/lib/Doctrine/ORM/Mapping/MappingException.php b/lib/Doctrine/ORM/Mapping/MappingException.php index 1b45aab32dc..48fc9a6654e 100644 --- a/lib/Doctrine/ORM/Mapping/MappingException.php +++ b/lib/Doctrine/ORM/Mapping/MappingException.php @@ -553,7 +553,7 @@ public static function invalidCascadeOption(array $cascades, string $className, $cascades = implode(', ', array_map(static fn (string $e): string => "'" . $e . "'", $cascades)); return new self(sprintf( - "You have specified invalid cascade options for %s::$%s: %s; available options: 'remove', 'persist', 'refresh', 'merge', and 'detach'", + "You have specified invalid cascade options for %s::$%s: %s; available options: 'remove', 'persist', 'refresh', and 'detach'", $className, $propertyName, $cascades, diff --git a/tests/Doctrine/Tests/Models/CMS/CmsPhonenumber.php b/tests/Doctrine/Tests/Models/CMS/CmsPhonenumber.php index 7bfe373cb3d..1f23e4e0b60 100644 --- a/tests/Doctrine/Tests/Models/CMS/CmsPhonenumber.php +++ b/tests/Doctrine/Tests/Models/CMS/CmsPhonenumber.php @@ -21,7 +21,7 @@ class CmsPhonenumber public $phonenumber; /** @var CmsUser */ - #[ManyToOne(targetEntity: 'CmsUser', inversedBy: 'phonenumbers', cascade: ['merge'])] + #[ManyToOne(targetEntity: 'CmsUser', inversedBy: 'phonenumbers', cascade: [])] #[JoinColumn(name: 'user_id', referencedColumnName: 'id')] public $user; diff --git a/tests/Doctrine/Tests/Models/CMS/CmsUser.php b/tests/Doctrine/Tests/Models/CMS/CmsUser.php index 335525fb366..ea36ea7e3f6 100644 --- a/tests/Doctrine/Tests/Models/CMS/CmsUser.php +++ b/tests/Doctrine/Tests/Models/CMS/CmsUser.php @@ -42,7 +42,7 @@ class CmsUser public $name; /** @psalm-var Collection */ - #[OneToMany(targetEntity: 'CmsPhonenumber', mappedBy: 'user', cascade: ['persist', 'merge'], orphanRemoval: true)] + #[OneToMany(targetEntity: 'CmsPhonenumber', mappedBy: 'user', cascade: ['persist',], orphanRemoval: true)] public $phonenumbers; /** @psalm-var Collection */ @@ -62,7 +62,7 @@ class CmsUser #[JoinTable(name: 'cms_users_groups')] #[JoinColumn(name: 'user_id', referencedColumnName: 'id')] #[InverseJoinColumn(name: 'group_id', referencedColumnName: 'id')] - #[ManyToMany(targetEntity: 'CmsGroup', inversedBy: 'users', cascade: ['persist', 'merge', 'detach'])] + #[ManyToMany(targetEntity: 'CmsGroup', inversedBy: 'users', cascade: ['persist', 'detach'])] public $groups; /** @var Collection */ diff --git a/tests/Doctrine/Tests/Models/DDC1872/DDC1872ExampleTrait.php b/tests/Doctrine/Tests/Models/DDC1872/DDC1872ExampleTrait.php index 735d014eb69..fdad6f4182b 100644 --- a/tests/Doctrine/Tests/Models/DDC1872/DDC1872ExampleTrait.php +++ b/tests/Doctrine/Tests/Models/DDC1872/DDC1872ExampleTrait.php @@ -21,7 +21,7 @@ trait DDC1872ExampleTrait protected $foo; /** @var DDC1872Bar */ - #[OneToOne(targetEntity: 'DDC1872Bar', cascade: ['persist', 'merge'])] + #[OneToOne(targetEntity: 'DDC1872Bar', cascade: ['persist'])] #[JoinColumn(name: 'example_trait_bar_id', referencedColumnName: 'id')] protected $bar; } diff --git a/tests/Doctrine/Tests/Models/DDC964/DDC964User.php b/tests/Doctrine/Tests/Models/DDC964/DDC964User.php index f2f17c14b97..9adcca23dd6 100644 --- a/tests/Doctrine/Tests/Models/DDC964/DDC964User.php +++ b/tests/Doctrine/Tests/Models/DDC964/DDC964User.php @@ -27,14 +27,14 @@ class DDC964User protected $id; /** @psalm-var Collection */ - #[ManyToMany(targetEntity: DDC964Group::class, inversedBy: 'users', cascade: ['persist', 'merge', 'detach'])] + #[ManyToMany(targetEntity: DDC964Group::class, inversedBy: 'users', cascade: ['persist', 'detach'])] #[JoinTable(name: 'ddc964_users_groups')] #[JoinColumn(name: 'user_id', referencedColumnName: 'id')] #[InverseJoinColumn(name: 'group_id', referencedColumnName: 'id')] protected $groups; /** @var DDC964Address */ - #[ManyToOne(targetEntity: DDC964Address::class, cascade: ['persist', 'merge'])] + #[ManyToOne(targetEntity: DDC964Address::class, cascade: ['persist'])] #[JoinColumn(name: 'address_id', referencedColumnName: 'id')] protected $address; @@ -110,7 +110,7 @@ public static function loadMetadata(ClassMetadata $metadata): void [ 'fieldName' => 'address', 'targetEntity' => 'DDC964Address', - 'cascade' => ['persist','merge'], + 'cascade' => ['persist'], 'joinColumns' => [['name' => 'address_id', 'referencedColumnName' => 'id']], ], ); @@ -120,7 +120,7 @@ public static function loadMetadata(ClassMetadata $metadata): void 'fieldName' => 'groups', 'targetEntity' => 'DDC964Group', 'inversedBy' => 'users', - 'cascade' => ['persist','merge','detach'], + 'cascade' => ['persist','detach'], 'joinTable' => [ 'name' => 'ddc964_users_groups', 'joinColumns' => [ diff --git a/tests/Doctrine/Tests/Models/Legacy/LegacyUser.php b/tests/Doctrine/Tests/Models/Legacy/LegacyUser.php index 50e1231a596..e43bc6828bc 100644 --- a/tests/Doctrine/Tests/Models/Legacy/LegacyUser.php +++ b/tests/Doctrine/Tests/Models/Legacy/LegacyUser.php @@ -47,7 +47,7 @@ class LegacyUser #[JoinTable(name: 'legacy_users_cars')] #[JoinColumn(name: 'iUserId', referencedColumnName: 'iUserId')] #[InverseJoinColumn(name: 'iCarId', referencedColumnName: 'iCarId')] - #[ManyToMany(targetEntity: 'LegacyCar', inversedBy: 'users', cascade: ['persist', 'merge'])] + #[ManyToMany(targetEntity: 'LegacyCar', inversedBy: 'users', cascade: ['persist'])] public $cars; public function __construct() diff --git a/tests/Doctrine/Tests/Models/MixedToOneIdentity/CompositeToOneKeyState.php b/tests/Doctrine/Tests/Models/MixedToOneIdentity/CompositeToOneKeyState.php index f3372e96763..f3f0d9a1289 100644 --- a/tests/Doctrine/Tests/Models/MixedToOneIdentity/CompositeToOneKeyState.php +++ b/tests/Doctrine/Tests/Models/MixedToOneIdentity/CompositeToOneKeyState.php @@ -22,7 +22,7 @@ class CompositeToOneKeyState /** @var Country */ #[Id] - #[ManyToOne(targetEntity: 'Country', cascade: ['MERGE'])] + #[ManyToOne(targetEntity: 'Country', cascade: [])] #[JoinColumn(referencedColumnName: 'country')] public $country; } diff --git a/tests/Doctrine/Tests/Models/VersionedManyToOne/Article.php b/tests/Doctrine/Tests/Models/VersionedManyToOne/Article.php index 41468abc189..8c57945ca7c 100644 --- a/tests/Doctrine/Tests/Models/VersionedManyToOne/Article.php +++ b/tests/Doctrine/Tests/Models/VersionedManyToOne/Article.php @@ -27,7 +27,7 @@ class Article public $name; /** @var Category */ - #[ManyToOne(targetEntity: 'Category', cascade: ['merge', 'persist'])] + #[ManyToOne(targetEntity: 'Category', cascade: ['persist'])] public $category; /** diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2602Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2602Test.php index 37a0bd1e9fc..fc1d74c5a57 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2602Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2602Test.php @@ -173,7 +173,7 @@ class DDC2602User public $name; /** @var DDC2602Biography */ - #[OneToOne(targetEntity: 'DDC2602Biography', inversedBy: 'user', cascade: ['persist', 'merge', 'refresh', 'remove'])] + #[OneToOne(targetEntity: 'DDC2602Biography', inversedBy: 'user', cascade: ['persist', 'refresh', 'remove'])] #[JoinColumn(nullable: false)] public $biography; } @@ -188,7 +188,7 @@ class DDC2602Biography public $id; /** @var DDC2602User */ - #[OneToOne(targetEntity: 'DDC2602User', mappedBy: 'biography', cascade: ['persist', 'merge', 'refresh'])] + #[OneToOne(targetEntity: 'DDC2602User', mappedBy: 'biography', cascade: ['persist', 'refresh'])] public $user; /** @var string */ @@ -217,7 +217,7 @@ class DDC2602BiographyField public $label; /** @var ArrayCollection */ - #[OneToMany(targetEntity: 'DDC2602BiographyFieldChoice', mappedBy: 'field', cascade: ['persist', 'merge', 'refresh'])] + #[OneToMany(targetEntity: 'DDC2602BiographyFieldChoice', mappedBy: 'field', cascade: ['persist', 'refresh'])] public $choiceList; public function __construct() diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC758Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC758Test.php deleted file mode 100644 index 461cf116d90..00000000000 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC758Test.php +++ /dev/null @@ -1,186 +0,0 @@ -useModelSet('cms'); - - parent::setUp(); - } - - /** - * Helper method to set cascade to merge only - */ - private function setCascadeMergeFor($class): void - { - $metadata = $this->_em->getMetadataFactory()->getMetadataFor($class); - foreach ($metadata->associationMappings as $key => $associationMapping) { - $metadata->associationMappings[$key]['isCascadePersist'] = false; - $metadata->associationMappings[$key]['isCascadeMerge'] = true; - $metadata->associationMappings[$key]['isCascadeRemove'] = false; - $metadata->associationMappings[$key]['isCascadeDetach'] = false; - } - } - - /** - * Test that changing associations on detached entities and then cascade merging them - * causes the database to be updated with the new associations. - * This specifically tests adding new associations. - */ - public function testManyToManyMergeAssociationAdds(): void - { - $this->setCascadeMergeFor(CmsUser::class); - $this->setCascadeMergeFor(CmsGroup::class); - - // Put entities in the database - $cmsUser = new CmsUser(); - $cmsUser->username = 'dave'; - $cmsUser->name = 'Dave Keen'; - $cmsUser->status = 'testing'; - - $group1 = new CmsGroup(); - $group1->name = 'Group 1'; - - $group2 = new CmsGroup(); - $group2->name = 'Group 2'; - - $this->_em->persist($cmsUser); - $this->_em->persist($group1); - $this->_em->persist($group2); - $this->_em->flush(); - - $cmsUserId = $cmsUser->id; - $group1Id = $group1->id; - $group2Id = $group2->id; - - $this->_em->clear(); - - // Now create detached versions of the entities with some new associations. - $cmsUser = new CmsUser(); - $cmsUser->id = $cmsUserId; - $cmsUser->username = 'dave'; - $cmsUser->name = 'Dave Keen'; - $cmsUser->status = 'testing'; - $cmsUser->groups = new ArrayCollection(); - - $group1 = new CmsGroup(); - $group1->id = $group1Id; - $group1->name = 'Group 1'; - $group1->users = new ArrayCollection(); - - $group2 = new CmsGroup(); - $group2->id = $group2Id; - $group2->name = 'Group 2'; - $group2->users = new ArrayCollection(); - - $cmsUser->addGroup($group1); - $cmsUser->addGroup($group2); - - // Cascade merge of cmsUser followed by a flush should add in the bidirectional new many-to-many associations between the user and the groups - $this->_em->merge($cmsUser); - $this->_em->flush(); - - $this->_em->clear(); - - $cmsUsers = $this->_em->getRepository(CmsUser::class)->findAll(); - $cmsGroups = $this->_em->getRepository(CmsGroup::class)->findAll(); - - // Check the entities are in the database - self::assertEquals(1, count($cmsUsers)); - self::assertEquals(2, count($cmsGroups)); - - // Check the associations between the entities are now in the database - self::assertEquals(2, count($cmsUsers[0]->groups)); - self::assertEquals(1, count($cmsGroups[0]->users)); - self::assertEquals(1, count($cmsGroups[1]->users)); - - self::assertSame($cmsUsers[0]->groups[0], $cmsGroups[0]); - self::assertSame($cmsUsers[0]->groups[1], $cmsGroups[1]); - self::assertSame($cmsGroups[0]->users[0], $cmsUsers[0]); - self::assertSame($cmsGroups[1]->users[0], $cmsUsers[0]); - } - - /** - * Test that changing associations on detached entities and then cascade merging them causes the - * database to be updated with the new associations. - */ - public function testManyToManyMergeAssociationRemoves(): void - { - $this->setCascadeMergeFor(CmsUser::class); - $this->setCascadeMergeFor(CmsGroup::class); - - $cmsUser = new CmsUser(); - $cmsUser->username = 'dave'; - $cmsUser->name = 'Dave Keen'; - $cmsUser->status = 'testing'; - - $group1 = new CmsGroup(); - $group1->name = 'Group 1'; - - $group2 = new CmsGroup(); - $group2->name = 'Group 2'; - - $cmsUser->addGroup($group1); - $cmsUser->addGroup($group2); - - $this->_em->persist($cmsUser); - $this->_em->persist($group1); - $this->_em->persist($group2); - $this->_em->flush(); - - $cmsUserId = $cmsUser->id; - $group1Id = $group1->id; - $group2Id = $group2->id; - - $this->_em->clear(); - - // Now create detached versions of the entities with NO associations. - $cmsUser = new CmsUser(); - $cmsUser->id = $cmsUserId; - $cmsUser->username = 'dave'; - $cmsUser->name = 'Dave Keen'; - $cmsUser->status = 'testing'; - $cmsUser->groups = new ArrayCollection(); - - $group1 = new CmsGroup(); - $group1->id = $group1Id; - $group1->name = 'Group 1'; - $group1->users = new ArrayCollection(); - - $group2 = new CmsGroup(); - $group2->id = $group2Id; - $group2->name = 'Group 2'; - $group2->users = new ArrayCollection(); - - // Cascade merge of cmsUser followed by a flush should result in the association array collection being empty - $this->_em->merge($cmsUser); - $this->_em->flush(); - - $this->_em->clear(); - - $cmsUsers = $this->_em->getRepository(CmsUser::class)->findAll(); - $cmsGroups = $this->_em->getRepository(CmsGroup::class)->findAll(); - - // Check the entities are in the database - self::assertEquals(1, count($cmsUsers)); - self::assertEquals(2, count($cmsGroups)); - - // Check the associations between the entities are now in the database - self::assertEquals(0, count($cmsUsers[0]->groups)); - self::assertEquals(0, count($cmsGroups[0]->users)); - self::assertEquals(0, count($cmsGroups[1]->users)); - } -} diff --git a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataBuilderTest.php b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataBuilderTest.php index 4dd6b62e0e3..3c9249a9962 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataBuilderTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataBuilderTest.php @@ -303,7 +303,6 @@ public function testCreateManyToOne(): void 0 => 'remove', 1 => 'persist', 2 => 'refresh', - 3 => 'merge', 4 => 'detach', ], 'fetch' => 4, @@ -357,7 +356,6 @@ public function testCreateManyToOneWithIdentity(): void 0 => 'remove', 1 => 'persist', 2 => 'refresh', - 3 => 'merge', 4 => 'detach', ], 'fetch' => 4, @@ -409,7 +407,6 @@ public function testCreateOneToOne(): void 0 => 'remove', 1 => 'persist', 2 => 'refresh', - 3 => 'merge', 4 => 'detach', ], 'fetch' => 4, @@ -463,7 +460,6 @@ public function testCreateOneToOneWithIdentity(): void 0 => 'remove', 1 => 'persist', 2 => 'refresh', - 3 => 'merge', 4 => 'detach', ], 'fetch' => 4, @@ -532,7 +528,6 @@ public function testCreateManyToMany(): void 0 => 'remove', 1 => 'persist', 2 => 'refresh', - 3 => 'merge', 4 => 'detach', ], 'fetch' => 4, diff --git a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php index 170f95bee6c..28b69ff08a5 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php @@ -808,7 +808,7 @@ public function testInvalidCascade(): void $cm->initializeReflection(new RuntimeReflectionService()); $this->expectException(MappingException::class); - $this->expectExceptionMessage('You have specified invalid cascade options for ' . CmsUser::class . "::\$address: 'invalid'; available options: 'remove', 'persist', 'refresh', 'merge', and 'detach'"); + $this->expectExceptionMessage('You have specified invalid cascade options for ' . CmsUser::class . "::\$address: 'invalid'; available options: 'remove', 'persist', 'refresh', and 'detach'"); $cm->mapManyToOne(['fieldName' => 'address', 'targetEntity' => 'UnknownClass', 'cascade' => ['invalid']]); } diff --git a/tests/Doctrine/Tests/ORM/Mapping/MappingDriverTestCase.php b/tests/Doctrine/Tests/ORM/Mapping/MappingDriverTestCase.php index 40c39827ee9..c56e231a677 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/MappingDriverTestCase.php +++ b/tests/Doctrine/Tests/ORM/Mapping/MappingDriverTestCase.php @@ -361,7 +361,6 @@ public function testOwningOneToOneAssociation(ClassMetadata $class): ClassMetada self::assertFalse($class->associationMappings['address']->isCascadePersist()); self::assertFalse($class->associationMappings['address']->isCascadeRefresh()); self::assertFalse($class->associationMappings['address']->isCascadeDetach()); - self::assertFalse($class->associationMappings['address']->isCascadeMerge()); return $class; } @@ -375,7 +374,6 @@ public function testInverseOneToManyAssociation(ClassMetadata $class): ClassMeta self::assertTrue($class->associationMappings['phonenumbers']->isCascadeRemove()); self::assertFalse($class->associationMappings['phonenumbers']->isCascadeRefresh()); self::assertFalse($class->associationMappings['phonenumbers']->isCascadeDetach()); - self::assertFalse($class->associationMappings['phonenumbers']->isCascadeMerge()); self::assertTrue($class->associationMappings['phonenumbers']->orphanRemoval); // Test Order By @@ -394,7 +392,6 @@ public function testManyToManyAssociationWithCascadeAll(ClassMetadata $class): C self::assertTrue($class->associationMappings['groups']->isCascadePersist()); self::assertTrue($class->associationMappings['groups']->isCascadeRefresh()); self::assertTrue($class->associationMappings['groups']->isCascadeDetach()); - self::assertTrue($class->associationMappings['groups']->isCascadeMerge()); self::assertFalse($class->associationMappings['groups']->isOrdered()); @@ -630,7 +627,6 @@ public function testAssociationOverridesMapping(): void self::assertEquals($guestGroups->isCascadeRemove(), $adminGroups->isCascadeRemove()); self::assertEquals($guestGroups->isCascadePersist(), $adminGroups->isCascadePersist()); self::assertEquals($guestGroups->isCascadeRefresh(), $adminGroups->isCascadeRefresh()); - self::assertEquals($guestGroups->isCascadeMerge(), $adminGroups->isCascadeMerge()); self::assertEquals($guestGroups->isCascadeDetach(), $adminGroups->isCascadeDetach()); // assert not override attributes @@ -666,7 +662,6 @@ public function testAssociationOverridesMapping(): void self::assertEquals($guestAddress->isCascadeRemove(), $adminAddress->isCascadeRemove()); self::assertEquals($guestAddress->isCascadePersist(), $adminAddress->isCascadePersist()); self::assertEquals($guestAddress->isCascadeRefresh(), $adminAddress->isCascadeRefresh()); - self::assertEquals($guestAddress->isCascadeMerge(), $adminAddress->isCascadeMerge()); self::assertEquals($guestAddress->isCascadeDetach(), $adminAddress->isCascadeDetach()); // assert override @@ -1101,7 +1096,6 @@ public static function loadMetadata(ClassMetadata $metadata): void 0 => 'remove', 1 => 'persist', 2 => 'refresh', - 3 => 'merge', 4 => 'detach', ], 'mappedBy' => null, diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsUser.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsUser.dcm.xml index 5e9bb53580b..104ef15a567 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsUser.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsUser.dcm.xml @@ -31,7 +31,6 @@ - @@ -44,7 +43,6 @@ - diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964User.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964User.dcm.xml index 3e6a91f39e1..cc4764b1b57 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964User.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964User.dcm.xml @@ -14,7 +14,6 @@ - @@ -22,7 +21,6 @@ -