Skip to content
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

Fix OneToManyPersister::deleteEntityCollection missing discriminator column/value. (GH-11500) #11501

Merged
merged 1 commit into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion src/Persisters/Collection/OneToManyPersister.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
use Doctrine\Common\Collections\Criteria;
use Doctrine\DBAL\Exception as DBALException;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\EntityNotFoundException;
use Doctrine\ORM\Mapping\MappingException;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Utility\PersisterHelper;

Expand Down Expand Up @@ -166,7 +168,11 @@ public function loadCriteria(PersistentCollection $collection, Criteria $criteri
throw new BadMethodCallException('Filtering a collection by Criteria is not supported by this CollectionPersister.');
}

/** @throws DBALException */
/**
* @throws DBALException
* @throws EntityNotFoundException
* @throws MappingException
*/
private function deleteEntityCollection(PersistentCollection $collection): int
{
$mapping = $collection->getMapping();
Expand All @@ -186,6 +192,13 @@ private function deleteEntityCollection(PersistentCollection $collection): int
$statement = 'DELETE FROM ' . $this->quoteStrategy->getTableName($targetClass, $this->platform)
. ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?';

if ($targetClass->isInheritanceTypeSingleTable()) {
$discriminatorColumn = $targetClass->getDiscriminatorColumn();
$statement .= ' AND ' . $discriminatorColumn['name'] . ' = ?';
$parameters[] = $targetClass->discriminatorValue;
$types[] = $discriminatorColumn['type'];
}

$numAffected = $this->conn->executeStatement($statement, $parameters, $types);

assert(is_int($numAffected));
Expand Down
137 changes: 137 additions & 0 deletions tests/Tests/ORM/Functional/Ticket/GH11500Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\ORM\Functional\Ticket;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Exception\ORMException;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Tests\OrmFunctionalTestCase;

class GH11500Test extends OrmFunctionalTestCase
{
protected function setUp(): void
{
parent::setUp();

$this->setUpEntitySchema([
GH11500AbstractTestEntity::class,
GH11500TestEntityOne::class,
GH11500TestEntityTwo::class,
GH11500TestEntityHolder::class,
]);
}

/**
* @throws ORMException
*/
public function testDeleteOneToManyCollectionWithSingleTableInheritance(): void
{
$testEntityOne = new GH11500TestEntityOne();
$testEntityTwo = new GH11500TestEntityTwo();
$testEntityHolder = new GH11500TestEntityHolder();

$testEntityOne->testEntityHolder = $testEntityHolder;
$testEntityHolder->testEntityOnes->add($testEntityOne);

$testEntityTwo->testEntityHolder = $testEntityHolder;
$testEntityHolder->testEntityTwos->add($testEntityTwo);

$em = $this->getEntityManager();
$em->persist($testEntityOne);
$em->persist($testEntityTwo);
$em->persist($testEntityHolder);
$em->flush();

$testEntityTwosBeforeRemovalOfTestEntityOnes = $testEntityHolder->testEntityTwos->toArray();

$testEntityHolder->testEntityOnes = new ArrayCollection();
$em->persist($testEntityHolder);
$em->flush();
$em->refresh($testEntityHolder);

static::assertEmpty($testEntityHolder->testEntityOnes->toArray(), 'All records should have been deleted');
static::assertEquals($testEntityTwosBeforeRemovalOfTestEntityOnes, $testEntityHolder->testEntityTwos->toArray(), 'Different Entity\'s records should not have been deleted');
}
}



/**
* @ORM\Entity
* @ORM\Table(name="one_to_many_single_table_inheritance_test_entities")
* @ORM\InheritanceType("SINGLE_TABLE")
* @ORM\DiscriminatorColumn(name="type", type="string")
* @ORM\DiscriminatorMap({"test_entity_one"="GH11500TestEntityOne", "test_entity_two"="GH11500TestEntityTwo"})
*/
class GH11500AbstractTestEntity
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue
*
* @var int
*/
public $id;
}


/** @ORM\Entity */
class GH11500TestEntityOne extends GH11500AbstractTestEntity
{
/**
* @ORM\ManyToOne(targetEntity="GH11500TestEntityHolder", inversedBy="testEntityOnes")
* @ORM\JoinColumn(name="test_entity_holder_id", referencedColumnName="id")
*
* @var GH11500TestEntityHolder
*/
public $testEntityHolder;
}

/** @ORM\Entity */
class GH11500TestEntityTwo extends GH11500AbstractTestEntity
{
/**
* @ORM\ManyToOne(targetEntity="GH11500TestEntityHolder", inversedBy="testEntityTwos")
* @ORM\JoinColumn(name="test_entity_holder_id", referencedColumnName="id")
*
* @var GH11500TestEntityHolder
*/
public $testEntityHolder;
}

/** @ORM\Entity */
class GH11500TestEntityHolder
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue
*
* @var int
*/
public $id;

/**
* @ORM\OneToMany(targetEntity="GH11500TestEntityOne", mappedBy="testEntityHolder", orphanRemoval=true)
*
* @var Collection
*/
public $testEntityOnes;

/**
* @ORM\OneToMany(targetEntity="GH11500TestEntityTwo", mappedBy="testEntityHolder", orphanRemoval=true)
*
* @var Collection
*/
public $testEntityTwos;

public function __construct()
{
$this->testEntityOnes = new ArrayCollection();
$this->testEntityTwos = new ArrayCollection();
}
}
Loading