diff --git a/src/Symfony/Bridge/Doctrine/CHANGELOG.md b/src/Symfony/Bridge/Doctrine/CHANGELOG.md index 961a0965d3431..ad412b85c1a04 100644 --- a/src/Symfony/Bridge/Doctrine/CHANGELOG.md +++ b/src/Symfony/Bridge/Doctrine/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +7.4 +--- + +* Add support for `Symfony\Component\Clock\DatePoint` as `DatePointDateType` Doctrine type + 7.3 --- diff --git a/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterDatePointTypePass.php b/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterDatePointTypePass.php index 68474d94f2048..3d655c108bc5d 100644 --- a/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterDatePointTypePass.php +++ b/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterDatePointTypePass.php @@ -12,6 +12,7 @@ namespace Symfony\Bridge\Doctrine\DependencyInjection\CompilerPass; use Symfony\Bridge\Doctrine\Types\DatePointType; +use Symfony\Bridge\Doctrine\Types\DatePointDateType; use Symfony\Component\Clock\DatePoint; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -30,7 +31,10 @@ public function process(ContainerBuilder $container): void $types = $container->getParameter('doctrine.dbal.connection_factory.types'); - $types['date_point'] ??= ['class' => DatePointType::class]; + if (is_array($types)) { + $types['date_point'] ??= ['class' => DatePointType::class]; + $types['date_point_date'] ??= ['class' => DatePointDateType::class]; + } $container->setParameter('doctrine.dbal.connection_factory.types', $types); } diff --git a/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/CompilerPass/RegisterDatePointTypePassTest.php b/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/CompilerPass/RegisterDatePointTypePassTest.php index 3ded48d86cdd3..d302309422abe 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/CompilerPass/RegisterDatePointTypePassTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/CompilerPass/RegisterDatePointTypePassTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Bridge\Doctrine\DependencyInjection\CompilerPass\RegisterDatePointTypePass; use Symfony\Bridge\Doctrine\Types\DatePointType; +use Symfony\Bridge\Doctrine\Types\DatePointDateType; use Symfony\Component\Clock\DatePoint; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -35,6 +36,7 @@ public function testRegistered() $expected = [ 'foo' => 'bar', 'date_point' => ['class' => DatePointType::class], + 'date_point_date' => ['class' => DatePointDateType::class], ]; $this->assertSame($expected, $container->getParameter('doctrine.dbal.connection_factory.types')); } diff --git a/src/Symfony/Bridge/Doctrine/Tests/Types/DatePointDateTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Types/DatePointDateTypeTest.php new file mode 100644 index 0000000000000..a78c79782f7a6 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/Types/DatePointDateTypeTest.php @@ -0,0 +1,106 @@ + + * + * 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\DatePointDateType; +use Symfony\Component\Clock\DatePoint; + +final class DatePointDateTypeTest extends TestCase +{ + private DatePointDateType $type; + + public static function setUpBeforeClass(): void + { + $name = DatePointDateType::NAME; + if (Type::hasType($name)) { + Type::overrideType($name, DatePointDateType::class); + } else { + Type::addType($name, DatePointDateType::class); + } + } + + protected function setUp(): void + { + if (!class_exists(DatePoint::class)) { + self::markTestSkipped('The DatePoint class is not available.'); + } + $this->type = Type::getType(DatePointDateType::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('date_point_date', $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(); + } +} diff --git a/src/Symfony/Bridge/Doctrine/Types/DatePointDateType.php b/src/Symfony/Bridge/Doctrine/Types/DatePointDateType.php new file mode 100644 index 0000000000000..0754ce27a0b07 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Types/DatePointDateType.php @@ -0,0 +1,40 @@ + + * + * 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 DatePointDateType extends DateImmutableType +{ + public const NAME = 'date_point_date'; + + /** + * @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; + } +}