Skip to content

Commit d773a34

Browse files
committed
Improve date time building (allow interfaces)
1 parent a60c4a9 commit d773a34

File tree

4 files changed

+55
-32
lines changed

4 files changed

+55
-32
lines changed

src/Type/Builder/DateTimeFromStringTypeBuilder.php

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,42 @@
44

55
namespace TypeLang\Mapper\Type\Builder;
66

7+
use TypeLang\Mapper\Exception\Definition\InternalTypeException;
78
use TypeLang\Mapper\Type\DateTimeFromStringType;
9+
use TypeLang\Parser\Node\Stmt\NamedTypeNode;
810

911
/**
10-
* @template TDateTime of \DateTime|\DateTimeImmutable = \DateTimeImmutable
12+
* @template TDateTime of \DateTimeInterface = \DateTimeInterface
1113
* @template-extends DateTimeTypeBuilder<TDateTime, TDateTime>
1214
*/
1315
class DateTimeFromStringTypeBuilder extends DateTimeTypeBuilder
1416
{
15-
protected function create(string $class, ?string $format = null): DateTimeFromStringType
17+
/**
18+
* @var array<class-string<\DateTimeInterface>, class-string<\DateTimeInterface>>
19+
*/
20+
private const DATE_INTERFACE_MAPPING = [
21+
\DateTimeInterface::class => \DateTimeImmutable::class,
22+
\Carbon\CarbonInterface::class => \Carbon\CarbonImmutable::class,
23+
];
24+
25+
protected function create(NamedTypeNode $stmt, string $class, ?string $format = null): DateTimeFromStringType
1626
{
27+
if (\interface_exists($class)) {
28+
foreach (self::DATE_INTERFACE_MAPPING as $interface => $impl) {
29+
if (\is_a($interface, $class, true)) {
30+
$class = $impl;
31+
break;
32+
}
33+
}
34+
}
35+
36+
if (!\class_exists($class)) {
37+
throw InternalTypeException::becauseInternalTypeErrorOccurs(
38+
type: $stmt,
39+
message: 'To create a date object from a string, a class must be specified, but {{type}} is not one'
40+
);
41+
}
42+
1743
return new DateTimeFromStringType($class, $format);
1844
}
1945
}

src/Type/Builder/DateTimeToStringTypeBuilder.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55
namespace TypeLang\Mapper\Type\Builder;
66

77
use TypeLang\Mapper\Type\DateTimeToStringType;
8+
use TypeLang\Parser\Node\Stmt\NamedTypeNode;
89

910
/**
10-
* @template TDateTime of \DateTime|\DateTimeImmutable = \DateTimeImmutable
11+
* @template TDateTime of \DateTimeInterface = \DateTimeInterface
1112
* @template-extends DateTimeTypeBuilder<TDateTime, string>
1213
*/
1314
class DateTimeToStringTypeBuilder extends DateTimeTypeBuilder
1415
{
15-
protected function create(string $class, ?string $format = null): DateTimeToStringType
16+
protected function create(NamedTypeNode $stmt, string $class, ?string $format = null): DateTimeToStringType
1617
{
1718
$format ??= DateTimeToStringType::DEFAULT_DATETIME_FORMAT;
1819

src/Type/Builder/DateTimeTypeBuilder.php

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
use TypeLang\Parser\Node\Stmt\TypeStatement;
1515

1616
/**
17-
* @template TDateTime of \DateTime|\DateTimeImmutable = \DateTimeImmutable
17+
* @template TDateTime of \DateTimeInterface = \DateTimeInterface
1818
* @template TResult of mixed = mixed
1919
* @template-extends Builder<NamedTypeNode, TypeInterface<TResult>>
2020
*/
@@ -26,21 +26,6 @@ public function isSupported(TypeStatement $statement): bool
2626
&& \is_a($statement->name->toLowerString(), \DateTimeInterface::class, true);
2727
}
2828

29-
/**
30-
* @return class-string<TDateTime>
31-
* @return class-string<TDateTime>
32-
*/
33-
private function getDateTimeClass(string $name): string
34-
{
35-
if ($name === \DateTimeInterface::class || \interface_exists($name)) {
36-
/** @phpstan-ignore-next-line : If an interface is passed, then return the base class */
37-
return \DateTimeImmutable::class;
38-
}
39-
40-
/** @var class-string<TDateTime> */
41-
return $name;
42-
}
43-
4429
public function build(
4530
TypeStatement $statement,
4631
TypeRepositoryInterface $types,
@@ -50,11 +35,7 @@ public function build(
5035
$this->expectTemplateArgumentsLessOrEqualThan($statement, 1, 0);
5136

5237
if ($statement->arguments === null) {
53-
return $this->create(
54-
class: $this->getDateTimeClass(
55-
name: $statement->name->toString(),
56-
),
57-
);
38+
return $this->create($statement, $statement->name->toString());
5839
}
5940

6041
/** @var TemplateArgumentNode $formatArgument */
@@ -71,9 +52,8 @@ class: $this->getDateTimeClass(
7152
}
7253

7354
return $this->create(
74-
class: $this->getDateTimeClass(
75-
name: $statement->name->toString(),
76-
),
55+
stmt: $statement,
56+
class: $statement->name->toString(),
7757
format: $formatArgument->value->value,
7858
);
7959
}
@@ -83,5 +63,5 @@ class: $this->getDateTimeClass(
8363
*
8464
* @return TypeInterface<TResult>
8565
*/
86-
abstract protected function create(string $class, ?string $format = null): TypeInterface;
66+
abstract protected function create(NamedTypeNode $stmt, string $class, ?string $format = null): TypeInterface;
8767
}

src/Type/DateTimeFromStringType.php

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@
44

55
namespace TypeLang\Mapper\Type;
66

7-
use DateTime as TDateTime;
87
use TypeLang\Mapper\Context\Context;
98
use TypeLang\Mapper\Exception\Runtime\InvalidValueException;
109

1110
/**
12-
* @template TDateTime of \DateTime|\DateTimeImmutable = \DateTimeImmutable
11+
* @template TDateTime of \DateTimeInterface = \DateTimeInterface
1312
* @template-implements TypeInterface<TDateTime>
1413
*/
1514
class DateTimeFromStringType implements TypeInterface
@@ -24,7 +23,24 @@ public function __construct(
2423
* @var TypeInterface<string>
2524
*/
2625
protected readonly TypeInterface $input = new StringType(),
27-
) {}
26+
) {
27+
$this->assertDateTimeClassExists($class);
28+
}
29+
30+
/**
31+
* @param class-string<TDateTime> $class
32+
*/
33+
private function assertDateTimeClassExists(string $class): void
34+
{
35+
if (\class_exists($class)) {
36+
return;
37+
}
38+
39+
throw new \InvalidArgumentException(\sprintf(
40+
'Creating a date instance requires a date class, but %s is not one',
41+
$class,
42+
));
43+
}
2844

2945
/**
3046
* @phpstan-assert-if-true string $value

0 commit comments

Comments
 (0)