Passed
Pull Request — master (#11)
by Alex
11:43 queued 03:10
created

DateTimeFactory::createDateTimeZone()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
eloc 10
c 1
b 1
f 0
dl 0
loc 13
rs 9.9332
cc 2
nc 2
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Arp\DateTime;
6
7
use Arp\DateTime\Exception\DateTimeFactoryException;
8
use Arp\DateTime\Exception\DateTimeZoneFactoryException;
9
10
/**
11
 * @author  Alex Patterson <[email protected]>
12
 * @package Arp\DateTime
13
 */
14
final class DateTimeFactory implements DateTimeFactoryInterface
15
{
16
    /**
17
     * @var DateTimeZoneFactoryInterface
18
     */
19
    private DateTimeZoneFactoryInterface $dateTimeZoneFactory;
20
21
    /**
22
     * @var string
23
     */
24
    private string $dateTimeClassName;
25
26
    /**
27
     * @param DateTimeZoneFactoryInterface|null $dateTimeZoneFactory
28
     * @param string|null                       $dateTimeClassName
29
     *
30
     * @throws DateTimeFactoryException
31
     */
32
    public function __construct(
33
        DateTimeZoneFactoryInterface $dateTimeZoneFactory = null,
34
        string $dateTimeClassName = null
35
    ) {
36
        $this->dateTimeZoneFactory = $dateTimeZoneFactory ?? new DateTimeZoneFactory();
37
38
        $dateTimeClassName ??= \DateTime::class;
39
        if (!is_a($dateTimeClassName, \DateTimeInterface::class, true)) {
40
            throw new DateTimeFactoryException(
41
                sprintf(
42
                    'The \'dateTimeClassName\' parameter must be a class name that implements \'%s\'',
43
                    \DateTimeInterface::class
44
                )
45
            );
46
        }
47
48
        $this->dateTimeClassName = $dateTimeClassName;
49
    }
50
51
    /**
52
     * @param null|string               $spec     The date and time specification
53
     * @param string|\DateTimeZone|null $timeZone The date time zone; if omitted or null the PHP default will be used
54
     *
55
     * @return \DateTimeInterface
56
     *
57
     * @throws DateTimeFactoryException If the \DateTime instance cannot be created.
58
     */
59
    public function createDateTime(?string $spec = null, $timeZone = null): \DateTimeInterface
60
    {
61
        try {
62
            return new $this->dateTimeClassName($spec ?? 'now', $this->resolveDateTimeZone($timeZone));
63
        } catch (\Exception $e) {
64
            throw new DateTimeFactoryException(
65
                sprintf(
66
                    'Failed to create a valid \DateTime instance using \'%s\': %s',
67
                    $spec,
68
                    $e->getMessage()
69
                ),
70
                $e->getCode(),
71
                $e
72
            );
73
        }
74
    }
75
76
    /**
77
     * @param string                    $format   The date and time format
78
     * @param string                    $spec     The date and time specification
79
     * @param string|\DateTimeZone|null $timeZone The date time zone; if omitted or null the PHP default will be used
80
     *
81
     * @return \DateTimeInterface
82
     *
83
     * @throws DateTimeFactoryException  If the \DateTime instance cannot be created
84
     */
85
    public function createFromFormat(string $format, string $spec, $timeZone = null): \DateTimeInterface
86
    {
87
        /** @var callable $factory */
88
        $factory = [$this->dateTimeClassName, 'createFromFormat'];
89
90
        $dateTime = $factory($format, $spec, $this->resolveDateTimeZone($timeZone));
91
92
        if (false === $dateTime || !$dateTime instanceof \DateTimeInterface) {
93
            throw new DateTimeFactoryException(
94
                sprintf(
95
                    'Failed to create a valid \DateTime instance using \'%s\' and format \'%s\'',
96
                    $spec,
97
                    $format
98
                )
99
            );
100
        }
101
102
        return $dateTime;
103
    }
104
105
    /**
106
     * @param mixed|string|\DateTimeZone|null $timeZone
107
     *
108
     * @return \DateTimeZone|null
109
     *
110
     * @throws DateTimeFactoryException
111
     */
112
    private function resolveDateTimeZone($timeZone): ?\DateTimeZone
113
    {
114
        if (empty($timeZone) || (!is_string($timeZone) && !$timeZone instanceof \DateTimeZone)) {
115
            return null;
116
        }
117
118
        try {
119
            return is_string($timeZone)
120
                ? $this->dateTimeZoneFactory->createDateTimeZone($timeZone)
121
                : $timeZone;
122
        } catch (DateTimeZoneFactoryException $e) {
123
            throw new DateTimeFactoryException(
124
                sprintf('Failed to create date time zone: %s', $e->getMessage()),
125
                $e->getCode(),
126
                $e
127
            );
128
        }
129
    }
130
}
131