1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
|
<?php
declare(strict_types=1);
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\ConversionException;
use Doctrine\DBAL\Types\StringType;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\Table;
use Doctrine\Tests\OrmFunctionalTestCase;
use PHPUnit\Framework\Attributes\Group;
use Stringable;
use function is_string;
#[Group('DDC-2984')]
class DDC2984Test extends OrmFunctionalTestCase
{
protected function setUp(): void
{
parent::setUp();
if (! Type::hasType('ddc2984_domain_user_id')) {
Type::addType(
'ddc2984_domain_user_id',
DDC2984UserIdCustomDbalType::class,
);
}
$this->createSchemaForModels(DDC2984User::class);
}
public function testIssue(): void
{
$user = new DDC2984User(new DDC2984DomainUserId('unique_id_within_a_vo'));
$user->applyName('Alex');
$this->_em->persist($user);
$this->_em->flush();
$repository = $this->_em->getRepository(__NAMESPACE__ . '\DDC2984User');
$sameUser = $repository->find(new DDC2984DomainUserId('unique_id_within_a_vo'));
//Until know, everything works as expected
self::assertTrue($user->sameIdentityAs($sameUser));
$this->_em->clear();
//After clearing the identity map, the UnitOfWork produces the warning described in DDC-2984
$equalUser = $repository->find(new DDC2984DomainUserId('unique_id_within_a_vo'));
self::assertNotSame($user, $equalUser);
self::assertTrue($user->sameIdentityAs($equalUser));
}
}
#[Table(name: 'users')]
#[Entity]
class DDC2984User
{
#[Column(type: 'string', length: 50)]
private string|null $name = null;
public function __construct(
#[Id]
#[Column(type: 'ddc2984_domain_user_id', length: 255)]
#[GeneratedValue(strategy: 'NONE')]
private DDC2984DomainUserId $userId,
) {
}
public function userId(): DDC2984DomainUserId
{
return $this->userId;
}
public function name(): string
{
return $this->name;
}
public function applyName(string $name): void
{
$this->name = $name;
}
public function sameIdentityAs(DDC2984User $other): bool
{
return $this->userId()->sameValueAs($other->userId());
}
}
/**
* DDC2984DomainUserId ValueObject
*/
class DDC2984DomainUserId implements Stringable
{
public function __construct(private string $userIdString)
{
}
public function toString(): string
{
return $this->userIdString;
}
public function __toString(): string
{
return $this->toString();
}
public function sameValueAs(DDC2984DomainUserId $other): bool
{
return $this->toString() === $other->toString();
}
}
class DDC2984UserIdCustomDbalType extends StringType
{
private const TYPE_NAME = 'ddc2984_domain_user_id';
public function getName(): string
{
return self::TYPE_NAME;
}
/**
* {@inheritDoc}
*/
public function convertToPHPValue($value, AbstractPlatform $platform): DDC2984DomainUserId|null
{
return ! empty($value)
? new DDC2984DomainUserId($value)
: null;
}
/**
* {@inheritDoc}
*/
public function convertToDatabaseValue($value, AbstractPlatform $platform): mixed
{
if (empty($value)) {
return null;
}
if (is_string($value)) {
return $value;
}
if (! $value instanceof DDC2984DomainUserId) {
throw ConversionException::conversionFailed($value, self::TYPE_NAME);
}
return $value->toString();
}
}
|