Passed
Push — master ( dd435e...1658ca )
by Tomáš
18:05 queued 08:04
created

Range::getEndRelativeDateValue()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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