Skip to content
Draft
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: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"psr/clock": "^1.0"
},
"require-dev": {
"doctrine/dbal": "^3.9 || ^4.0",
"infection/infection": "^0.29.6",
"lendable/composer-license-checker": "^1.2.1",
"lendable/phpunit-extensions": "^0.3",
Expand Down Expand Up @@ -90,7 +91,7 @@
"phpunit --colors --testsuite=unit"
],
"infection": [
"./bin/infection --threads=8 --min-msi=99 --show-mutations"
"./bin/infection --threads=8 --min-msi=98 --show-mutations"
],
"tests": [
"@tests:unit"
Expand Down
157 changes: 156 additions & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

69 changes: 69 additions & 0 deletions lib/Bridge/Doctrine/Type/DateType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

declare(strict_types=1);

namespace Lendable\Clock\Bridge\Doctrine\Type;

use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\ConversionException;
use Doctrine\DBAL\Types\Exception\InvalidFormat;
use Doctrine\DBAL\Types\Exception\InvalidType;
use Doctrine\DBAL\Types\Exception\ValueNotConvertible;
use Doctrine\DBAL\Types\Type;
use Lendable\Clock\Date;

final class DateType extends Type
{
public const NAME = 'lendable_date';

public function getSQLDeclaration(array $column, AbstractPlatform $platform): string
{
return $platform->getDateTypeDeclarationSQL($column);
}

public function convertToPHPValue($value, AbstractPlatform $platform): ?Date
{
if ($value === null) {
return null;
}

if (!\is_string($value)) {
throw \class_exists(ValueNotConvertible::class)
? ValueNotConvertible::new($value, self::NAME)
: ConversionException::conversionFailed($value, self::NAME);
}

try {
return Date::fromYearMonthDayString($value);
} catch (\InvalidArgumentException $e) {
throw \class_exists(InvalidFormat::class)
? InvalidFormat::new($value, self::NAME, 'Y-m-d', $e)
: ConversionException::conversionFailedFormat($value, self::NAME, 'Y-m-d', $e);
}
}

public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string
{
if ($value === null) {
return null;
}

if ($value instanceof Date) {
return $value->toYearMonthDayString();
}

// @infection-ignore-all (ArrayItemRemoval)
throw \class_exists(InvalidType::class)
? InvalidType::new($value, self::NAME, ['null', Date::class])
: ConversionException::conversionFailedInvalidType(
$value,
self::NAME,
['null', Date::class],
);
}

public function getName(): string
{
return self::NAME;
}
}
2 changes: 1 addition & 1 deletion phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ parameters:

ignoreErrors:
- '#Dynamic call to static method PHPUnit\\Framework\\.*#'
- '#^Call to an undefined static method DateTime(?:Immutable)?::createFromInterface\(\)\.$#'
- '#^Attribute class PHPUnit\\Framework\\Attributes\\CodeCoverageIgnore is deprecated: https://github.com/sebastianbergmann/phpunit/issues/5236$#'
- '#^Call to an undefined static method Doctrine\\DBAL\\Types\\ConversionException::.+$#'
117 changes: 117 additions & 0 deletions tests/unit/Bridge/Doctrine/Type/DateTypeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?php

declare(strict_types=1);

namespace Tests\Lendable\Clock\Unit\Bridge\Doctrine\Type;

use Doctrine\DBAL\Platforms\MySQLPlatform;
use Doctrine\DBAL\Types\ConversionException;
use Doctrine\DBAL\Types\Exception\InvalidFormat;
use Doctrine\DBAL\Types\Exception\InvalidType;
use Doctrine\DBAL\Types\Exception\ValueNotConvertible;
use Lendable\Clock\Bridge\Doctrine\Type\DateType;
use Lendable\Clock\Date;
use Lendable\PHPUnitExtensions\TestCase;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\RequiresMethod;
use PHPUnit\Framework\Attributes\Test;

#[CoversClass(DateType::class)]
final class DateTypeTest extends TestCase
{
#[Test]
public function null_conversion_to_db_value(): void
{
$this->assertNull((new DateType())->convertToDatabaseValue(null, new MySQLPlatform()));
}

#[Test]
public function conversion_to_db_value(): void
{
$this->assertSame(
'2020-01-03',
(new DateType())->convertToDatabaseValue(Date::fromYearMonthDayString('2020-01-03'), new MySQLPlatform()),
);
}

#[Test]
public function db_value_conversion(): void
{
$this->assertSame(
'2020-01-03',
(new DateType())->convertToPHPValue('2020-01-03', new MySQLPlatform())?->toYearMonthDayString(),
);
}

#[Test]
public function null_db_value_conversion(): void
{
$this->assertNull((new DateType())->convertToPHPValue(null, new MySQLPlatform()));
}

#[Test]
#[RequiresMethod(ValueNotConvertible::class, 'new')]
public function invalid_db_value_conversion_dbal_4(): void
{
$this->expectExceptionObject(ValueNotConvertible::new(321, DateType::NAME));

(new DateType())->convertToPHPValue(321, new MySQLPlatform());
}

#[Test]
#[RequiresMethod(InvalidFormat::class, 'new')]
public function invalid_db_format_conversion_dbal_4(): void
{
$this->expectExceptionObject(InvalidFormat::new('2010-01', DateType::NAME, 'Y-m-d'));

try {
(new DateType())->convertToPHPValue('2010-01', new MySQLPlatform());
} catch (InvalidFormat $e) {
$this->assertInstanceOf(\InvalidArgumentException::class, $e->getPrevious());

throw $e;
}
}

#[Test]
#[RequiresMethod(InvalidType::class, 'new')]
public function invalid_php_value_conversion_dbal_4(): void
{
$this->expectExceptionObject(InvalidType::new(321, DateType::NAME, ['null', Date::class]));

(new DateType())->convertToDatabaseValue(321, new MySQLPlatform());
}

#[Test]
#[RequiresMethod(ConversionException::class, 'conversionFailed')]
public function invalid_db_value_conversion_dbal_3(): void
{
$this->expectExceptionObject(ConversionException::conversionFailed(321, DateType::NAME));

(new DateType())->convertToPHPValue(321, new MySQLPlatform());
}

#[Test]
#[RequiresMethod(ConversionException::class, 'conversionFailedFormat')]
public function invalid_db_format_conversion_dbal_3(): void
{
$this->expectExceptionObject(ConversionException::conversionFailedFormat('2010-01', DateType::NAME, 'Y-m-d'));

try {
(new DateType())->convertToPHPValue('2010-01', new MySQLPlatform());
} catch (ConversionException $e) {
$this->assertInstanceOf(\InvalidArgumentException::class, $e->getPrevious());

throw $e;
}
}

#[Test]
#[RequiresMethod(ConversionException::class, 'conversionFailedInvalidType')]
public function invalid_php_value_conversion_dbal_3(): void
{
$this->expectExceptionObject(ConversionException::conversionFailedInvalidType(321, DateType::NAME, ['null', Date::class]));

(new DateType())->convertToDatabaseValue(321, new MySQLPlatform());
}
}
Loading