Skip to content

Commit f1fddb3

Browse files
committed
fix(GH12017): Reproductions tests - generated fields make the uow believe the entity is dirty
1 parent 4262eb4 commit f1fddb3

2 files changed

Lines changed: 226 additions & 0 deletions

File tree

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Tests\ORM\Functional\Ticket;
6+
7+
use DateTimeImmutable;
8+
use Doctrine\DBAL\Schema\DefaultExpression\CurrentTimestamp;
9+
use Doctrine\DBAL\Types\Types;
10+
use Doctrine\ORM\Mapping as ORM;
11+
use Doctrine\ORM\Mapping\DiscriminatorColumn;
12+
use Doctrine\ORM\Mapping\DiscriminatorMap;
13+
use Doctrine\ORM\Mapping\InheritanceType;
14+
use Doctrine\Tests\OrmFunctionalTestCase;
15+
16+
class GH12017SubClassTest extends OrmFunctionalTestCase
17+
{
18+
protected function setUp(): void
19+
{
20+
parent::setUp();
21+
22+
$this->createSchemaForModels(GH12017ParentEntity::class, GH12017ChildEntity::class);
23+
}
24+
25+
public function testGeneratedFieldFromChildShouldNotBeDetectedAsChangeAfterInsert(): void
26+
{
27+
$entity = new GH12017ChildEntity();
28+
29+
$this->_em->persist($entity);
30+
$this->_em->flush();
31+
32+
$uow = $this->_em->getUnitOfWork();
33+
$uow->computeChangeSets();
34+
35+
self::assertFalse(
36+
$uow->isScheduledForUpdate($entity),
37+
'Entity should not be scheduled for update after a generated field was refreshed from the DB',
38+
);
39+
}
40+
41+
public function testGeneratedStringFieldShouldNotBeDetectedAsChangeAfterInsert(): void
42+
{
43+
$entity = new GH12017ChildEntity();
44+
$this->_em->persist($entity);
45+
$this->_em->flush();
46+
47+
$uow = $this->_em->getUnitOfWork();
48+
$uow->computeChangeSets();
49+
50+
self::assertFalse(
51+
$uow->isScheduledForUpdate($entity),
52+
'Entity should not be scheduled for update after a generated string field was refreshed from the DB',
53+
);
54+
}
55+
56+
public function testGeneratedFieldShouldNotBeDetectedAsChangeAfterUpdate(): void
57+
{
58+
$entity = new GH12017ChildEntity();
59+
$this->_em->persist($entity);
60+
$this->_em->flush();
61+
62+
$entity->other = 1;
63+
$this->_em->flush();
64+
65+
$uow = $this->_em->getUnitOfWork();
66+
$uow->computeChangeSets();
67+
self::assertFalse(
68+
$uow->isScheduledForUpdate($entity),
69+
'Entity should not be scheduled for update after a generated field was refreshed from the DB',
70+
);
71+
}
72+
}
73+
74+
#[ORM\MappedSuperclass]
75+
#[InheritanceType('JOINED')]
76+
#[DiscriminatorColumn(name: 'discr', type: 'string')]
77+
#[DiscriminatorMap(['child' => GH12017ChildEntity::class])]
78+
#[ORM\Entity]
79+
#[ORM\Table(name: 'gh12017_parent')]
80+
class GH12017ParentEntity
81+
{
82+
#[ORM\Id]
83+
#[ORM\GeneratedValue]
84+
#[ORM\Column]
85+
public int $id;
86+
87+
#[ORM\Column(
88+
type: Types::INTEGER,
89+
nullable: false,
90+
options: ['default' => 0],
91+
)]
92+
public int $other = 0;
93+
}
94+
95+
#[ORM\Entity]
96+
#[ORM\Table(name: 'gh12017_child')]
97+
class GH12017ChildEntity extends GH12017ParentEntity
98+
{
99+
#[ORM\Column(
100+
type: Types::DATETIME_IMMUTABLE,
101+
insertable: false,
102+
updatable: false,
103+
options: ['default' => new CurrentTimestamp()],
104+
generated: 'ALWAYS',
105+
)]
106+
public DateTimeImmutable|null $tested = null;
107+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Tests\ORM\Functional\Ticket;
6+
7+
use DateTimeImmutable;
8+
use Doctrine\DBAL\Schema\DefaultExpression\CurrentTimestamp;
9+
use Doctrine\DBAL\Types\Types;
10+
use Doctrine\ORM\Mapping as ORM;
11+
use Doctrine\Tests\OrmFunctionalTestCase;
12+
13+
class GH12017Test extends OrmFunctionalTestCase
14+
{
15+
protected function setUp(): void
16+
{
17+
parent::setUp();
18+
19+
$this->createSchemaForModels(GH12017Entity::class, GH12017EntityWithStringField::class);
20+
}
21+
22+
public function testGeneratedFieldShouldNotBeDetectedAsChangeAfterFlush(): void
23+
{
24+
$entity = new GH12017Entity();
25+
26+
$this->_em->persist($entity);
27+
$this->_em->flush();
28+
29+
$uow = $this->_em->getUnitOfWork();
30+
$uow->computeChangeSets();
31+
32+
self::assertFalse(
33+
$uow->isScheduledForUpdate($entity),
34+
'Entity should not be scheduled for update after a generated field was refreshed from the DB',
35+
);
36+
}
37+
38+
public function testGeneratedStringFieldShouldNotBeDetectedAsChangeAfterFlush(): void
39+
{
40+
$entity = new GH12017EntityWithStringField();
41+
42+
$this->_em->persist($entity);
43+
$this->_em->flush();
44+
45+
$uow = $this->_em->getUnitOfWork();
46+
$uow->computeChangeSets();
47+
48+
self::assertFalse(
49+
$uow->isScheduledForUpdate($entity),
50+
'Entity should not be scheduled for update after a generated string field was refreshed from the DB',
51+
);
52+
}
53+
54+
public function testGeneratedFieldShouldNotBeDetectedAsChangeAfterUpdate(): void
55+
{
56+
$entity = new GH12017Entity();
57+
58+
$this->_em->persist($entity);
59+
$this->_em->flush();
60+
$this->_em->clear();
61+
62+
$entity = $this->_em->find(GH12017Entity::class, $entity->id);
63+
$entity->other = 1;
64+
$this->_em->flush();
65+
66+
$uow = $this->_em->getUnitOfWork();
67+
$uow->computeChangeSets();
68+
self::assertFalse(
69+
$uow->isScheduledForUpdate($entity),
70+
'Entity should not be scheduled for update after a generated field was refreshed from the DB',
71+
);
72+
}
73+
}
74+
75+
#[ORM\Entity]
76+
#[ORM\Table(name: 'gh12017')]
77+
class GH12017Entity
78+
{
79+
#[ORM\Id]
80+
#[ORM\GeneratedValue]
81+
#[ORM\Column]
82+
public int|null $id = null;
83+
84+
#[ORM\Column(
85+
type: Types::DATETIME_IMMUTABLE,
86+
nullable: false,
87+
insertable: false,
88+
updatable: false,
89+
options: ['default' => new CurrentTimestamp()],
90+
generated: 'ALWAYS',
91+
)]
92+
public DateTimeImmutable|null $tested = null;
93+
94+
#[ORM\Column(
95+
type: Types::INTEGER,
96+
nullable: false,
97+
options: ['default' => 0],
98+
)]
99+
public int $other = 0;
100+
}
101+
102+
#[ORM\Entity]
103+
#[ORM\Table(name: 'gh12017_string')]
104+
class GH12017EntityWithStringField
105+
{
106+
#[ORM\Id]
107+
#[ORM\GeneratedValue]
108+
#[ORM\Column]
109+
public int|null $id = null;
110+
111+
#[ORM\Column(
112+
type: Types::STRING,
113+
insertable: false,
114+
updatable: false,
115+
options: ['default' => 'generated'],
116+
generated: 'ALWAYS',
117+
)]
118+
public string|null $tested = null;
119+
}

0 commit comments

Comments
 (0)