Skip to content

Commit

Permalink
Add weekday value object (#55)
Browse files Browse the repository at this point in the history
Co-authored-by: Christian Kolb <[email protected]>
  • Loading branch information
christian-kolb and Christian Kolb authored Jun 9, 2024
1 parent d9f1a50 commit 0df267f
Show file tree
Hide file tree
Showing 49 changed files with 2,098 additions and 35 deletions.
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ php-8.2-tests:
php-8.3-tests:
docker-compose run --rm php-8.3 ./vendor/bin/phpunit

## php-tests-coverage Run the tests for default PHP version and create coverage report.
.PHONY: php-tests-coverage
php-tests-coverage: php-8.3-tests-html-coverage

## php-8.2-tests-html-coverage Run the tests with PHP 8.2 including coverage report as HTML.
.PHONY: php-8.2-tests-html-coverage
php-8.2-tests-html-coverage:
Expand Down
10 changes: 10 additions & 0 deletions infection.json5
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@
"DigitalCraftsman\\DateTimePrecision\\Moment",
]
},
"IncrementInteger": {
"ignore": [
"DigitalCraftsman\\DateTimePrecision\\Doctrine\\WeekdaysType::convertToPHPValue"
]
},
"DecrementInteger": {
"ignore": [
"DigitalCraftsman\\DateTimePrecision\\Doctrine\\WeekdaysType::convertToPHPValue"
]
}
},
"minMsi": 100,
"minCoveredMsi": 100
Expand Down
6 changes: 5 additions & 1 deletion src/Date.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace DigitalCraftsman\DateTimePrecision;

/** @psalm-immutable */
final readonly class Date implements \Stringable
{
private const DATE_FORMAT = 'Y-m-d';
Expand Down Expand Up @@ -152,6 +151,11 @@ public function datesUntil(
return $dates;
}

public function weekday(): Weekday
{
return Weekday::fromDateTime($this->toDateTimeImmutable());
}

// Mutations

public function format(string $format): string
Expand Down
4 changes: 4 additions & 0 deletions src/DependencyInjection/DoctrineTypeRegisterCompilerPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
use DigitalCraftsman\DateTimePrecision\Doctrine\MomentType;
use DigitalCraftsman\DateTimePrecision\Doctrine\MonthType;
use DigitalCraftsman\DateTimePrecision\Doctrine\TimeType;
use DigitalCraftsman\DateTimePrecision\Doctrine\WeekdaysType;
use DigitalCraftsman\DateTimePrecision\Doctrine\WeekdayType;
use DigitalCraftsman\DateTimePrecision\Doctrine\YearType;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
Expand All @@ -23,6 +25,8 @@ public function process(ContainerBuilder $container): void

$typeDefinitions['dtp_moment'] = ['class' => MomentType::class];
$typeDefinitions['dtp_time'] = ['class' => TimeType::class];
$typeDefinitions['dtp_weekday'] = ['class' => WeekdayType::class];
$typeDefinitions['dtp_weekdays'] = ['class' => WeekdaysType::class];
$typeDefinitions['dtp_date'] = ['class' => DateType::class];
$typeDefinitions['dtp_month'] = ['class' => MonthType::class];
$typeDefinitions['dtp_year'] = ['class' => YearType::class];
Expand Down
50 changes: 50 additions & 0 deletions src/Doctrine/WeekdayType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

declare(strict_types=1);

namespace DigitalCraftsman\DateTimePrecision\Doctrine;

use DigitalCraftsman\DateTimePrecision\Weekday;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\StringType;

final class WeekdayType extends StringType
{
/** @codeCoverageIgnore */
public function getName(): string
{
return 'dtp_weekday';
}

/** @param Weekday|null $value */
public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string
{
if ($value === null) {
return null;
}

return $value->value;
}

/** @param string|null $value */
public function convertToPHPValue($value, AbstractPlatform $platform): ?Weekday
{
return $value === null
? null
: Weekday::from($value);
}

/** @codeCoverageIgnore */
public function getSQLDeclaration(array $column, AbstractPlatform $platform): string
{
$column['length'] = 9;

return $platform->getStringTypeDeclarationSQL($column);
}

/** @codeCoverageIgnore */
public function requiresSQLCommentHint(AbstractPlatform $platform): bool
{
return true;
}
}
56 changes: 56 additions & 0 deletions src/Doctrine/WeekdaysType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

declare(strict_types=1);

namespace DigitalCraftsman\DateTimePrecision\Doctrine;

use DigitalCraftsman\DateTimePrecision\Weekdays;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\JsonType;

final class WeekdaysType extends JsonType
{
/** @codeCoverageIgnore */
public function getName(): string
{
return 'dtp_weekdays';
}

/** @param Weekdays|null $value */
public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string
{
if ($value === null) {
return null;
}

$array = $value->normalize();

return json_encode($array, JSON_THROW_ON_ERROR);
}

/** @param string|null $value */
public function convertToPHPValue($value, AbstractPlatform $platform): ?Weekdays
{
if ($value === null) {
return null;
}

$array = json_decode($value, true, 512, JSON_THROW_ON_ERROR);

return Weekdays::denormalize($array);
}

/** @codeCoverageIgnore */
public function getSQLDeclaration(array $column, AbstractPlatform $platform): string
{
$column['jsonb'] = true;

return $platform->getJsonTypeDeclarationSQL($column);
}

/** @codeCoverageIgnore */
public function requiresSQLCommentHint(AbstractPlatform $platform): bool
{
return true;
}
}
42 changes: 32 additions & 10 deletions src/Moment.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,18 @@ public function timeInTimeZone(\DateTimeZone $timeZone): Time
->time();
}

