-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add test to show why delete-before-insert may be challenging #10809
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Doctrine\Tests\ORM\Functional\Ticket; | ||
|
||
use Doctrine\Common\Collections\ArrayCollection; | ||
use Doctrine\Common\Collections\Collection; | ||
use Doctrine\ORM\Mapping as ORM; | ||
use Doctrine\Tests\OrmFunctionalTestCase; | ||
|
||
class GH5742Test extends OrmFunctionalTestCase | ||
{ | ||
protected function setUp(): void | ||
{ | ||
parent::setUp(); | ||
|
||
$this->createSchemaForModels( | ||
GH5742Person::class, | ||
GH5742Toothbrush::class, | ||
GH5742ToothpasteBrand::class | ||
); | ||
} | ||
|
||
public function testUpdateOneToOneToNewEntityBeforePreviousEntityCanBeRemoved(): void | ||
{ | ||
$person = new GH5742Person(); | ||
$oldToothbrush = new GH5742Toothbrush(); | ||
$person->toothbrush = $oldToothbrush; | ||
|
||
$this->_em->persist($person); | ||
$this->_em->persist($oldToothbrush); | ||
$this->_em->flush(); | ||
|
||
$oldToothbrushId = $oldToothbrush->id; | ||
|
||
$newToothbrush = new GH5742Toothbrush(); | ||
$person->toothbrush = $newToothbrush; | ||
|
||
$this->_em->remove($oldToothbrush); | ||
$this->_em->persist($newToothbrush); | ||
|
||
// The flush operation will have to make sure the new toothbrush | ||
// has been written to the database | ||
// _before_ the person can be updated to refer to it. | ||
// Likewise, the update must have happened _before_ the old | ||
// toothbrush can be removed (non-nullable FK constraint). | ||
|
||
$this->_em->flush(); | ||
|
||
$this->_em->clear(); | ||
self::assertSame($newToothbrush->id, $this->_em->find(GH5742Person::class, $person->id)->toothbrush->id); | ||
self::assertNull($this->_em->find(GH5742Toothbrush::class, $oldToothbrushId)); | ||
} | ||
|
||
public function testManyToManyCollectionUpdateBeforeRemoval(): void | ||
{ | ||
$person = new GH5742Person(); | ||
$person->toothbrush = new GH5742Toothbrush(); // to satisfy not-null constraint | ||
$this->_em->persist($person); | ||
|
||
$oldMice = new GH5742ToothpasteBrand(); | ||
$this->_em->persist($oldMice); | ||
|
||
$person->preferredBrands->set(1, $oldMice); | ||
$this->_em->flush(); | ||
|
||
$oldBrandId = $oldMice->id; | ||
|
||
$newSpice = new GH5742ToothpasteBrand(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "old mice"? "new spice" What's the joke? I don't get it… 🤔 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Old mice 🐁 is not so yum. New spice might me something fresh like peppermint? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense :) |
||
$this->_em->persist($newSpice); | ||
|
||
$person->preferredBrands->set(1, $newSpice); | ||
|
||
$this->_em->remove($oldMice); | ||
|
||
// The flush operation will have to make sure the new brand | ||
// has been written to the database _before_ it can be referred | ||
// to from the m2m join table. | ||
// Likewise, the old join table entry must have been removed | ||
// _before_ the old brand can be removed. | ||
|
||
$this->_em->flush(); | ||
|
||
$this->_em->clear(); | ||
self::assertCount(1, $this->_em->find(GH5742Person::class, $person->id)->preferredBrands); | ||
self::assertNull($this->_em->find(GH5742ToothpasteBrand::class, $oldBrandId)); | ||
} | ||
} | ||
|
||
/** | ||
* @ORM\Entity | ||
*/ | ||
class GH5742Person | ||
{ | ||
/** | ||
* @ORM\Id | ||
* @ORM\GeneratedValue(strategy="AUTO") | ||
* @ORM\Column(type="integer") | ||
* | ||
* @var int | ||
*/ | ||
public $id; | ||
|
||
/** | ||
* @ORM\OneToOne(targetEntity="GH5742Toothbrush", cascade={"persist"}) | ||
* @ORM\JoinColumn(nullable=false) | ||
* | ||
* @var GH5742Toothbrush | ||
*/ | ||
public $toothbrush; | ||
|
||
/** | ||
* @ORM\ManyToMany(targetEntity="GH5742ToothpasteBrand") | ||
* @ORM\JoinTable(name="gh5742person_gh5742toothpastebrand", | ||
* joinColumns={@ORM\JoinColumn(name="person_id", referencedColumnName="id", onDelete="CASCADE")}, | ||
* inverseJoinColumns={@ORM\JoinColumn(name="brand_id", referencedColumnName="id")} | ||
* ) | ||
* | ||
* @var Collection<GH5742ToothpasteBrand> | ||
*/ | ||
public $preferredBrands; | ||
|
||
public function __construct() | ||
{ | ||
$this->preferredBrands = new ArrayCollection(); | ||
} | ||
} | ||
|
||
/** | ||
* @ORM\Entity | ||
*/ | ||
class GH5742Toothbrush | ||
{ | ||
/** | ||
* @ORM\Id | ||
* @ORM\GeneratedValue(strategy="AUTO") | ||
* @ORM\Column(type="integer") | ||
* | ||
* @var int | ||
*/ | ||
public $id; | ||
} | ||
|
||
/** | ||
* @ORM\Entity | ||
*/ | ||
class GH5742ToothpasteBrand | ||
{ | ||
/** | ||
* @ORM\Id | ||
* @ORM\GeneratedValue(strategy="AUTO") | ||
* @ORM\Column(type="integer") | ||
* | ||
* @var int | ||
*/ | ||
public $id; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aaaah a funny test at last… this is going to be good! 🍿
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I designed it that way particularly with you in mind 😉