Skip to content

Commit

Permalink
ChronosDate does not implement DateTimeInterface #9967
Browse files Browse the repository at this point in the history
For coherence, we also update Chronos and cover everything with tests
since we have more code than before.
  • Loading branch information
PowerKiKi committed Nov 15, 2023
1 parent 9aff229 commit 861d055
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 3 deletions.
27 changes: 26 additions & 1 deletion src/DBAL/Types/ChronosType.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,44 @@
use Cake\Chronos\Chronos;
use DateTimeInterface;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\ConversionException;
use Doctrine\DBAL\Types\DateTimeType;

final class ChronosType extends DateTimeType
{
/**
* @param null|DateTimeInterface|int|string $value
* @return ($value is null ? null : string)
*/
public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform): ?string
{
if ($value === null) {
return $value;
}

if ($value instanceof DateTimeInterface) {
return $value->format($platform->getDateTimeFormatString());
}

throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'Chronos']);
}

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

if (!is_string($value) && !$value instanceof DateTimeInterface) {
throw ConversionException::conversionFailedFormat(
$value,
$this->getName(),
$platform->getDateTimeFormatString(),
);
}

$val = new Chronos($value);

return $val;
Expand Down
28 changes: 26 additions & 2 deletions src/DBAL/Types/DateType.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,44 @@
namespace Ecodev\Felix\DBAL\Types;

use Cake\Chronos\ChronosDate;
use DateTimeInterface;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\ConversionException;

final class DateType extends \Doctrine\DBAL\Types\DateType
{
/**
* @param null|ChronosDate|DateTimeInterface|string $value
* @return ($value is null ? null : string)
*/
public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform): ?string
{
if ($value === null) {
return $value;
}

if ($value instanceof ChronosDate) {
return $value->format($platform->getDateFormatString());
}

throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'ChronosDate']);
}

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

if (!is_string($value)) {
throw ConversionException::conversionFailedFormat(
$value,
$this->getName(),
$platform->getDateFormatString(),
);
}

$val = new ChronosDate($value);

return $val;
Expand Down
71 changes: 71 additions & 0 deletions tests/DBAL/Types/ChronosTypeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

declare(strict_types=1);

namespace EcodevTests\Felix\DBAL\Types;

use Cake\Chronos\Chronos;
use DateTimeImmutable;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\MySQLPlatform;
use Doctrine\DBAL\Types\ConversionException;
use Ecodev\Felix\DBAL\Types\ChronosType;
use PHPUnit\Framework\TestCase;

class ChronosTypeTest extends TestCase
{
private ChronosType $type;

private AbstractPlatform $platform;

protected function setUp(): void
{
$this->type = new ChronosType();
$this->platform = new MySQLPlatform();
}

public function testConvertToDatabaseValue(): void
{
self::assertSame('DATETIME', $this->type->getSqlDeclaration(['foo'], $this->platform));
self::assertFalse($this->type->requiresSQLCommentHint($this->platform));

$actual = $this->type->convertToDatabaseValue(new Chronos('2016-01-01 15:58:59'), $this->platform);
self::assertSame('2016-01-01 15:58:59', $actual, 'support Chronos');

$actual = $this->type->convertToDatabaseValue(new DateTimeImmutable('2016-01-01 15:58:59'), $this->platform);
self::assertSame('2016-01-01 15:58:59', $actual, 'support DateTimeImmutable');

self::assertNull($this->type->convertToDatabaseValue(null, $this->platform), 'support null values');
}

public function testConvertToPHPValue(): void
{
$actualPhp = $this->type->convertToPHPValue('2016-01-01 15:58:59', $this->platform);
self::assertInstanceOf(Chronos::class, $actualPhp);
self::assertSame('2016-01-01 15:58:59', $actualPhp->__toString(), 'support string');

$actualPhp = $this->type->convertToPHPValue(new Chronos('2016-01-01 15:58:59'), $this->platform);
self::assertInstanceOf(Chronos::class, $actualPhp);
self::assertSame('2016-01-01 15:58:59', $actualPhp->__toString(), 'support Chronos');

$actualPhp = $this->type->convertToPHPValue(new DateTimeImmutable('2016-01-01 15:58:59'), $this->platform);
self::assertInstanceOf(Chronos::class, $actualPhp);
self::assertSame('2016-01-01 15:58:59', $actualPhp->__toString(), 'support DateTimeImmutable');

self::assertNull($this->type->convertToPHPValue(null, $this->platform), 'support null values');
}

public function testConvertToPHPValueThrowsWithInvalidValue(): void
{
$this->expectException(ConversionException::class);

$this->type->convertToPHPValue(123, $this->platform);
}

public function testConvertToDatabaseValueThrowsWithInvalidValue(): void
{
$this->expectException(ConversionException::class);

$this->type->convertToDatabaseValue(123, $this->platform);
}
}
63 changes: 63 additions & 0 deletions tests/DBAL/Types/DateTypeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

declare(strict_types=1);

namespace EcodevTests\Felix\DBAL\Types;

use Cake\Chronos\ChronosDate;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\MySQLPlatform;
use Doctrine\DBAL\Types\ConversionException;
use Ecodev\Felix\DBAL\Types\DateType;
use PHPUnit\Framework\TestCase;

class DateTypeTest extends TestCase
{
private DateType $type;

private AbstractPlatform $platform;

protected function setUp(): void
{
$this->type = new DateType();
$this->platform = new MySQLPlatform();
}

public function testConvertToDatabaseValue(): void
{
self::assertSame('DATE', $this->type->getSqlDeclaration(['foo'], $this->platform));
self::assertFalse($this->type->requiresSQLCommentHint($this->platform));

$actual = $this->type->convertToDatabaseValue(new ChronosDate('2016-01-01'), $this->platform);
self::assertSame('2016-01-01', $actual, 'support Chronos');

self::assertNull($this->type->convertToDatabaseValue(null, $this->platform), 'support null values');
}

public function testConvertToPHPValue(): void
{
$actualPhp = $this->type->convertToPHPValue('2022-12-31', $this->platform);
self::assertInstanceOf(ChronosDate::class, $actualPhp);
self::assertSame('2022-12-31', $actualPhp->__toString(), 'support string');

$actualPhp = $this->type->convertToPHPValue(new ChronosDate('2022-12-31'), $this->platform);
self::assertInstanceOf(ChronosDate::class, $actualPhp);
self::assertSame('2022-12-31', $actualPhp->__toString(), 'support ChronosDate');

self::assertNull($this->type->convertToPHPValue(null, $this->platform), 'support null values');
}

public function testConvertToPHPValueThrowsWithInvalidValue(): void
{
$this->expectException(ConversionException::class);

$this->type->convertToPHPValue(123, $this->platform);
}

public function testConvertToDatabaseValueThrowsWithInvalidValue(): void
{
$this->expectException(ConversionException::class);

$this->type->convertToDatabaseValue(123, $this->platform);
}
}

0 comments on commit 861d055

Please sign in to comment.