public function weekday(): Weekday
{
return Weekday::fromDateTime($this->dateTime);
}

public function weekdayInTimeZone(\DateTimeZone $timeZone): Weekday
{
return $this
->toTimeZone($timeZone)
->weekday();
}

public function month(): Month
{
return Month::fromDateTime($this->dateTime);
Expand Down Expand Up @@ -98,11 +110,12 @@ public function isEqualTo(self $moment): bool
}

public function isEqualToInTimeZone(
Time | Date | Month | Year $comparator,
Time | Weekday | Date | Month | Year $comparator,
\DateTimeZone $timeZone,
): bool {
return match (true) {
$comparator instanceof Time => $this->timeInTimeZone($timeZone)->isEqualTo($comparator),
$comparator instanceof Weekday => $this->weekdayInTimeZone($timeZone)->isEqualTo($comparator),
$comparator instanceof Date => $this->dateInTimeZone($timeZone)->isEqualTo($comparator),
$comparator instanceof Month => $this->monthInTimeZone($timeZone)->isEqualTo($comparator),
$comparator instanceof Year => $this->yearInTimeZone($timeZone)->isEqualTo($comparator),
Expand All @@ -115,11 +128,12 @@ public function isNotEqualTo(self $moment): bool
}

public function isNotEqualToInTimeZone(
Time | Date | Month | Year $comparator,
Time | Weekday | Date | Month | Year $comparator,
\DateTimeZone $timeZone,
): bool {
return match (true) {
$comparator instanceof Time => $this->timeInTimeZone($timeZone)->isNotEqualTo($comparator),
$comparator instanceof Weekday => $this->weekdayInTimeZone($timeZone)->isNotEqualTo($comparator),
$comparator instanceof Date => $this->dateInTimeZone($timeZone)->isNotEqualTo($comparator),
$comparator instanceof Month => $this->monthInTimeZone($timeZone)->isNotEqualTo($comparator),
$comparator instanceof Year => $this->yearInTimeZone($timeZone)->isNotEqualTo($comparator),
Expand All @@ -132,11 +146,12 @@ public function isAfter(self $moment): bool
}

public function isAfterInTimeZone(
Time | Date | Month | Year $comparator,
Time | Weekday | Date | Month | Year $comparator,
\DateTimeZone $timeZone,
): bool {
return match (true) {
$comparator instanceof Time => $this->timeInTimeZone($timeZone)->isAfter($comparator),
$comparator instanceof Weekday => $this->weekdayInTimeZone($timeZone)->isAfter($comparator),
$comparator instanceof Date => $this->dateInTimeZone($timeZone)->isAfter($comparator),
$comparator instanceof Month => $this->monthInTimeZone($timeZone)->isAfter($comparator),
$comparator instanceof Year => $this->yearInTimeZone($timeZone)->isAfter($comparator),
Expand All @@ -149,11 +164,12 @@ public function isNotAfter(self $moment): bool
}

public function isNotAfterInTimeZone(
Time | Date | Month | Year $comparator,
Time | Weekday | Date | Month | Year $comparator,
\DateTimeZone $timeZone,
): bool {
return match (true) {
$comparator instanceof Time => $this->timeInTimeZone($timeZone)->isNotAfter($comparator),
$comparator instanceof Weekday => $this->weekdayInTimeZone($timeZone)->isNotAfter($comparator),
$comparator instanceof Date => $this->dateInTimeZone($timeZone)->isNotAfter($comparator),
$comparator instanceof Month => $this->monthInTimeZone($timeZone)->isNotAfter($comparator),
$comparator instanceof Year => $this->yearInTimeZone($timeZone)->isNotAfter($comparator),
Expand All @@ -166,11 +182,12 @@ public function isAfterOrEqualTo(self $moment): bool
}

public function isAfterOrEqualToInTimeZone(
Time | Date | Month | Year $comparator,
Time | Weekday | Date | Month | Year $comparator,
\DateTimeZone $timeZone,
): bool {
return match (true) {
$comparator instanceof Time => $this->timeInTimeZone($timeZone)->isAfterOrEqualTo($comparator),
$comparator instanceof Weekday => $this->weekdayInTimeZone($timeZone)->isAfterOrEqualTo($comparator),
$comparator instanceof Date => $this->dateInTimeZone($timeZone)->isAfterOrEqualTo($comparator),
$comparator instanceof Month => $this->monthInTimeZone($timeZone)->isAfterOrEqualTo($comparator),
$comparator instanceof Year => $this->yearInTimeZone($timeZone)->isAfterOrEqualTo($comparator),
Expand All @@ -183,11 +200,12 @@ public function isNotAfterOrEqualTo(self $moment): bool
}

public function isNotAfterOrEqualToInTimeZone(
Time | Date | Month | Year $comparator,
Time | Weekday | Date | Month | Year $comparator,
\DateTimeZone $timeZone,
): bool {
return match (true) {
$comparator instanceof Time => $this->timeInTimeZone($timeZone)->isNotAfterOrEqualTo($comparator),
$comparator instanceof Weekday => $this->weekdayInTimeZone($timeZone)->isNotAfterOrEqualTo($comparator),
$comparator instanceof Date => $this->dateInTimeZone($timeZone)->isNotAfterOrEqualTo($comparator),
$comparator instanceof Month => $this->monthInTimeZone($timeZone)->isNotAfterOrEqualTo($comparator),
$comparator instanceof Year => $this->yearInTimeZone($timeZone)->isNotAfterOrEqualTo($comparator),
Expand All @@ -200,11 +218,12 @@ public function isBeforeOrEqualTo(self $moment): bool
}

public function isBeforeOrEqualToInTimeZone(
Time | Date | Month | Year $comparator,
Time | Weekday | Date | Month | Year $comparator,
\DateTimeZone $timeZone,
): bool {
return match (true) {
$comparator instanceof Time => $this->timeInTimeZone($timeZone)->isBeforeOrEqualTo($comparator),
$comparator instanceof Weekday => $this->weekdayInTimeZone($timeZone)->isBeforeOrEqualTo($comparator),
$comparator instanceof Date => $this->dateInTimeZone($timeZone)->isBeforeOrEqualTo($comparator),
$comparator instanceof Month => $this->monthInTimeZone($timeZone)->isBeforeOrEqualTo($comparator),
$comparator instanceof Year => $this->yearInTimeZone($timeZone)->isBeforeOrEqualTo($comparator),
Expand All @@ -217,11 +236,12 @@ public function isNotBeforeOrEqualTo(self $moment): bool
}

public function isNotBeforeOrEqualToInTimeZone(
Time | Date | Month | Year $comparator,
Time | Weekday | Date | Month | Year $comparator,
\DateTimeZone $timeZone,
): bool {
return match (true) {
$comparator instanceof Time => $this->timeInTimeZone($timeZone)->isNotBeforeOrEqualTo($comparator),
$comparator instanceof Weekday => $this->weekdayInTimeZone($timeZone)->isNotBeforeOrEqualTo($comparator),
$comparator instanceof Date => $this->dateInTimeZone($timeZone)->isNotBeforeOrEqualTo($comparator),
$comparator instanceof Month => $this->monthInTimeZone($timeZone)->isNotBeforeOrEqualTo($comparator),
$comparator instanceof Year => $this->yearInTimeZone($timeZone)->isNotBeforeOrEqualTo($comparator),
Expand All @@ -235,11 +255,12 @@ public function isBefore(
}

public function isBeforeInTimeZone(
Time | Date | Month | Year $comparator,
Time | Weekday | Date | Month | Year $comparator,
\DateTimeZone $timeZone,
): bool {
return match (true) {
$comparator instanceof Time => $this->timeInTimeZone($timeZone)->isBefore($comparator),
$comparator instanceof Weekday => $this->weekdayInTimeZone($timeZone)->isBefore($comparator),
$comparator instanceof Date => $this->dateInTimeZone($timeZone)->isBefore($comparator),
$comparator instanceof Month => $this->monthInTimeZone($timeZone)->isBefore($comparator),
$comparator instanceof Year => $this->yearInTimeZone($timeZone)->isBefore($comparator),
Expand All @@ -252,11 +273,12 @@ public function isNotBefore(self $moment): bool
}

public function isNotBeforeInTimeZone(
Time | Date | Month | Year $comparator,
Time | Weekday | Date | Month | Year $comparator,
\DateTimeZone $timeZone,
): bool {
return match (true) {
$comparator instanceof Time => $this->timeInTimeZone($timeZone)->isNotBefore($comparator),
$comparator instanceof Weekday => $this->weekdayInTimeZone($timeZone)->isNotBefore($comparator),
$comparator instanceof Date => $this->dateInTimeZone($timeZone)->isNotBefore($comparator),
$comparator instanceof Month => $this->monthInTimeZone($timeZone)->isNotBefore($comparator),
$comparator instanceof Year => $this->yearInTimeZone($timeZone)->isNotBefore($comparator),
Expand Down
1 change: 0 additions & 1 deletion src/Month.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace DigitalCraftsman\DateTimePrecision;

/** @psalm-immutable */
final readonly class Month implements \Stringable
{
private const MONTH_FORMAT = 'Y-m';
Expand Down
6 changes: 6 additions & 0 deletions src/Resources/config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ services:
DigitalCraftsman\DateTimePrecision\Serializer\TimeNormalizer:
tags: [ { name: 'serializer.normalizer' } ]

DigitalCraftsman\DateTimePrecision\Serializer\WeekdayNormalizer:
tags: [ { name: 'serializer.normalizer' } ]

DigitalCraftsman\DateTimePrecision\Serializer\WeekdaysNormalizer:
tags: [ { name: 'serializer.normalizer' } ]

DigitalCraftsman\DateTimePrecision\Serializer\DateNormalizer:
tags: [ { name: 'serializer.normalizer' } ]

Expand Down
Loading

0 comments on commit 0df267f

Please sign in to comment.