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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ a release.
## [Unreleased]
### Added
- Support for Symfony 8
- SoftDeleteable: Add support for `date_point` type (#3013)
- Timestampable: Add support for `date_point` type (#3013)

## [3.21.0] - 2025-09-22
### Added
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"phpstan/phpstan-phpunit": "^2.0.3",
"phpunit/phpunit": "^9.6",
"rector/rector": "^2.2.6",
"symfony/clock": "^6.4 || ^7.3 || ^8.0",
"symfony/console": "^5.4 || ^6.4 || ^7.3 || ^8.0",
"symfony/doctrine-bridge": "^5.4 || ^6.4 || ^7.3 || ^8.0",
"symfony/phpunit-bridge": "^6.4 || ^7.3 || ^8.0",
Expand Down
2 changes: 1 addition & 1 deletion src/SoftDeleteable/Mapping/Event/Adapter/ORM.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ private function getRawDateValue($mapping)
return (int) $datetime->format('U');
}

if (in_array($type, ['date_immutable', 'time_immutable', 'datetime_immutable', 'datetimetz_immutable'], true)) {
if (in_array($type, ['date_immutable', 'time_immutable', 'datetime_immutable', 'datetimetz_immutable', 'date_point'], true)) {
return $datetime;
}

Expand Down
1 change: 1 addition & 0 deletions src/SoftDeleteable/Mapping/Validator.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class Validator
'datetimetz',
'datetimetz_immutable',
'timestamp',
'date_point',
];

/**
Expand Down
1 change: 1 addition & 0 deletions src/Timestampable/Mapping/Driver/Attribute.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class Attribute extends AbstractAnnotationDriver
'timestamp',
'vardatetime',
'integer',
'date_point',
];

public function readExtendedMetadata($meta, array &$config)
Expand Down
1 change: 1 addition & 0 deletions src/Timestampable/Mapping/Driver/Xml.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class Xml extends BaseXml
'timestamp',
'vardatetime',
'integer',
'date_point',
];

public function readExtendedMetadata($meta, array &$config)
Expand Down
1 change: 1 addition & 0 deletions src/Timestampable/Mapping/Driver/Yaml.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class Yaml extends File implements Driver
'timestamp',
'vardatetime',
'integer',
'date_point',
];

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Timestampable/Mapping/Event/Adapter/ORM.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ private function getRawDateValue($mapping)
return (int) $datetime->format('U');
}

if (in_array($type, ['date_immutable', 'time_immutable', 'datetime_immutable', 'datetimetz_immutable'], true)) {
if (in_array($type, ['date_immutable', 'time_immutable', 'datetime_immutable', 'datetimetz_immutable', 'date_point'], true)) {
return $datetime;
}

Expand Down
85 changes: 85 additions & 0 deletions tests/Gedmo/SoftDeleteable/DatePointTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

/*
* This file is part of the Doctrine Behavioral Extensions package.
* (c) Gediminas Morkevicius <[email protected]> http://www.gediminasm.org
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Gedmo\Tests\SoftDeleteable;

use Carbon\Doctrine\DateTimeType;
use Doctrine\Common\EventManager;
use Doctrine\DBAL\Types\Type as DoctrineType;
use Doctrine\DBAL\Types\Types;
use Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter;
use Gedmo\SoftDeleteable\SoftDeleteableListener;
use Gedmo\Tests\SoftDeleteable\Fixture\Entity\BookDatePoint;
use Gedmo\Tests\Tool\BaseTestCaseORM;
use Symfony\Component\Clock\DatePoint;

final class DatePointTest extends BaseTestCaseORM
{
private const SOFT_DELETEABLE_FILTER_NAME = 'soft-deleteable';

private SoftDeleteableListener $softDeleteableListener;

protected function setUp(): void
{
parent::setUp();

$evm = new EventManager();
$this->softDeleteableListener = new SoftDeleteableListener();
$evm->addEventSubscriber($this->softDeleteableListener);
$config = $this->getDefaultConfiguration();
$config->addFilter(self::SOFT_DELETEABLE_FILTER_NAME, SoftDeleteableFilter::class);
$this->em = $this->getDefaultMockSqliteEntityManager($evm, $config);
$this->em->getFilters()->enable(self::SOFT_DELETEABLE_FILTER_NAME);

DoctrineType::overrideType(Types::DATETIME_MUTABLE, DateTimeType::class);
}

protected function tearDown(): void
{
parent::tearDown();

DoctrineType::overrideType(Types::DATETIME_MUTABLE, \Doctrine\DBAL\Types\DateTimeType::class);
}

public function testSoftDeleteable(): void
{
$repo = $this->em->getRepository(BookDatePoint::class);

$book0 = new BookDatePoint();
$field = 'title';
$value = 'Title 1';
$book0->setTitle($value);

$this->em->persist($book0);
$this->em->flush();

static::assertNull($book0->getDeletedAt());

$book = $repo->findOneBy([$field => $value]);
$this->em->remove($book);
$this->em->flush();

$book = $repo->findOneBy([$field => $value]);
static::assertNull($book);

// Now we deactivate the filter so we test if the entity appears in the result
$this->em->getFilters()->disable(self::SOFT_DELETEABLE_FILTER_NAME);

$book = $repo->findOneBy([$field => $value]);
static::assertIsObject($book);
static::assertInstanceOf(DatePoint::class, $book->getDeletedAt());
}

protected function getUsedEntityFixtures(): array
{
return [
BookDatePoint::class,
];
}
}
76 changes: 76 additions & 0 deletions tests/Gedmo/SoftDeleteable/Fixture/Entity/BookDatePoint.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Doctrine Behavioral Extensions package.
* (c) Gediminas Morkevicius <[email protected]> http://www.gediminasm.org
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Gedmo\Tests\SoftDeleteable\Fixture\Entity;

use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Clock\DatePoint;

/**
* @ORM\Entity
*
* @Gedmo\SoftDeleteable(fieldName="deletedAt")
*/
#[ORM\Entity]
#[Gedmo\SoftDeleteable(fieldName: 'deletedAt')]
class BookDatePoint
{
/**
* @var int|null
*
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
* @ORM\Column(type="integer")
*/
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'IDENTITY')]
#[ORM\Column(type: Types::INTEGER)]
private $id;

