Skip to content

Commit

Permalink
fix: OneToManyPersister does not take custom types into account for o…
Browse files Browse the repository at this point in the history
…rphan removal
  • Loading branch information
wtfzdotnet committed Jun 3, 2023
1 parent 4dfbe13 commit 97ebed4
Show file tree
Hide file tree
Showing 2 changed files with 197 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -174,16 +174,18 @@ private function deleteEntityCollection(PersistentCollection $collection): int
$targetClass = $this->em->getClassMetadata($mapping['targetEntity']);
$columns = [];
$parameters = [];
$types = [];

foreach ($targetClass->associationMappings[$mapping['mappedBy']]['joinColumns'] as $joinColumn) {
$columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform);
$parameters[] = $identifier[$sourceClass->getFieldForColumn($joinColumn['referencedColumnName'])];
$types[] = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $sourceClass, $this->em);
}

$statement = 'DELETE FROM ' . $this->quoteStrategy->getTableName($targetClass, $this->platform)
. ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?';

return $this->conn->executeStatement($statement, $parameters);
return $this->conn->executeStatement($statement, $parameters, $types);
}

/**
Expand Down
194 changes: 194 additions & 0 deletions tests/Doctrine/Tests/ORM/Functional/GH10747Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\ORM\Functional;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\Type as DBALType;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\Table;
use Doctrine\Tests\DbalTypes\CustomIdObject;
use Doctrine\Tests\OrmFunctionalTestCase;

use function method_exists;
use function str_replace;

/**
* Functional tests for asserting that orphaned children in a OneToMany relationship get removed with a custom identifier
*
* @group GH10747
*/
final class GH10747Test extends OrmFunctionalTestCase
{
protected function setUp(): void
{
parent::setUp();

if (! DBALType::hasType(GH10747CustomIdObjectHashType::class)) {
DBALType::addType(GH10747CustomIdObjectHashType::class, GH10747CustomIdObjectHashType::class);
}

$this->setUpEntitySchema([GH10747Article::class, GH10747Credit::class]);
}

public function testOrphanedOneToManyDeletesCollection(): void
{
$object = new GH10747Article(
new CustomIdObject('article')
);

$creditOne = new GH10747Credit(
$object,
'credit1'
);

$creditTwo = new GH10747Credit(
$object,
'credit2'
);

$object->setCredits(new ArrayCollection([$creditOne, $creditTwo]));

$this->_em->persist($object);
$this->_em->persist($creditOne);
$this->_em->persist($creditTwo);
$this->_em->flush();

$id = $object->id;

$object2 = $this->_em->find(GH10747Article::class, $id);

$creditThree = new GH10747Credit(
$object2,
'credit3'
);

$object2->setCredits(new ArrayCollection([$creditThree]));

$this->_em->persist($object2);
$this->_em->persist($creditThree);
$this->_em->flush();

$currentDatabaseCredits = $this->_em->createQueryBuilder()
->select('c.id')
->from(GH10747Credit::class, 'c')
->getQuery()
->execute();

self::assertCount(1, $currentDatabaseCredits);
}
}

/**
* @Entity
* @Table
*/
class GH10747Article
{
/**
* @Id
* @Column(type="Doctrine\Tests\ORM\Functional\GH10747CustomIdObjectHashType")
* @var CustomIdObject
*/
public $id;

/**
* @ORM\OneToMany(targetEntity="GH10747Credit", mappedBy="article", orphanRemoval=true)
*
* @var Collection
*/
public $credits;

public function __construct(CustomIdObject $id)
{
$this->id = $id;
$this->credits = new ArrayCollection();
}

public function setCredits(Collection $credits): void
{
$this->credits = $credits;
}

/** @return Collection<int, GH10747Credit> */
public function getCredits(): Collection
{
return $this->credits;
}
}

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

/** @var string */
public $name;

/**
* @ORM\ManyToOne(targetEntity="GH10747Article", inversedBy="credits")
*
* @var GH10747Article
*/
public $article;

public function __construct(GH10747Article $article, string $name)
{
$this->article = $article;
$this->name = $name;
}
}

class GH10747CustomIdObjectHashType extends DBALType
{
/**
* {@inheritDoc}
*/
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
return $value->id . '_test';
}

/**
* {@inheritDoc}
*/
public function convertToPHPValue($value, AbstractPlatform $platform)
{
return new CustomIdObject(str_replace('_test', '', $value));
}

/**
* {@inheritDoc}
*/
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
if (method_exists($platform, 'getStringTypeDeclarationSQL')) {
return $platform->getStringTypeDeclarationSQL($fieldDeclaration);
}

return $platform->getVarcharTypeDeclarationSQL($fieldDeclaration);
}

/**
* {@inheritDoc}
*/
public function getName()
{
return self::class;
}
}

0 comments on commit 97ebed4

Please sign in to comment.