Skip to content
Merged
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
1 change: 1 addition & 0 deletions src/Symfony/Bridge/Doctrine/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ CHANGELOG

* Deprecate `UniqueEntity::getRequiredOptions()` and `UniqueEntity::getDefaultOption()`
* Use a single table named `_schema_subscriber_check` in schema listeners to detect same database connections
* Add support for `Symfony\Component\Clock\DatePoint` as `DayPointType` and `TimePointType` Doctrine type

7.3
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
namespace Symfony\Bridge\Doctrine\DependencyInjection\CompilerPass;

use Symfony\Bridge\Doctrine\Types\DatePointType;
use Symfony\Bridge\Doctrine\Types\DayPointType;
use Symfony\Bridge\Doctrine\Types\TimePointType;
use Symfony\Component\Clock\DatePoint;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
Expand All @@ -31,6 +33,8 @@
$types = $container->getParameter('doctrine.dbal.connection_factory.types');

$types['date_point'] ??= ['class' => DatePointType::class];
$types['day_point'] ??= ['class' => DayPointType::class];

Check failure on line 36 in src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterDatePointTypePass.php

View workflow job for this annotation

GitHub Actions / Psalm

UndefinedInterfaceMethod

src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterDatePointTypePass.php:36:9: UndefinedInterfaceMethod: Method UnitEnum::offsetSet does not exist (see https://psalm.dev/181)

Check failure on line 36 in src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterDatePointTypePass.php

View workflow job for this annotation

GitHub Actions / Psalm

UndefinedInterfaceMethod

src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterDatePointTypePass.php:36:9: UndefinedInterfaceMethod: Method UnitEnum::offsetGet does not exist (see https://psalm.dev/181)

Check failure on line 36 in src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterDatePointTypePass.php

View workflow job for this annotation

GitHub Actions / Psalm

UndefinedInterfaceMethod

src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterDatePointTypePass.php:36:9: UndefinedInterfaceMethod: Method UnitEnum::offsetSet does not exist (see https://psalm.dev/181)

Check failure on line 36 in src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterDatePointTypePass.php

View workflow job for this annotation

GitHub Actions / Psalm

UndefinedInterfaceMethod

src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterDatePointTypePass.php:36:9: UndefinedInterfaceMethod: Method UnitEnum::offsetGet does not exist (see https://psalm.dev/181)
$types['time_point'] ??= ['class' => TimePointType::class];

Check failure on line 37 in src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterDatePointTypePass.php

View workflow job for this annotation

GitHub Actions / Psalm

UndefinedInterfaceMethod

src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterDatePointTypePass.php:37:9: UndefinedInterfaceMethod: Method UnitEnum::offsetSet does not exist (see https://psalm.dev/181)

Check failure on line 37 in src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterDatePointTypePass.php

View workflow job for this annotation

GitHub Actions / Psalm

UndefinedInterfaceMethod

src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterDatePointTypePass.php:37:9: UndefinedInterfaceMethod: Method UnitEnum::offsetGet does not exist (see https://psalm.dev/181)

Check failure on line 37 in src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterDatePointTypePass.php

View workflow job for this annotation

GitHub Actions / Psalm

UndefinedInterfaceMethod

src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterDatePointTypePass.php:37:9: UndefinedInterfaceMethod: Method UnitEnum::offsetSet does not exist (see https://psalm.dev/181)

Check failure on line 37 in src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterDatePointTypePass.php

View workflow job for this annotation

GitHub Actions / Psalm

UndefinedInterfaceMethod

src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterDatePointTypePass.php:37:9: UndefinedInterfaceMethod: Method UnitEnum::offsetGet does not exist (see https://psalm.dev/181)

$container->setParameter('doctrine.dbal.connection_factory.types', $types);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Doctrine\DependencyInjection\CompilerPass\RegisterDatePointTypePass;
use Symfony\Bridge\Doctrine\Types\DatePointType;
use Symfony\Bridge\Doctrine\Types\DayPointType;
use Symfony\Bridge\Doctrine\Types\TimePointType;
use Symfony\Component\Clock\DatePoint;
use Symfony\Component\DependencyInjection\ContainerBuilder;

Expand All @@ -35,6 +37,8 @@ public function testRegistered()
$expected = [
'foo' => 'bar',
'date_point' => ['class' => DatePointType::class],
'day_point' => ['class' => DayPointType::class],
'time_point' => ['class' => TimePointType::class],
];
$this->assertSame($expected, $container->getParameter('doctrine.dbal.connection_factory.types'));
}
Expand Down
106 changes: 106 additions & 0 deletions src/Symfony/Bridge/Doctrine/Tests/Types/DayPointTypeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bridge\Doctrine\Tests\Types;

use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
use Doctrine\DBAL\Types\Type;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Doctrine\Types\DayPointType;
use Symfony\Component\Clock\DatePoint;

final class DayPointTypeTest extends TestCase
{
private DayPointType $type;

public static function setUpBeforeClass(): void
{
$name = DayPointType::NAME;
if (Type::hasType($name)) {
Type::overrideType($name, DayPointType::class);
} else {
Type::addType($name, DayPointType::class);
}
}

protected function setUp(): void
{
if (!class_exists(DatePoint::class)) {
self::markTestSkipped('The DatePoint class is not available.');
}
$this->type = Type::getType(DayPointType::NAME);
}

public function testDatePointConvertsToDatabaseValue()
{
$datePoint = DatePoint::createFromFormat('!Y-m-d', '2025-03-03');

$expected = $datePoint->format('Y-m-d');
$actual = $this->type->convertToDatabaseValue($datePoint, new PostgreSQLPlatform());

$this->assertSame($expected, $actual);
}

public function testDatePointConvertsToPHPValue()
{
$datePoint = new DatePoint();
$actual = $this->type->convertToPHPValue($datePoint, self::getSqlitePlatform());

$this->assertSame($datePoint, $actual);
}

public function testNullConvertsToPHPValue()
{
$actual = $this->type->convertToPHPValue(null, self::getSqlitePlatform());

$this->assertNull($actual);
}

public function testDateTimeImmutableConvertsToPHPValue()
{
$format = 'Y-m-d H:i:s.u';
$date = '2025-03-03';
$dateTime = \DateTimeImmutable::createFromFormat('!Y-m-d', $date);
$actual = $this->type->convertToPHPValue($dateTime, self::getSqlitePlatform());
$expected = DatePoint::createFromFormat('!Y-m-d', $date);

$this->assertInstanceOf(DatePoint::class, $actual);
$this->assertSame($expected->format($format), $actual->format($format));
}

public function testDatabaseValueConvertsToPHPValue()
{
$format = 'Y-m-d H:i:s.u';
$date = '2025-03-03';
$actual = $this->type->convertToPHPValue($date, new PostgreSQLPlatform());
$expected = DatePoint::createFromFormat('!Y-m-d', $date);

$this->assertInstanceOf(DatePoint::class, $actual);
$this->assertSame($expected->format($format), $actual->format($format));
}

public function testGetName()
{
$this->assertSame('day_point', $this->type->getName());
}

private static function getSqlitePlatform(): AbstractPlatform
{
if (interface_exists(Exception::class)) {
// DBAL 4+
return new \Doctrine\DBAL\Platforms\SQLitePlatform();
}

return new \Doctrine\DBAL\Platforms\SqlitePlatform();
}
}
106 changes: 106 additions & 0 deletions src/Symfony/Bridge/Doctrine/Tests/Types/TimePointTypeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bridge\Doctrine\Tests\Types;

use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
use Doctrine\DBAL\Types\Type;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Doctrine\Types\TimePointType;
use Symfony\Component\Clock\DatePoint;

final class TimePointTypeTest extends TestCase
{
private TimePointType $type;

public static function setUpBeforeClass(): void
{
$name = TimePointType::NAME;
if (Type::hasType($name)) {
Type::overrideType($name, TimePointType::class);
} else {
Type::addType($name, TimePointType::class);
}
}

protected function setUp(): void
{
if (!class_exists(DatePoint::class)) {
self::markTestSkipped('The DatePoint class is not available.');
}
$this->type = Type::getType(TimePointType::NAME);
}

public function testDatePointConvertsToDatabaseValue()
{
$datePoint = DatePoint::createFromFormat('!H:i:s', '05:10:15');

$expected = $datePoint->format('H:i:s');
$actual = $this->type->convertToDatabaseValue($datePoint, new PostgreSQLPlatform());

$this->assertSame($expected, $actual);
}

public function testDatePointConvertsToPHPValue()
{
$datePoint = new DatePoint();
$actual = $this->type->convertToPHPValue($datePoint, self::getSqlitePlatform());

$this->assertSame($datePoint, $actual);
}

public function testNullConvertsToPHPValue()
{
$actual = $this->type->convertToPHPValue(null, self::getSqlitePlatform());

$this->assertNull($actual);
}

public function testDateTimeImmutableConvertsToPHPValue()
{
$format = 'Y-m-d H:i:s.u';
$time = '05:10:15';
$dateTime = \DateTimeImmutable::createFromFormat('!H:i:s', $time);
$actual = $this->type->convertToPHPValue($dateTime, self::getSqlitePlatform());
$expected = DatePoint::createFromFormat('!H:i:s', $time);

$this->assertInstanceOf(DatePoint::class, $actual);
$this->assertSame($expected->format($format), $actual->format($format));
}

public function testDatabaseValueConvertsToPHPValue()
{
$format = 'Y-m-d H:i:s.u';
$time = '05:10:15';
$actual = $this->type->convertToPHPValue($time, new PostgreSQLPlatform());
$expected = DatePoint::createFromFormat('!H:i:s', $time);

$this->assertInstanceOf(DatePoint::class, $actual);
$this->assertSame($expected->format($format), $actual->format($format));
}

public function testGetName()
{
$this->assertSame('time_point', $this->type->getName());
}

private static function getSqlitePlatform(): AbstractPlatform
{
if (interface_exists(Exception::class)) {
// DBAL 4+
return new \Doctrine\DBAL\Platforms\SQLitePlatform();
}

return new \Doctrine\DBAL\Platforms\SqlitePlatform();
}
}
40 changes: 40 additions & 0 deletions src/Symfony/Bridge/Doctrine/Types/DayPointType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bridge\Doctrine\Types;

use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\DateImmutableType;
use Symfony\Component\Clock\DatePoint;

final class DayPointType extends DateImmutableType
{
public const NAME = 'day_point';

/**
* @return ($value is null ? null : DatePoint)
*/
public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?DatePoint
{
if (null === $value || $value instanceof DatePoint) {
return $value;
}

$value = parent::convertToPHPValue($value, $platform);

return DatePoint::createFromInterface($value);
}

public function getName(): string
{
return self::NAME;
}
}
40 changes: 40 additions & 0 deletions src/Symfony/Bridge/Doctrine/Types/TimePointType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bridge\Doctrine\Types;

use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\TimeImmutableType;
use Symfony\Component\Clock\DatePoint;

final class TimePointType extends TimeImmutableType
{
public const NAME = 'time_point';

/**
* @return ($value is null ? null : DatePoint)
*/
public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?DatePoint
{
if (null === $value || $value instanceof DatePoint) {
return $value;
}

$value = parent::convertToPHPValue($value, $platform);

return DatePoint::createFromInterface($value);
}

public function getName(): string
{
return self::NAME;
}
}
Loading