Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
91.67% covered (success)
91.67%
22 / 24
83.33% covered (warning)
83.33%
5 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
DateTime
91.67% covered (success)
91.67%
22 / 24
83.33% covered (warning)
83.33%
5 / 6
11.07
0.00% covered (danger)
0.00%
0 / 1
 control
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 value
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 structure
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 shape
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
2
 metaShape
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 normalize
71.43% covered (warning)
71.43%
5 / 7
0.00% covered (danger)
0.00%
0 / 1
5.58
1<?php
2
3declare(strict_types=1);
4
5namespace Cosray\Field;
6
7use Celema\Sire\Shape;
8use Cosray\DateTime\Codec;
9use Cosray\Validation\Shapes;
10use Cosray\Value\DateTime as DateTimeValue;
11use Override;
12
13class DateTime extends Field
14{
15    #[Override]
16    public function control(): Control
17    {
18        return Control::datetime();
19    }
20
21    #[Override]
22    public function value(): DateTimeValue
23    {
24        return new DateTimeValue($this->owner, $this, $this->valueContext);
25    }
26
27    #[Override]
28    public function structure(mixed $value = null): array
29    {
30        return $this->getSimpleStructure('datetime', $value);
31    }
32
33    #[Override]
34    public function shape(): Shape
35    {
36        $shape = Shapes::create();
37        $this->addType($shape);
38
39        $value = $shape
40            ->add('value', $this->zxxShape('string', ['rfc3339', ...$this->validators]))
41            ->finalize(self::normalize(...));
42
43        if (!$this->isRequired()) {
44            $value->optional()->nullable();
45        }
46
47        $this->addMeta($shape);
48
49        return $shape;
50    }
51
52    #[Override]
53    protected function metaShape(): Shape
54    {
55        $shape = parent::metaShape();
56        $timezone = Shapes::create();
57        $timezone->add(self::NEUTRAL_LOCALE, 'string')->rules('timezone')->optional()->nullable();
58        $shape->add('timezone', $timezone)->optional()->nullable();
59
60        return $shape;
61    }
62
63    private static function normalize(mixed $value): mixed
64    {
65        if (!is_array($value)) {
66            return $value;
67        }
68
69        $datetime = $value[self::NEUTRAL_LOCALE] ?? null;
70
71        if (!is_string($datetime) || $datetime === '') {
72            return $value;
73        }
74
75        $normalized = Codec::normalize($datetime);
76
77        return $normalized === null ? $value : [...$value, self::NEUTRAL_LOCALE => $normalized];
78    }
79}