Passed
Push — master ( 6d5c7d...f7244e )
by Tomáš
09:21
created

Range::getEndDateTimeValue()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 2
eloc 3
nc 2
nop 0
dl 0
loc 7
ccs 0
cts 0
cp 0
crap 6
rs 10
c 1
b 0
f 1
1
<?php declare(strict_types = 1);
2
3
namespace Apicart\FQL\Token\Token;
4
5
use DateTimeImmutable;
6
use Apicart\FQL\Value\Token;
7
use InvalidArgumentException;
8
use Apicart\FQL\Tokenizer\Tokenizer;
9
10
final class Range extends Token
11
{
12
13
    public const TYPE_INCLUSIVE = 'inclusive';
14
15
    public const TYPE_EXCLUSIVE = 'exclusive';
16
17
    public const DATE_FORMAT = 'Y-m-d';
18
    public const DATE_REGEX = '/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/';
19
20
    public const DATETIME_FORMAT = 'Y-m-d\TH:i:s\Z';
21
    public const DATETIME_REGEX = '/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])T([01]\d|2[0-3]):([0-5]\d):([0-5]\d)(\.\d{1,9})?Z$/';
22
    public const RELATIVE_DATE_SEPARATOR = '|';
23
    public const RELATIVE_DATE_REGEX = '/^(today|week|month|year)(\|(\+|-)?\d+)?$/';
24
25
    /**
26
     * @var string
27
     */
28
    private $domain;
29
30
    /**
31
     * @var int|float|string
32
     */
33
    private $startValue;
34
35
    /**
36
     * @var int|float|string
37
     */
38
    private $endValue;
39
40
    /**
41
     * @var string|null
42
     */
43
    private $startType;
44
45
    /**
46 23
     * @var string|null
47
     */
48
    private $endType;
49
50
    /**
51
     * @var Flags|null
52
     */
53
    private $flags;
54
55 23
56 16
    /**
57 10
     * @param int|float|string $startValue
58
     * @param int|float|string $endValue
59 10
     */
60 10
    public function __construct(
61 10
        string $lexeme,
62 10
        int $position,
63 10
        string $domain,
64 10
        $startValue,
65
        $endValue,
66
        ?string $startType,
67 7
        ?string $endType,
68
        ?Flags $flags = null
69 7
    ) {
70
        $this->ensureValidType($startType);
71
        $this->ensureValidType($endType);
72
        parent::__construct(Tokenizer::TOKEN_TERM, $lexeme, $position);
73
74
        $this->domain = $domain;
75
        $this->startValue = $startValue;
76 6
        $this->endValue = $endValue;
77
        $this->startType = $startType;
78 6
        $this->endType = $endType;
79
        $this->flags = $flags;
80
    }
81
82
83
    public function getDomain(): string
84
    {
85 5
        return $this->domain;
86
    }
87 5
88
89
    /**
90
     * @return int|float|string
91 7
     */
92
    public function getStartValue()
93 7
    {
94
        return $this->startValue;
95
    }
96
97 1
98
    public function getStartDateValue(): ?DateTimeImmutable
99 1
    {
100 1
        if ($this->isStartInDateFormat()) {
101
            return DateTimeImmutable::createFromFormat(self::DATE_FORMAT, $this->getStartValue());
102
        }
103 6
104
        return null;
105 6
    }
106
107
    public function getStartDateTimeValue(): ?DateTimeImmutable
108
    {
109 1
        if ($this->isStartInDateTimeFormat()) {
110
            return DateTimeImmutable::createFromFormat(self::DATETIME_FORMAT, $this->getStartValue());
111 1
        }
112 1
113
        return null;
114
    }
115 1
116
    public function getStartRelativeDateValue(): ?array
117 1
    {
118
        if ($this->isStartInRelativeDateFormat()) {
119
            $parts = explode(self::RELATIVE_DATE_SEPARATOR, $this->getStartValue());
120
            $value = $parts[0];
121 1
            $offset = isset($parts[1]) ? (int) $parts[1] : 0;
122
123 1
            return ['value' => $value, 'offset' => $offset];
124
        }
125
126
        return null;
127 1
    }
128
129 1
130
    /**
131
     * @return int|float|string
132
     */
133 1
    public function getEndValue()
134
    {
135 1
        return $this->endValue;
136
    }
137
138
    public function getEndDateValue(): ?DateTimeImmutable
139 23
    {
140
        if ($this->isEndInDateFormat()) {
141 23
            return DateTimeImmutable::createFromFormat(self::DATE_FORMAT, $this->getEndValue());
142 13
        }
143
144 16
        return null;
145
    }
146
147
    public function getEndDateTimeValue(): ?DateTimeImmutable
148
    {
149
        if ($this->isEndInDateTimeFormat()) {
150
            return DateTimeImmutable::createFromFormat(self::DATETIME_FORMAT, $this->getEndValue());
151
        }
152
153
        return null;
154
    }
155
156
    public function getEndRelativeDateValue(): ?array
157
    {
158
        if ($this->isEndInRelativeDateFormat()) {
159
            $parts = explode(self::RELATIVE_DATE_SEPARATOR, $this->getEndValue());
160
            $value = $parts[0];
161
            $offset = isset($parts[1]) ? (int) $parts[1] : 0;
162
163
            return ['value' => $value, 'offset' => $offset];
164
        }
165
166
        return null;
167
    }
168
169
170
    public function getStartType(): ?string
171
    {
172
        return $this->startType;
173
    }
174
175
176
    public function setStartType(?string $startType): void
177
    {
178
        $this->startType = $startType;
179
    }
180
181
182
    public function getEndType(): ?string
183
    {
184
        return $this->endType;
185
    }
186
187
188
    public function setEndType(?string $endType): void
189
    {
190
        $this->endType = $endType;
191
    }
192
193
194
    public function getStartSign(): string
195
    {
196
        return $this->getStartType() === Range::TYPE_INCLUSIVE ? '>=' : '>';
197
    }
198
199
200
    public function getEndSign(): string
201
    {
202
        return $this->getEndType() === Range::TYPE_INCLUSIVE ? '<=' : '<';
203
    }
204
205
206
    public function isStartDefined(): bool
207
    {
208
        return $this->getStartValue() !== '*';
209
    }
210
211
212
    public function isEndDefined(): bool
213
    {
214
        return $this->getEndValue() !== '*';
215
    }
216
217
218
    public function getFlags(): ?Flags
219
    {
220
        return $this->flags;
221
    }
222
223
    public function isStartInDateFormat(): bool
224
    {
225
        return preg_match(self::DATE_REGEX, $this->getStartValue()) === 1;
226
    }
227
228
    public function isStartInDateTimeFormat(): bool
229
    {
230
        return preg_match(self::DATETIME_REGEX, $this->getStartValue()) === 1;
231
    }
232
233
    public function isStartInRelativeDateFormat(): bool
234
    {
235
        return preg_match(self::RELATIVE_DATE_REGEX, $this->getStartValue()) === 1;
236
    }
237
238
    public function isEndInDateFormat(): bool
239
    {
240
        return preg_match(self::DATE_REGEX, $this->getEndValue()) === 1;
241
    }
242
243
    public function isEndInDateTimeFormat(): bool
244
    {
245
        return preg_match(self::DATETIME_REGEX, $this->getEndValue()) === 1;
246
    }
247
248
    public function isEndInRelativeDateFormat(): bool
249
    {
250
        return preg_match(self::RELATIVE_DATE_REGEX, $this->getEndValue()) === 1;
251
    }
252
253
254
    private function ensureValidType(?string $type): void
255
    {
256
        if (! in_array($type, [self::TYPE_EXCLUSIVE, self::TYPE_INCLUSIVE], true)) {
257
            throw new InvalidArgumentException(sprintf('Invalid range type: %s', $type));
258
        }
259
    }
260
261
}
262