Range::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 20
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 9
c 1
b 0
f 0
nc 1
nop 8
dl 0
loc 20
ccs 5
cts 5
cp 1
crap 1
rs 9.9666

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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