/**
* @ORM\Column(name="title", type="string")
*/
#[ORM\Column(name: 'title', type: Types::STRING)]
private ?string $title = null;

/**
* @ORM\Column(name="deletedAt", type="date_point", nullable=true)
*/
#[ORM\Column(name: 'deletedAt', type: 'date_point', nullable: true)]
private ?DatePoint $deletedAt = null;

public function getId(): ?int
{
return $this->id;
}

public function setTitle(?string $title): void
{
$this->title = $title;
}

public function getTitle(): ?string
{
return $this->title;
}

public function setDeletedAt(?DatePoint $deletedAt): void
{
$this->deletedAt = $deletedAt;
}

public function getDeletedAt(): ?DatePoint
{
return $this->deletedAt;
}
}
135 changes: 135 additions & 0 deletions tests/Gedmo/Timestampable/DatePointTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
<?php

/*
* This file is part of the Doctrine Behavioral Extensions package.
* (c) Gediminas Morkevicius <[email protected]> http://www.gediminasm.org
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Gedmo\Tests\Timestampable;

use Doctrine\Common\EventManager;
use Gedmo\Tests\Timestampable\Fixture\ArticleDatePoint;
use Gedmo\Tests\Timestampable\Fixture\Author;
use Gedmo\Tests\Timestampable\Fixture\CommentDatePoint;
use Gedmo\Tests\Timestampable\Fixture\Type;
use Gedmo\Tests\Tool\BaseTestCaseORM;
use Gedmo\Timestampable\TimestampableListener;
use Symfony\Component\Clock\DatePoint;
use Symfony\Component\Clock\NativeClock;

final class DatePointTest extends BaseTestCaseORM
{
protected function setUp(): void
{
parent::setUp();

$evm = new EventManager();
$evm->addEventSubscriber(new TimestampableListener());

$this->getDefaultMockSqliteEntityManager($evm);
}

protected function tearDown(): void
{
parent::tearDown();
}

public function testShouldHandleStandardBehavior(): void
{
$sport = new ArticleDatePoint();
$sport->setTitle('Sport');
$sport->setBody('Sport article body.');

$sportComment = new CommentDatePoint();
$sportComment->setMessage('hello');
$sportComment->setArticle($sport);
$sportComment->setStatus(0);

$author = new Author();
$author->setName('Original author');
$author->setEmail('[email protected]');

$sport->setAuthor($author);

$this->em->persist($sport);
$this->em->persist($sportComment);
$this->em->flush();

/** @var ArticleDatePoint $sport */
$sport = $this->em->getRepository(ArticleDatePoint::class)->findOneBy(['title' => 'Sport']);
static::assertInstanceOf(DatePoint::class, $su = $sport->getUpdated());

