Skip to content
Open
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
3 changes: 3 additions & 0 deletions src/Persisters/Entity/BasicEntityPersister.php
Original file line number Diff line number Diff line change
Expand Up @@ -288,11 +288,14 @@ public function executeInserts(): void
protected function assignDefaultVersionAndUpsertableValues(object $entity, array $id): void
{
$values = $this->fetchVersionAndNotUpsertableValues($this->class, $id);
$uow = $this->em->getUnitOfWork();
$oid = spl_object_id($entity);

foreach ($values as $field => $value) {
$value = Type::getType($this->class->fieldMappings[$field]->type)->convertToPHPValue($value, $this->platform);

$this->class->setFieldValue($entity, $field, $value);
$uow->setOriginalEntityProperty($oid, $field, $value);
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/Persisters/Entity/JoinedSubclassPersister.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use function array_keys;
use function array_values;
use function implode;
use function spl_object_id;

/**
* The joined subclass persister maps a single entity instance to several tables in the
Expand Down Expand Up @@ -509,11 +510,14 @@ protected function getInsertColumnList(): array
protected function assignDefaultVersionAndUpsertableValues(object $entity, array $id): void
{
$values = $this->fetchVersionAndNotUpsertableValues($this->getVersionedClassMetadata(), $id);
$uow = $this->em->getUnitOfWork();
$oid = spl_object_id($entity);

foreach ($values as $field => $value) {
$value = Type::getType($this->class->fieldMappings[$field]->type)->convertToPHPValue($value, $this->platform);

$this->class->setFieldValue($entity, $field, $value);
$uow->setOriginalEntityProperty($oid, $field, $value);
}
}

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

declare(strict_types=1);

namespace Doctrine\Tests\ORM\Functional\Ticket;

use DateTimeImmutable;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\DiscriminatorColumn;
use Doctrine\ORM\Mapping\DiscriminatorMap;
use Doctrine\ORM\Mapping\InheritanceType;
use Doctrine\Tests\OrmFunctionalTestCase;

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

$this->createSchemaForModels(GH12017ParentEntity::class, GH12017ChildEntity::class);
}

public function testGeneratedFieldFromChildShouldNotBeDetectedAsChangeAfterInsert(): void
{
$entity = new GH12017ChildEntity();

$this->_em->persist($entity);
$this->_em->flush();

$uow = $this->_em->getUnitOfWork();
$uow->computeChangeSets();

self::assertFalse(
$uow->isScheduledForUpdate($entity),
'Entity should not be scheduled for update after a generated field was refreshed from the DB',
);
}

public function testGeneratedStringFieldShouldNotBeDetectedAsChangeAfterInsert(): void
{
$entity = new GH12017ChildEntity();
$this->_em->persist($entity);
$this->_em->flush();

$uow = $this->_em->getUnitOfWork();
$uow->computeChangeSets();

self::assertFalse(
$uow->isScheduledForUpdate($entity),
'Entity should not be scheduled for update after a generated string field was refreshed from the DB',
);
}

public function testGeneratedFieldShouldNotBeDetectedAsChangeAfterUpdate(): void
{
$entity = new GH12017ChildEntity();
$this->_em->persist($entity);
$this->_em->flush();

$entity->other = 1;
$this->_em->flush();

$uow = $this->_em->getUnitOfWork();
$uow->computeChangeSets();
self::assertFalse(
$uow->isScheduledForUpdate($entity),
'Entity should not be scheduled for update after a generated field was refreshed from the DB',
);
}
}

#[ORM\MappedSuperclass]
#[InheritanceType('JOINED')]
#[DiscriminatorColumn(name: 'discr', type: 'string')]
#[DiscriminatorMap(['child' => GH12017ChildEntity::class])]
#[ORM\Entity]
#[ORM\Table(name: 'gh12017_parent')]
class GH12017ParentEntity
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
public int $id;

#[ORM\Column(
type: Types::INTEGER,
nullable: false,
options: ['default' => 0],
)]
public int $other = 0;
}

#[ORM\Entity]
#[ORM\Table(name: 'gh12017_child')]
class GH12017ChildEntity extends GH12017ParentEntity
{
#[ORM\Column(
type: Types::DATETIME_IMMUTABLE,
insertable: false,
updatable: false,
options: ['default' => 'CURRENT_TIMESTAMP'],
generated: 'ALWAYS',
)]
public DateTimeImmutable|null $tested = null;
}
118 changes: 118 additions & 0 deletions tests/Tests/ORM/Functional/Ticket/GH12017Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\ORM\Functional\Ticket;

use DateTimeImmutable;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Tests\OrmFunctionalTestCase;

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

$this->createSchemaForModels(GH12017Entity::class, GH12017EntityWithStringField::class);
}

public function testGeneratedFieldShouldNotBeDetectedAsChangeAfterFlush(): void
{
$entity = new GH12017Entity();

$this->_em->persist($entity);
$this->_em->flush();

$uow = $this->_em->getUnitOfWork();
$uow->computeChangeSets();

self::assertFalse(
$uow->isScheduledForUpdate($entity),
'Entity should not be scheduled for update after a generated field was refreshed from the DB',
);
}

public function testGeneratedStringFieldShouldNotBeDetectedAsChangeAfterFlush(): void
{
$entity = new GH12017EntityWithStringField();

$this->_em->persist($entity);
$this->_em->flush();

$uow = $this->_em->getUnitOfWork();
$uow->computeChangeSets();

self::assertFalse(
$uow->isScheduledForUpdate($entity),
'Entity should not be scheduled for update after a generated string field was refreshed from the DB',
);
}

public function testGeneratedFieldShouldNotBeDetectedAsChangeAfterUpdate(): void
{
$entity = new GH12017Entity();

$this->_em->persist($entity);
$this->_em->flush();
$this->_em->clear();

$entity = $this->_em->find(GH12017Entity::class, $entity->id);
$entity->other = 1;
$this->_em->flush();

$uow = $this->_em->getUnitOfWork();
$uow->computeChangeSets();
self::assertFalse(
$uow->isScheduledForUpdate($entity),
'Entity should not be scheduled for update after a generated field was refreshed from the DB',
);
}
}

#[ORM\Entity]
#[ORM\Table(name: 'gh12017')]
class GH12017Entity
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
public int|null $id = null;

#[ORM\Column(
type: Types::DATETIME_IMMUTABLE,
nullable: false,
insertable: false,
updatable: false,
options: ['default' => 'CURRENT_TIMESTAMP'],
generated: 'ALWAYS',
)]
public DateTimeImmutable|null $tested = null;

#[ORM\Column(
type: Types::INTEGER,
nullable: false,
options: ['default' => 0],
)]
public int $other = 0;
}

#[ORM\Entity]
#[ORM\Table(name: 'gh12017_string')]
class GH12017EntityWithStringField
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
public int|null $id = null;

#[ORM\Column(
type: Types::STRING,
insertable: false,
updatable: false,
options: ['default' => 'generated'],
generated: 'ALWAYS',
)]
public string|null $tested = null;
}