From 874d60d8c7bd236b736ce5a15999ce2b81833a35 Mon Sep 17 00:00:00 2001 From: Uladzimir Struts Date: Fri, 11 Aug 2017 13:46:21 +0300 Subject: [PATCH 01/23] It added the unit test #6613 --- tests/Doctrine/Tests/Models/DDC6613/Phone.php | 27 ++++++++ tests/Doctrine/Tests/Models/DDC6613/User.php | 43 ++++++++++++ .../ORM/Functional/Ticket/DDC6613Test.php | 67 +++++++++++++++++++ 3 files changed, 137 insertions(+) create mode 100644 tests/Doctrine/Tests/Models/DDC6613/Phone.php create mode 100644 tests/Doctrine/Tests/Models/DDC6613/User.php create mode 100644 tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php diff --git a/tests/Doctrine/Tests/Models/DDC6613/Phone.php b/tests/Doctrine/Tests/Models/DDC6613/Phone.php new file mode 100644 index 00000000000..32f878eeecb --- /dev/null +++ b/tests/Doctrine/Tests/Models/DDC6613/Phone.php @@ -0,0 +1,27 @@ + + * Date: 11.08.2017 + * Time: 13:12 + */ + +namespace Doctrine\Tests\Models\DDC6613; + + +/** + * @Entity(readOnly=true) + * @Table(name="ddc6613_phone") + */ + +class Phone +{ + + /** + * @Id + * @GeneratedValue + * @Column(type="integer") + */ + public $id; + +} \ No newline at end of file diff --git a/tests/Doctrine/Tests/Models/DDC6613/User.php b/tests/Doctrine/Tests/Models/DDC6613/User.php new file mode 100644 index 00000000000..ee4e7260b0b --- /dev/null +++ b/tests/Doctrine/Tests/Models/DDC6613/User.php @@ -0,0 +1,43 @@ + + * Date: 11.08.2017 + * Time: 13:12 + */ + +namespace Doctrine\Tests\Models\DDC6613; + + +use Doctrine\Common\Collections\ArrayCollection; + +/** + * @Entity() + * @Table(name="ddc6613_user") + */ +class User +{ + + /** + * @Id + * @GeneratedValue + * @Column(type="integer") + */ + public $id; + + + /** + * @ManyToMany(targetEntity="Phone", fetch="LAZY", cascade={"remove", "detach"}) + */ + public $phones; + + /** + * User constructor. + */ + public function __construct() + { + $this->phones = new ArrayCollection(); + } + + +} \ No newline at end of file diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php new file mode 100644 index 00000000000..11b8f511102 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php @@ -0,0 +1,67 @@ + + * Date: 11.08.2017 + * Time: 12:28 + */ + +namespace Doctrine\Tests\ORM\Functional\Ticket; + + +use Doctrine\DBAL\Schema\SchemaException; +use Doctrine\ORM\Mapping\Column; +use Doctrine\ORM\Mapping\Embeddable; +use Doctrine\ORM\Mapping\Entity; +use Doctrine\ORM\Mapping\Id; +use Doctrine\ORM\Mapping\GeneratedValue; +use Doctrine\ORM\Mapping\ManyToOne; +use Doctrine\ORM\Proxy\Proxy; +use Doctrine\Tests\Models\DDC6613\Phone; +use Doctrine\Tests\Models\DDC6613\User; + + +class DDC6613Test extends \Doctrine\Tests\OrmFunctionalTestCase +{ + + public function setUp() + { + parent::setUp(); + + try { + $this->setUpEntitySchema( + [ + Phone::class, + User::class + ] + ); + } catch (SchemaException $e) { + } + } + + public function testFail() + { + $user = new User(); + $user->id = 1; + $this->_em->persist($user); + $this->_em->flush(); + + $this->_em->clear(); + + /** @var User $user */ + $user = $this->_em->find(User::class, 1); + $phone1 = new Phone(); + $phone1->id = 1; + $user->phones->add($phone1); + $this->_em->persist($phone1); + $this->_em->flush(); + + $phone2 = new Phone(); + $phone2->id = 2; + $user->phones->add($phone2); + $this->_em->persist($phone2); + $user->phones->toArray(); + $this->_em->flush(); + } + +} \ No newline at end of file From 594e60d3f7610016d3fa0b9de5d71de3308293f2 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 11 Aug 2017 14:19:01 +0200 Subject: [PATCH 02/23] #6613 #6614 simplifying entity definition - using auto-assigned string identifiers to reduce moving parts --- tests/Doctrine/Tests/Models/DDC6613/Phone.php | 7 +++++-- tests/Doctrine/Tests/Models/DDC6613/User.php | 7 ++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/Doctrine/Tests/Models/DDC6613/Phone.php b/tests/Doctrine/Tests/Models/DDC6613/Phone.php index 32f878eeecb..9ce0909608f 100644 --- a/tests/Doctrine/Tests/Models/DDC6613/Phone.php +++ b/tests/Doctrine/Tests/Models/DDC6613/Phone.php @@ -10,7 +10,6 @@ /** - * @Entity(readOnly=true) * @Table(name="ddc6613_phone") */ @@ -19,9 +18,13 @@ class Phone /** * @Id - * @GeneratedValue + * @GeneratedValue(strategy="NONE") * @Column(type="integer") */ public $id; + public function __construct() + { + $this->id = uniqid('phone', true); + } } \ No newline at end of file diff --git a/tests/Doctrine/Tests/Models/DDC6613/User.php b/tests/Doctrine/Tests/Models/DDC6613/User.php index ee4e7260b0b..6b233c0a233 100644 --- a/tests/Doctrine/Tests/Models/DDC6613/User.php +++ b/tests/Doctrine/Tests/Models/DDC6613/User.php @@ -20,10 +20,10 @@ class User /** * @Id - * @GeneratedValue - * @Column(type="integer") + * @GeneratedValue(strategy="NONE") + * @Column(type="string") */ - public $id; + private $id; /** @@ -36,6 +36,7 @@ class User */ public function __construct() { + $this->id = uniqid('user', true); $this->phones = new ArrayCollection(); } From 0a1a84163e91836afa51d8e9068bbf0fa2e29f6c Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 11 Aug 2017 14:20:07 +0200 Subject: [PATCH 03/23] #6613 #6614 better test specification - removing useless assertions --- tests/Doctrine/Tests/Models/DDC6613/User.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/Doctrine/Tests/Models/DDC6613/User.php b/tests/Doctrine/Tests/Models/DDC6613/User.php index 6b233c0a233..9475bef4b2c 100644 --- a/tests/Doctrine/Tests/Models/DDC6613/User.php +++ b/tests/Doctrine/Tests/Models/DDC6613/User.php @@ -31,9 +31,6 @@ class User */ public $phones; - /** - * User constructor. - */ public function __construct() { $this->id = uniqid('user', true); From 112a402016c0e056aeb99e217a52d63813e2b9c8 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 11 Aug 2017 14:21:56 +0200 Subject: [PATCH 04/23] #6613 #6614 smashing entity definitions into the test --- .../ORM/Functional/Ticket/DDC6613Test.php | 78 ++++++++++++++++--- 1 file changed, 69 insertions(+), 9 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php index 11b8f511102..30e4f5276da 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php @@ -16,6 +16,7 @@ use Doctrine\ORM\Mapping\Id; use Doctrine\ORM\Mapping\GeneratedValue; use Doctrine\ORM\Mapping\ManyToOne; +use Doctrine\ORM\PersistentCollection; use Doctrine\ORM\Proxy\Proxy; use Doctrine\Tests\Models\DDC6613\Phone; use Doctrine\Tests\Models\DDC6613\User; @@ -31,8 +32,8 @@ public function setUp() try { $this->setUpEntitySchema( [ - Phone::class, - User::class + DDC6613Phone::class, + DDC6613User::class ] ); } catch (SchemaException $e) { @@ -41,8 +42,7 @@ public function setUp() public function testFail() { - $user = new User(); - $user->id = 1; + $user = new DDC6613User(); $this->_em->persist($user); $this->_em->flush(); @@ -50,18 +50,78 @@ public function testFail() /** @var User $user */ $user = $this->_em->find(User::class, 1); - $phone1 = new Phone(); - $phone1->id = 1; + $phone1 = new DDC6613Phone(); + $phones = $user->phones; $user->phones->add($phone1); $this->_em->persist($phone1); $this->_em->flush(); - $phone2 = new Phone(); - $phone2->id = 2; + $phone2 = new DDC6613Phone(); $user->phones->add($phone2); $this->_em->persist($phone2); - $user->phones->toArray(); + + /* @var $phones PersistentCollection */ +// $phones = $user->phones; + + self::assertInstanceOf(PersistentCollection::class, $phones); + self::assertFalse($phones->isInitialized()); + + $phones->initialize(); + + self::assertTrue($phones->isInitialized()); + self::assertCount(2, $phones); + $this->_em->flush(); + + self::assertFalse($phones->isDirty()); + self::assertTrue($phones->isInitialized()); + self::assertCount(2, $user->phones); + } + +} + +/** + * @Entity + * @Table(name="ddc6613_user") + */ +class DDC6613User +{ + /** + * @Id + * @GeneratedValue(strategy="NONE") + * @Column(type="string") + */ + private $id; + + /** + * @ManyToMany(targetEntity="Phone", fetch="LAZY", cascade={"remove", "detach"}) + */ + public $phones; + + public function __construct() + { + $this->id = uniqid('user', true); + $this->phones = new ArrayCollection(); } + +} + +/** + * @Table(name="ddc6613_phone") + */ +class DDC6613Phone +{ + + /** + * @Id + * @GeneratedValue(strategy="NONE") + * @Column(type="integer") + */ + public $id; + + public function __construct() + { + $this->id = uniqid('phone', true); + } } \ No newline at end of file From 625f79229031e02c787d2d2e88cae58f53e7e5f7 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 11 Aug 2017 14:22:31 +0200 Subject: [PATCH 05/23] #6613 #6614 removing dedicated DDC6613 model directory --- tests/Doctrine/Tests/Models/DDC6613/Phone.php | 30 -------------- tests/Doctrine/Tests/Models/DDC6613/User.php | 41 ------------------- 2 files changed, 71 deletions(-) delete mode 100644 tests/Doctrine/Tests/Models/DDC6613/Phone.php delete mode 100644 tests/Doctrine/Tests/Models/DDC6613/User.php diff --git a/tests/Doctrine/Tests/Models/DDC6613/Phone.php b/tests/Doctrine/Tests/Models/DDC6613/Phone.php deleted file mode 100644 index 9ce0909608f..00000000000 --- a/tests/Doctrine/Tests/Models/DDC6613/Phone.php +++ /dev/null @@ -1,30 +0,0 @@ - - * Date: 11.08.2017 - * Time: 13:12 - */ - -namespace Doctrine\Tests\Models\DDC6613; - - -/** - * @Table(name="ddc6613_phone") - */ - -class Phone -{ - - /** - * @Id - * @GeneratedValue(strategy="NONE") - * @Column(type="integer") - */ - public $id; - - public function __construct() - { - $this->id = uniqid('phone', true); - } -} \ No newline at end of file diff --git a/tests/Doctrine/Tests/Models/DDC6613/User.php b/tests/Doctrine/Tests/Models/DDC6613/User.php deleted file mode 100644 index 9475bef4b2c..00000000000 --- a/tests/Doctrine/Tests/Models/DDC6613/User.php +++ /dev/null @@ -1,41 +0,0 @@ - - * Date: 11.08.2017 - * Time: 13:12 - */ - -namespace Doctrine\Tests\Models\DDC6613; - - -use Doctrine\Common\Collections\ArrayCollection; - -/** - * @Entity() - * @Table(name="ddc6613_user") - */ -class User -{ - - /** - * @Id - * @GeneratedValue(strategy="NONE") - * @Column(type="string") - */ - private $id; - - - /** - * @ManyToMany(targetEntity="Phone", fetch="LAZY", cascade={"remove", "detach"}) - */ - public $phones; - - public function __construct() - { - $this->id = uniqid('user', true); - $this->phones = new ArrayCollection(); - } - - -} \ No newline at end of file From c195064ba49d58cb46ecd5387875350a59e9ca7e Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 11 Aug 2017 14:23:21 +0200 Subject: [PATCH 06/23] #6613 #6614 CS - applying `@group` annotation to the test --- .../ORM/Functional/Ticket/DDC6613Test.php | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php index 30e4f5276da..16d21bbd1c3 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php @@ -8,23 +8,21 @@ namespace Doctrine\Tests\ORM\Functional\Ticket; - +use Doctrine\Common\Collections\ArrayCollection; use Doctrine\DBAL\Schema\SchemaException; use Doctrine\ORM\Mapping\Column; -use Doctrine\ORM\Mapping\Embeddable; use Doctrine\ORM\Mapping\Entity; -use Doctrine\ORM\Mapping\Id; use Doctrine\ORM\Mapping\GeneratedValue; -use Doctrine\ORM\Mapping\ManyToOne; +use Doctrine\ORM\Mapping\Id; use Doctrine\ORM\PersistentCollection; -use Doctrine\ORM\Proxy\Proxy; -use Doctrine\Tests\Models\DDC6613\Phone; -use Doctrine\Tests\Models\DDC6613\User; +use Doctrine\Tests\OrmFunctionalTestCase; - -class DDC6613Test extends \Doctrine\Tests\OrmFunctionalTestCase +/** + * @group #6613 + * @group #6614 + */ +class DDC6613Test extends OrmFunctionalTestCase { - public function setUp() { parent::setUp(); @@ -33,7 +31,7 @@ public function setUp() $this->setUpEntitySchema( [ DDC6613Phone::class, - DDC6613User::class + DDC6613User::class, ] ); } catch (SchemaException $e) { @@ -49,7 +47,7 @@ public function testFail() $this->_em->clear(); /** @var User $user */ - $user = $this->_em->find(User::class, 1); + $user = $this->_em->find(User::class, 1); $phone1 = new DDC6613Phone(); $phones = $user->phones; $user->phones->add($phone1); @@ -77,7 +75,6 @@ public function testFail() self::assertTrue($phones->isInitialized()); self::assertCount(2, $user->phones); } - } /** @@ -103,8 +100,6 @@ public function __construct() $this->id = uniqid('user', true); $this->phones = new ArrayCollection(); } - - } /** @@ -112,7 +107,6 @@ public function __construct() */ class DDC6613Phone { - /** * @Id * @GeneratedValue(strategy="NONE") From eca1d6b3ead294a40727f8b26ea9572c02214d7c Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 11 Aug 2017 14:27:34 +0200 Subject: [PATCH 07/23] #6613 #6614 rewrote test logic to be less magic-constant-dependent --- .../ORM/Functional/Ticket/DDC6613Test.php | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php index 16d21bbd1c3..5c3e0c0396b 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php @@ -10,10 +10,6 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\DBAL\Schema\SchemaException; -use Doctrine\ORM\Mapping\Column; -use Doctrine\ORM\Mapping\Entity; -use Doctrine\ORM\Mapping\GeneratedValue; -use Doctrine\ORM\Mapping\Id; use Doctrine\ORM\PersistentCollection; use Doctrine\Tests\OrmFunctionalTestCase; @@ -40,14 +36,17 @@ public function setUp() public function testFail() { - $user = new DDC6613User(); - $this->_em->persist($user); + $newUser = new DDC6613User(); + $this->_em->persist($newUser); $this->_em->flush(); $this->_em->clear(); - /** @var User $user */ - $user = $this->_em->find(User::class, 1); + /** @var DDC6613User $user */ + $user = $this->_em->find(DDC6613User::class, $newUser->id); + + self::assertInstanceOf(DDC6613User::class, $user); + $phone1 = new DDC6613Phone(); $phones = $user->phones; $user->phones->add($phone1); @@ -88,10 +87,10 @@ class DDC6613User * @GeneratedValue(strategy="NONE") * @Column(type="string") */ - private $id; + public $id; /** - * @ManyToMany(targetEntity="Phone", fetch="LAZY", cascade={"remove", "detach"}) + * @ManyToMany(targetEntity=DDC6613Phone::class, fetch="LAZY", cascade={"remove", "detach"}) */ public $phones; @@ -103,6 +102,7 @@ public function __construct() } /** + * @Entity * @Table(name="ddc6613_phone") */ class DDC6613Phone From a4e547b6915bcfed7fbce54ac7c5398a025f48bf Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 11 Aug 2017 14:34:35 +0200 Subject: [PATCH 08/23] #6613 #6614 remove superfluous mappings --- .../ORM/Functional/Ticket/DDC6613Test.php | 28 ++++--------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php index 5c3e0c0396b..26fe56b0192 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php @@ -76,22 +76,13 @@ public function testFail() } } -/** - * @Entity - * @Table(name="ddc6613_user") - */ +/** @Entity */ class DDC6613User { - /** - * @Id - * @GeneratedValue(strategy="NONE") - * @Column(type="string") - */ + /** @Id @Column(type="string") */ public $id; - /** - * @ManyToMany(targetEntity=DDC6613Phone::class, fetch="LAZY", cascade={"remove", "detach"}) - */ + /** @ManyToMany(targetEntity=DDC6613Phone::class) */ public $phones; public function __construct() @@ -101,18 +92,11 @@ public function __construct() } } -/** - * @Entity - * @Table(name="ddc6613_phone") - */ +/** @Entity */ class DDC6613Phone { - /** - * @Id - * @GeneratedValue(strategy="NONE") - * @Column(type="integer") - */ - public $id; + /** @Id @Column(type="integer") */ + private $id; public function __construct() { From 80f12ed49040eb7991f1956fe3a74682b085b318 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 11 Aug 2017 14:41:32 +0200 Subject: [PATCH 09/23] #6613 #6614 correcting column mapping (was `integer`, should be `string`), segregating phone creation away --- .../ORM/Functional/Ticket/DDC6613Test.php | 42 +++++++++---------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php index 26fe56b0192..84f60243d38 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php @@ -9,7 +9,6 @@ namespace Doctrine\Tests\ORM\Functional\Ticket; use Doctrine\Common\Collections\ArrayCollection; -use Doctrine\DBAL\Schema\SchemaException; use Doctrine\ORM\PersistentCollection; use Doctrine\Tests\OrmFunctionalTestCase; @@ -23,46 +22,43 @@ public function setUp() { parent::setUp(); - try { - $this->setUpEntitySchema( - [ - DDC6613Phone::class, - DDC6613User::class, - ] - ); - } catch (SchemaException $e) { - } + $this->setUpEntitySchema([ + DDC6613Phone::class, + DDC6613User::class, + ]); } public function testFail() { $newUser = new DDC6613User(); + $this->_em->persist($newUser); $this->_em->flush(); - $this->_em->clear(); - /** @var DDC6613User $user */ - $user = $this->_em->find(DDC6613User::class, $newUser->id); - - self::assertInstanceOf(DDC6613User::class, $user); - $phone1 = new DDC6613Phone(); - $phones = $user->phones; - $user->phones->add($phone1); + $phone2 = new DDC6613Phone(); + $this->_em->persist($phone1); + $this->_em->persist($phone2); $this->_em->flush(); - $phone2 = new DDC6613Phone(); - $user->phones->add($phone2); - $this->_em->persist($phone2); + /* @var DDC6613User $user */ + $user = $this->_em->find(DDC6613User::class, $newUser->id); + + self::assertInstanceOf(DDC6613User::class, $user); /* @var $phones PersistentCollection */ -// $phones = $user->phones; + $phones = $user->phones; self::assertInstanceOf(PersistentCollection::class, $phones); self::assertFalse($phones->isInitialized()); + $phones->add($phone1); + $this->_em->flush(); + + $phones->add($phone2); + $phones->initialize(); self::assertTrue($phones->isInitialized()); @@ -95,7 +91,7 @@ public function __construct() /** @Entity */ class DDC6613Phone { - /** @Id @Column(type="integer") */ + /** @Id @Column(type="string") */ private $id; public function __construct() From 8c4b5a4b7122b76b1ffaaec68948af307749807d Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 11 Aug 2017 14:44:04 +0200 Subject: [PATCH 10/23] #6613 #6614 removing phone/user specifics, using ORM naming for associations --- .../ORM/Functional/Ticket/DDC6613Test.php | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php index 84f60243d38..2456f1ed97d 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php @@ -23,41 +23,41 @@ public function setUp() parent::setUp(); $this->setUpEntitySchema([ - DDC6613Phone::class, - DDC6613User::class, + DDC6613InverseSide::class, + DDC6613OwningSide::class, ]); } public function testFail() { - $newUser = new DDC6613User(); + $owningSide = new DDC6613OwningSide(); - $this->_em->persist($newUser); + $this->_em->persist($owningSide); $this->_em->flush(); $this->_em->clear(); - $phone1 = new DDC6613Phone(); - $phone2 = new DDC6613Phone(); + $item1 = new DDC6613InverseSide(); + $item2 = new DDC6613InverseSide(); - $this->_em->persist($phone1); - $this->_em->persist($phone2); + $this->_em->persist($item1); + $this->_em->persist($item2); $this->_em->flush(); - /* @var DDC6613User $user */ - $user = $this->_em->find(DDC6613User::class, $newUser->id); + /* @var DDC6613OwningSide $foundOwningSide */ + $foundOwningSide = $this->_em->find(DDC6613OwningSide::class, $owningSide->id); - self::assertInstanceOf(DDC6613User::class, $user); + self::assertInstanceOf(DDC6613OwningSide::class, $foundOwningSide); /* @var $phones PersistentCollection */ - $phones = $user->phones; + $phones = $foundOwningSide->phones; self::assertInstanceOf(PersistentCollection::class, $phones); self::assertFalse($phones->isInitialized()); - $phones->add($phone1); + $phones->add($item1); $this->_em->flush(); - $phones->add($phone2); + $phones->add($item2); $phones->initialize(); @@ -68,17 +68,17 @@ public function testFail() self::assertFalse($phones->isDirty()); self::assertTrue($phones->isInitialized()); - self::assertCount(2, $user->phones); + self::assertCount(2, $foundOwningSide->phones); } } /** @Entity */ -class DDC6613User +class DDC6613OwningSide { /** @Id @Column(type="string") */ public $id; - /** @ManyToMany(targetEntity=DDC6613Phone::class) */ + /** @ManyToMany(targetEntity=DDC6613InverseSide::class) */ public $phones; public function __construct() @@ -89,7 +89,7 @@ public function __construct() } /** @Entity */ -class DDC6613Phone +class DDC6613InverseSide { /** @Id @Column(type="string") */ private $id; From d2c9b22397f3edee08c9f92a5f6df26536f384dc Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 11 Aug 2017 14:44:28 +0200 Subject: [PATCH 11/23] #6613 #6614 removing IDE-generated header --- tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php index 2456f1ed97d..35195f29079 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php @@ -1,10 +1,4 @@ - * Date: 11.08.2017 - * Time: 12:28 - */ namespace Doctrine\Tests\ORM\Functional\Ticket; From 5e2257db04971e753dd008f5f1790c70b06458a2 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 11 Aug 2017 14:46:11 +0200 Subject: [PATCH 12/23] #6613 #6614 adding assertions about collection initialization and dirty status --- .../Tests/ORM/Functional/Ticket/DDC6613Test.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php index 35195f29079..519e88e88a7 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php @@ -47,15 +47,27 @@ public function testFail() self::assertInstanceOf(PersistentCollection::class, $phones); self::assertFalse($phones->isInitialized()); + self::assertFalse($phones->isDirty()); $phones->add($item1); + + self::assertFalse($phones->isInitialized()); + self::assertTrue($phones->isDirty()); + $this->_em->flush(); + self::assertFalse($phones->isInitialized()); + self::assertFalse($phones->isDirty()); + $phones->add($item2); + self::assertFalse($phones->isInitialized()); + self::assertTrue($phones->isDirty()); + $phones->initialize(); self::assertTrue($phones->isInitialized()); + self::assertFalse($phones->isDirty(), 'Possibly wrong assertion'); self::assertCount(2, $phones); $this->_em->flush(); From 1fc7f81741be84bbce6f92c61d6f6c2b4a3e573f Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 11 Aug 2017 14:47:27 +0200 Subject: [PATCH 13/23] #6613 #6614 after initialization, the collection should be dirty anyway --- tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php index 519e88e88a7..d95c8d8ff46 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php @@ -67,7 +67,7 @@ public function testFail() $phones->initialize(); self::assertTrue($phones->isInitialized()); - self::assertFalse($phones->isDirty(), 'Possibly wrong assertion'); + self::assertTrue($phones->isDirty()); self::assertCount(2, $phones); $this->_em->flush(); From d44e6e1a9ec833c4380bf46d26907c3e3e11a22a Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 11 Aug 2017 15:13:39 +0200 Subject: [PATCH 14/23] #6613 #6614 ensuring that only newly added items that weren't loaded are restored in the dirty state of the collection --- lib/Doctrine/ORM/PersistentCollection.php | 34 +++++++++++++++++------ 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/lib/Doctrine/ORM/PersistentCollection.php b/lib/Doctrine/ORM/PersistentCollection.php index 2210c3c310c..3dc254a53a5 100644 --- a/lib/Doctrine/ORM/PersistentCollection.php +++ b/lib/Doctrine/ORM/PersistentCollection.php @@ -692,23 +692,41 @@ public function unwrap() protected function doInitialize() { // Has NEW objects added through add(). Remember them. - $newObjects = []; + $newlyAddedDirtyObjects = []; if ($this->isDirty) { - $newObjects = $this->collection->toArray(); + $newlyAddedDirtyObjects = $this->collection->toArray(); } $this->collection->clear(); $this->em->getUnitOfWork()->loadCollection($this); $this->takeSnapshot(); + if ($newlyAddedDirtyObjects) { + $this->restoreNewObjectsInDirtyCollection($newlyAddedDirtyObjects); + } + } + + /** + * @param object[] $newObjects + * + * @return void + * + * Note: the only reason why this entire looping/complexity is performed via `spl_object_hash` + * is because we want to prevent using `array_udiff()`, which is likely to cause very + * high overhead (complexity of O(n^2)). `array_diff_key()` performs the operation in + * core, which is faster than using a callback for comparisons + */ + private function restoreNewObjectsInDirtyCollection(array $newObjects) + { + $loadedObjects = $this->collection->toArray(); + $newObjectsByOid = array_combine(array_map('spl_object_hash', $newObjects), $newObjects); + $loadedObjectsByOid = array_combine(array_map('spl_object_hash', $loadedObjects), $loadedObjects); + $newObjectsThatWereNotLoaded = array_diff_key($newObjectsByOid, $loadedObjectsByOid); + // Reattach NEW objects added through add(), if any. - if ($newObjects) { - foreach ($newObjects as $obj) { - $this->collection->add($obj); - } + array_walk($newObjectsThatWereNotLoaded, [$this->collection, 'add']); - $this->isDirty = true; - } + $this->isDirty = true; } } From 031e79e726bf08f1fd3acb9047c63419e0377d62 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 11 Aug 2017 15:14:42 +0200 Subject: [PATCH 15/23] #6613 #6614 correcting broken test that isn't using objects against a `PersistentCollection` --- tests/Doctrine/Tests/ORM/PersistentCollectionTest.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php b/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php index 0e1c20f517e..a678b7f5057 100644 --- a/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php +++ b/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php @@ -115,10 +115,12 @@ public function testRemovingElementsAlsoRemovesKeys() { $this->setUpPersistentCollection(); - $this->collection->add('dummy'); + $dummy = new \stdClass(); + + $this->collection->add($dummy); $this->assertEquals([0], array_keys($this->collection->toArray())); - $this->collection->removeElement('dummy'); + $this->collection->removeElement($dummy); $this->assertEquals([], array_keys($this->collection->toArray())); } @@ -129,7 +131,7 @@ public function testClearWillAlsoClearKeys() { $this->setUpPersistentCollection(); - $this->collection->add('dummy'); + $this->collection->add(new \stdClass()); $this->collection->clear(); $this->assertEquals([], array_keys($this->collection->toArray())); } From 345cf1acf84a5c178352e5c6662eb3f6c8a58a56 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 11 Aug 2017 15:15:57 +0200 Subject: [PATCH 16/23] #6613 #6614 correcting broken test that isn't using objects against a `PersistentCollection` --- tests/Doctrine/Tests/ORM/PersistentCollectionTest.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php b/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php index a678b7f5057..1c48cf207c3 100644 --- a/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php +++ b/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php @@ -143,10 +143,12 @@ public function testClearWillAlsoResetKeyPositions() { $this->setUpPersistentCollection(); - $this->collection->add('dummy'); - $this->collection->removeElement('dummy'); + $dummy = new \stdClass(); + + $this->collection->add($dummy); + $this->collection->removeElement($dummy); $this->collection->clear(); - $this->collection->add('dummy'); + $this->collection->add($dummy); $this->assertEquals([0], array_keys($this->collection->toArray())); } } From 04a5b122b0eeeba7a71b2cf240f8e04f06755c90 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 11 Aug 2017 18:58:05 +0200 Subject: [PATCH 17/23] #6613 #6614 #6616 moved integration test basics to a unit test that verifies basic dirty collection initialization semantics --- .../Tests/ORM/PersistentCollectionTest.php | 41 ++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php b/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php index 1c48cf207c3..82b8096a64c 100644 --- a/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php +++ b/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php @@ -3,7 +3,9 @@ namespace Doctrine\Tests\ORM; use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; use Doctrine\ORM\PersistentCollection; +use Doctrine\ORM\UnitOfWork; use Doctrine\Tests\Mocks\ConnectionMock; use Doctrine\Tests\Mocks\DriverMock; use Doctrine\Tests\Mocks\EntityManagerMock; @@ -24,7 +26,7 @@ class PersistentCollectionTest extends OrmTestCase protected $collection; /** - * @var \Doctrine\ORM\EntityManagerInterface + * @var EntityManagerMock */ private $_emMock; @@ -151,4 +153,41 @@ public function testClearWillAlsoResetKeyPositions() $this->collection->add($dummy); $this->assertEquals([0], array_keys($this->collection->toArray())); } + + /** + * @group 6613 + * @group 6614 + * @group 6616 + */ + public function testWillKeepNewItemsAfterInitialization() + { + /* @var $unitOfWork UnitOfWork|\PHPUnit_Framework_MockObject_MockObject */ + $unitOfWork = $this->createMock(UnitOfWork::class); + + $this->_emMock->setUnitOfWork($unitOfWork); + + $this->setUpPersistentCollection(); + + $newElement = new \stdClass(); + $persistedElement = new \stdClass(); + + $this->collection->add($newElement); + + self::assertFalse($this->collection->isInitialized()); + self::assertTrue($this->collection->isDirty()); + + $unitOfWork + ->expects(self::once()) + ->method('loadCollection') + ->with($this->collection) + ->willReturnCallback(function (PersistentCollection $persistentCollection) use ($persistedElement) { + $persistentCollection->unwrap()->add($persistedElement); + }); + + $this->collection->initialize(); + + self::assertSame([$persistedElement, $newElement], $this->collection->toArray()); + self::assertTrue($this->collection->isInitialized()); + self::assertTrue($this->collection->isDirty()); + } } From 93c4064679d4315b8445198919e5eac4b938d7ca Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 11 Aug 2017 19:02:39 +0200 Subject: [PATCH 18/23] #6613 #6614 #6616 initializing a dirty collection that has new items that are also coming from initialization data de-duplicates new and persisted items --- .../Tests/ORM/PersistentCollectionTest.php | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php b/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php index 82b8096a64c..4c7f14f79a5 100644 --- a/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php +++ b/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php @@ -159,7 +159,7 @@ public function testClearWillAlsoResetKeyPositions() * @group 6614 * @group 6616 */ - public function testWillKeepNewItemsAfterInitialization() + public function testWillKeepNewItemsInDirtyCollectionAfterInitialization() { /* @var $unitOfWork UnitOfWork|\PHPUnit_Framework_MockObject_MockObject */ $unitOfWork = $this->createMock(UnitOfWork::class); @@ -190,4 +190,50 @@ public function testWillKeepNewItemsAfterInitialization() self::assertTrue($this->collection->isInitialized()); self::assertTrue($this->collection->isDirty()); } + + /** + * @group 6613 + * @group 6614 + * @group 6616 + */ + public function testWillDeDuplicateNewItemsThatWerePreviouslyPersistedInDirtyCollectionAfterInitialization() + { + /* @var $unitOfWork UnitOfWork|\PHPUnit_Framework_MockObject_MockObject */ + $unitOfWork = $this->createMock(UnitOfWork::class); + + $this->_emMock->setUnitOfWork($unitOfWork); + + $this->setUpPersistentCollection(); + + $newElement = new \stdClass(); + $newElementThatIsAlsoPersisted = new \stdClass(); + $persistedElement = new \stdClass(); + + $this->collection->add($newElementThatIsAlsoPersisted); + $this->collection->add($newElement); + + self::assertFalse($this->collection->isInitialized()); + self::assertTrue($this->collection->isDirty()); + + $unitOfWork + ->expects(self::once()) + ->method('loadCollection') + ->with($this->collection) + ->willReturnCallback(function (PersistentCollection $persistentCollection) use ( + $persistedElement, + $newElementThatIsAlsoPersisted + ) { + $persistentCollection->unwrap()->add($newElementThatIsAlsoPersisted); + $persistentCollection->unwrap()->add($persistedElement); + }); + + $this->collection->initialize(); + + self::assertSame( + [$newElementThatIsAlsoPersisted, $persistedElement, $newElement], + $this->collection->toArray() + ); + self::assertTrue($this->collection->isInitialized()); + self::assertTrue($this->collection->isDirty()); + } } From b064fe3d8600d85f9f098e4fed8f1e3bd0fc1cf9 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 11 Aug 2017 19:08:24 +0200 Subject: [PATCH 19/23] #6613 #6614 #6616 removing repeated `PersistentCollectionTest` chunks of code --- .../Tests/ORM/PersistentCollectionTest.php | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php b/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php index 4c7f14f79a5..e4566620bb7 100644 --- a/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php +++ b/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php @@ -35,6 +35,8 @@ protected function setUp() parent::setUp(); $this->_emMock = EntityManagerMock::create(new ConnectionMock([], new DriverMock())); + + $this->setUpPersistentCollection(); } /** @@ -61,7 +63,6 @@ public function testCanBePutInLazyLoadingMode() */ public function testCurrentInitializesCollection() { - $this->setUpPersistentCollection(); $this->collection->current(); $this->assertTrue($this->collection->isInitialized()); } @@ -71,7 +72,6 @@ public function testCurrentInitializesCollection() */ public function testKeyInitializesCollection() { - $this->setUpPersistentCollection(); $this->collection->key(); $this->assertTrue($this->collection->isInitialized()); } @@ -81,7 +81,6 @@ public function testKeyInitializesCollection() */ public function testNextInitializesCollection() { - $this->setUpPersistentCollection(); $this->collection->next(); $this->assertTrue($this->collection->isInitialized()); } @@ -91,8 +90,6 @@ public function testNextInitializesCollection() */ public function testNonObjects() { - $this->setUpPersistentCollection(); - $this->assertEmpty($this->collection); $this->collection->add("dummy"); @@ -115,8 +112,6 @@ public function testNonObjects() */ public function testRemovingElementsAlsoRemovesKeys() { - $this->setUpPersistentCollection(); - $dummy = new \stdClass(); $this->collection->add($dummy); @@ -131,8 +126,6 @@ public function testRemovingElementsAlsoRemovesKeys() */ public function testClearWillAlsoClearKeys() { - $this->setUpPersistentCollection(); - $this->collection->add(new \stdClass()); $this->collection->clear(); $this->assertEquals([], array_keys($this->collection->toArray())); @@ -143,8 +136,6 @@ public function testClearWillAlsoClearKeys() */ public function testClearWillAlsoResetKeyPositions() { - $this->setUpPersistentCollection(); - $dummy = new \stdClass(); $this->collection->add($dummy); @@ -166,8 +157,6 @@ public function testWillKeepNewItemsInDirtyCollectionAfterInitialization() $this->_emMock->setUnitOfWork($unitOfWork); - $this->setUpPersistentCollection(); - $newElement = new \stdClass(); $persistedElement = new \stdClass(); @@ -203,8 +192,6 @@ public function testWillDeDuplicateNewItemsThatWerePreviouslyPersistedInDirtyCol $this->_emMock->setUnitOfWork($unitOfWork); - $this->setUpPersistentCollection(); - $newElement = new \stdClass(); $newElementThatIsAlsoPersisted = new \stdClass(); $persistedElement = new \stdClass(); From 1174ec6e8ae746bbbae865dcdab6dbfe2c6899b5 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Fri, 11 Aug 2017 20:37:23 +0200 Subject: [PATCH 20/23] Add failing test for dirty flag --- .../Tests/ORM/PersistentCollectionTest.php | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php b/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php index e4566620bb7..c7b68fe5283 100644 --- a/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php +++ b/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php @@ -223,4 +223,46 @@ public function testWillDeDuplicateNewItemsThatWerePreviouslyPersistedInDirtyCol self::assertTrue($this->collection->isInitialized()); self::assertTrue($this->collection->isDirty()); } + + /** + * @group 6613 + * @group 6614 + * @group 6616 + */ + public function testWillNotMarkCollectionAsDirtyAfterInitializationIfNoElementsWereAdded() + { + /* @var $unitOfWork UnitOfWork|\PHPUnit_Framework_MockObject_MockObject */ + $unitOfWork = $this->createMock(UnitOfWork::class); + + $this->_emMock->setUnitOfWork($unitOfWork); + + $newElementThatIsAlsoPersisted = new \stdClass(); + $persistedElement = new \stdClass(); + + $this->collection->add($newElementThatIsAlsoPersisted); + + self::assertFalse($this->collection->isInitialized()); + self::assertTrue($this->collection->isDirty()); + + $unitOfWork + ->expects(self::once()) + ->method('loadCollection') + ->with($this->collection) + ->willReturnCallback(function (PersistentCollection $persistentCollection) use ( + $persistedElement, + $newElementThatIsAlsoPersisted + ) { + $persistentCollection->unwrap()->add($newElementThatIsAlsoPersisted); + $persistentCollection->unwrap()->add($persistedElement); + }); + + $this->collection->initialize(); + + self::assertSame( + [$newElementThatIsAlsoPersisted, $persistedElement], + $this->collection->toArray() + ); + self::assertTrue($this->collection->isInitialized()); + self::assertFalse($this->collection->isDirty()); + } } From a2ca6bbfafd0200d2cf658f5b4fd9e80d65c3d9d Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 11 Aug 2017 21:09:34 +0200 Subject: [PATCH 21/23] #6613 #6614 #6616 ensuring that the collection is marked as non-dirty if all new items are contained in the initialized ones --- lib/Doctrine/ORM/PersistentCollection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Doctrine/ORM/PersistentCollection.php b/lib/Doctrine/ORM/PersistentCollection.php index 3dc254a53a5..1ce3e495bde 100644 --- a/lib/Doctrine/ORM/PersistentCollection.php +++ b/lib/Doctrine/ORM/PersistentCollection.php @@ -727,6 +727,6 @@ private function restoreNewObjectsInDirtyCollection(array $newObjects) // Reattach NEW objects added through add(), if any. array_walk($newObjectsThatWereNotLoaded, [$this->collection, 'add']); - $this->isDirty = true; + $this->isDirty = (bool) $newObjectsThatWereNotLoaded; } } From 35799975310d2f9c9a2c11c0400c30b801e0328d Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 11 Aug 2017 21:11:31 +0200 Subject: [PATCH 22/23] #6613 #6614 #6616 removing DDC6613 test, which was fully ported to unit tests --- .../ORM/Functional/Ticket/DDC6613Test.php | 107 ------------------ 1 file changed, 107 deletions(-) delete mode 100644 tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php deleted file mode 100644 index d95c8d8ff46..00000000000 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC6613Test.php +++ /dev/null @@ -1,107 +0,0 @@ -setUpEntitySchema([ - DDC6613InverseSide::class, - DDC6613OwningSide::class, - ]); - } - - public function testFail() - { - $owningSide = new DDC6613OwningSide(); - - $this->_em->persist($owningSide); - $this->_em->flush(); - $this->_em->clear(); - - $item1 = new DDC6613InverseSide(); - $item2 = new DDC6613InverseSide(); - - $this->_em->persist($item1); - $this->_em->persist($item2); - $this->_em->flush(); - - /* @var DDC6613OwningSide $foundOwningSide */ - $foundOwningSide = $this->_em->find(DDC6613OwningSide::class, $owningSide->id); - - self::assertInstanceOf(DDC6613OwningSide::class, $foundOwningSide); - - /* @var $phones PersistentCollection */ - $phones = $foundOwningSide->phones; - - self::assertInstanceOf(PersistentCollection::class, $phones); - self::assertFalse($phones->isInitialized()); - self::assertFalse($phones->isDirty()); - - $phones->add($item1); - - self::assertFalse($phones->isInitialized()); - self::assertTrue($phones->isDirty()); - - $this->_em->flush(); - - self::assertFalse($phones->isInitialized()); - self::assertFalse($phones->isDirty()); - - $phones->add($item2); - - self::assertFalse($phones->isInitialized()); - self::assertTrue($phones->isDirty()); - - $phones->initialize(); - - self::assertTrue($phones->isInitialized()); - self::assertTrue($phones->isDirty()); - self::assertCount(2, $phones); - - $this->_em->flush(); - - self::assertFalse($phones->isDirty()); - self::assertTrue($phones->isInitialized()); - self::assertCount(2, $foundOwningSide->phones); - } -} - -/** @Entity */ -class DDC6613OwningSide -{ - /** @Id @Column(type="string") */ - public $id; - - /** @ManyToMany(targetEntity=DDC6613InverseSide::class) */ - public $phones; - - public function __construct() - { - $this->id = uniqid('user', true); - $this->phones = new ArrayCollection(); - } -} - -/** @Entity */ -class DDC6613InverseSide -{ - /** @Id @Column(type="string") */ - private $id; - - public function __construct() - { - $this->id = uniqid('phone', true); - } -} \ No newline at end of file From 004ac518695da8a0194d1dbd2ba00574a6027a12 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 11 Aug 2017 21:14:05 +0200 Subject: [PATCH 23/23] #6613 #6614 #6616 minor performance optimisations around the new `restoreNewObjectsInDirtyCollection` implementation --- lib/Doctrine/ORM/PersistentCollection.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/Doctrine/ORM/PersistentCollection.php b/lib/Doctrine/ORM/PersistentCollection.php index 1ce3e495bde..9abea4f22ca 100644 --- a/lib/Doctrine/ORM/PersistentCollection.php +++ b/lib/Doctrine/ORM/PersistentCollection.php @@ -720,13 +720,15 @@ protected function doInitialize() private function restoreNewObjectsInDirtyCollection(array $newObjects) { $loadedObjects = $this->collection->toArray(); - $newObjectsByOid = array_combine(array_map('spl_object_hash', $newObjects), $newObjects); - $loadedObjectsByOid = array_combine(array_map('spl_object_hash', $loadedObjects), $loadedObjects); - $newObjectsThatWereNotLoaded = array_diff_key($newObjectsByOid, $loadedObjectsByOid); + $newObjectsByOid = \array_combine(\array_map('spl_object_hash', $newObjects), $newObjects); + $loadedObjectsByOid = \array_combine(\array_map('spl_object_hash', $loadedObjects), $loadedObjects); + $newObjectsThatWereNotLoaded = \array_diff_key($newObjectsByOid, $loadedObjectsByOid); - // Reattach NEW objects added through add(), if any. - array_walk($newObjectsThatWereNotLoaded, [$this->collection, 'add']); + if ($newObjectsThatWereNotLoaded) { + // Reattach NEW objects added through add(), if any. + \array_walk($newObjectsThatWereNotLoaded, [$this->collection, 'add']); - $this->isDirty = (bool) $newObjectsThatWereNotLoaded; + $this->isDirty = true; + } } }