static::assertNull($sport->getContentChanged());
static::assertNull($sport->getPublished());
static::assertNull($sport->getAuthorChanged());

$author = $sport->getAuthor();
$author->setName('New author');
$sport->setAuthor($author);

/** @var CommentDatePoint $sportComment */
$sportComment = $this->em->getRepository(CommentDatePoint::class)->findOneBy(['message' => 'hello']);
static::assertInstanceOf(DatePoint::class, $sc = $sportComment->getModified());

static::assertNotNull($sportComment->getModified());
static::assertNull($sportComment->getClosed());

$sportComment->setStatus(1);
$published = new Type();
$published->setTitle('Published');

$sport->setType($published);
$this->em->persist($sport);
$this->em->persist($published);
$this->em->persist($sportComment);
$this->em->flush();

$sportComment = $this->em->getRepository(CommentDatePoint::class)->findOneBy(['message' => 'hello']);
static::assertInstanceOf(DatePoint::class, $scc = $sportComment->getClosed());
static::assertInstanceOf(DatePoint::class, $sp = $sport->getPublished());
static::assertInstanceOf(DatePoint::class, $sa = $sport->getAuthorChanged());

$sport->setTitle('Updated');
$this->em->persist($sport);
$this->em->persist($published);
$this->em->persist($sportComment);
$this->em->flush();

// prevent "Failed asserting that two variables reference the same object." error, hence compare unix epoch
static::assertEquals($sport->getCreated()->format('U'), $sc->format('U'), 'Date created should remain same after update');
static::assertNotSame($su2 = $sport->getUpdated(), $su, 'Date updated should change after update');
static::assertInstanceOf(DatePoint::class, $sport->getUpdated());
static::assertSame($sport->getPublished(), $sp, 'Date published should remain the same after update');
static::assertNotSame($scc2 = $sport->getContentChanged(), $scc, 'Content must have changed after update');
static::assertInstanceOf(DatePoint::class, $sport->getContentChanged());
static::assertSame($sport->getAuthorChanged(), $sa, 'Author should remain same after update');

$author = $sport->getAuthor();
$author->setName('Third author');
$sport->setAuthor($author);

$sport->setBody('Body updated');
$this->em->persist($sport);
$this->em->persist($published);
$this->em->persist($sportComment);
$this->em->flush();

// prevent "Failed asserting that two variables reference the same object." error, hence compare unix epoch
static::assertEquals($sport->getCreated()->format('U'), $sc->format('U'), 'Date created should remain same after update');
static::assertNotSame($sport->getUpdated(), $su2, 'Date updated should change after update');
static::assertSame($sport->getPublished(), $sp, 'Date published should remain the same after update');
static::assertNotSame($sport->getContentChanged(), $scc2, 'Content must have changed after update');
static::assertNotSame($sport->getAuthorChanged(), $sa, 'Author must have changed after update');
}

protected function getUsedEntityFixtures(): array
{
return [
ArticleDatePoint::class,
CommentDatePoint::class,
Type::class,
];
}
}
Loading