Passed
Pull Request — master (#93)
by Wilmer
12:16
created

RangeParser::parseType()   C

Complexity

Conditions 12
Paths 14

Size

Total Lines 36
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 156

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 12
eloc 17
c 1
b 0
f 0
nc 14
nop 2
dl 0
loc 36
ccs 0
cts 18
cp 0
crap 156
rs 6.9666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Pgsql;
6
7
use DateInterval;
8
use DateTime;
9
use InvalidArgumentException;
10
use function preg_match;
11
12
final class RangeParser
13
{
14
    private const RANGES = [
15
        Schema::TYPE_INT_4_RANGE,
16
        Schema::TYPE_INT_8_RANGE,
17
        Schema::TYPE_NUM_RANGE,
18
        Schema::TYPE_TS_RANGE,
19
        Schema::TYPE_TS_TZ_RANGE,
20
        Schema::TYPE_DATE_RANGE,
21
    ];
22
23
    private ?string $type = null;
24
25 53
    public function __construct(?string $type = null)
26
    {
27 53
        if ($type !== null) {
28 53
            if (self::isAllowedType($type)) {
29 53
                $this->type = $type;
30
            } else {
31
                throw new InvalidArgumentException('Unsupported range type "' . $type . '"');
32
            }
33
        }
34 53
    }
35
36 53
    public function parse(?string $value): ?array
37
    {
38 53
        if ($value === null) {
39
            return null;
40
        }
41
42 53
        if (!preg_match('/^(?P<open>\[|\()(?P<lower>[^,]*),(?P<upper>[^\)\]]*)(?P<close>\)|\])$/', $value, $matches)) {
43
            throw new InvalidArgumentException();
44
        }
45
46 53
        $lower = $matches['lower'] ? trim($matches['lower'], '"') : null;
47 53
        $upper = $matches['upper'] ? trim($matches['upper'], '"') : null;
48 53
        $includeLower = $matches['open'] === '[';
49 53
        $includeUpper = $matches['close'] === ']';
50
51 53
        if ($lower === null && $upper === null) {
52
            return [null, null];
53
        }
54
55 53
        $type = $this->type ?? self::parseType($lower, $upper);
56
57 53
        switch ($type) {
58
            case Schema::TYPE_INT_4_RANGE:
59 12
                return self::parseIntRange($lower, $upper, $includeLower, $includeUpper);
60
            case Schema::TYPE_INT_8_RANGE:
61 12
                return self::parseBigIntRange($lower, $upper, $includeLower, $includeUpper);
62
            case Schema::TYPE_NUM_RANGE:
63 7
                return self::parseNumRange($lower, $upper, $includeLower, $includeUpper);
64
            case Schema::TYPE_DATE_RANGE:
65 9
                return self::parseDateRange($lower, $upper, $includeLower, $includeUpper);
66
            case Schema::TYPE_TS_RANGE:
67 7
                return self::parseTsRange($lower, $upper, $includeLower, $includeUpper);
68
            case Schema::TYPE_TS_TZ_RANGE:
69 6
                return self::parseTsTzRange($lower, $upper, $includeLower, $includeUpper);
70
            default:
71
                return null;
72
        }
73
    }
74
75 24
    private static function parseIntRange(?string $lower, ?string $upper, bool $includeLower, bool $includeUpper): array
76
    {
77 24
        $min = $lower === null ? null : (int) $lower;
78 24
        $max = $upper === null ? null : (int) $upper;
79
80 24
        if ($min !== null && $includeLower === false) {
81
            $min += 1;
82
        }
83
84 24
        if ($max !== null && $includeUpper === false) {
85 18
            $max -= 1;
86
        }
87
88 24
        return [$min, $max];
89
    }
90
91 12
    private static function parseBigIntRange(?string $lower, ?string $upper, bool $includeLower, bool $includeUpper): array
92
    {
93 12
        if (PHP_INT_SIZE === 8) {
94 12
            return self::parseIntRange($lower, $upper, $includeLower, $includeUpper);
95
        }
96
97
        [$min, $max] = self::parseNumRange($lower, $upper, $includeLower, $includeUpper);
98
99
        if ($min !== null && $includeLower === false) {
100
            $min += 1;
101
        }
102
103
        if ($max !== null && $includeUpper === false) {
104
            $max -= 1;
105
        }
106
107
        return [$min, $max];
108
    }
109
110 7
    private static function parseNumRange(?string $lower, ?string $upper, bool $includeLower, bool $includeUpper): array
0 ignored issues
show
Unused Code introduced by
The parameter $includeLower is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

110
    private static function parseNumRange(?string $lower, ?string $upper, /** @scrutinizer ignore-unused */ bool $includeLower, bool $includeUpper): array

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $includeUpper is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

110
    private static function parseNumRange(?string $lower, ?string $upper, bool $includeLower, /** @scrutinizer ignore-unused */ bool $includeUpper): array

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
111
    {
112 7
        $min = $lower === null ? null : (float) $lower;
113 7
        $max = $upper === null ? null : (float) $upper;
114
115 7
        return [$min, $max];
116
    }
117
118 9
    private static function parseDateRange(?string $lower, ?string $upper, bool $includeLower, bool $includeUpper): array
119
    {
120 9
        $interval = new DateInterval('P1D');
121 9
        $min = $lower ? DateTime::createFromFormat('Y-m-d', $lower) : null;
122 9
        $max = $upper ? DateTime::createFromFormat('Y-m-d', $upper) : null;
123
124 9
        if ($min && $includeLower === false) {
125
            $min->add($interval);
126
        }
127
128 9
        if ($max && $includeUpper === false) {
129 6
            $max->sub($interval);
130
        }
131
132 9
        return [$min, $max];
133
    }
134
135 7
    private static function parseTsRange(?string $lower, ?string $upper, bool $includeLower, bool $includeUpper): array
0 ignored issues
show
Unused Code introduced by
The parameter $includeLower is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

135
    private static function parseTsRange(?string $lower, ?string $upper, /** @scrutinizer ignore-unused */ bool $includeLower, bool $includeUpper): array

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $includeUpper is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

135
    private static function parseTsRange(?string $lower, ?string $upper, bool $includeLower, /** @scrutinizer ignore-unused */ bool $includeUpper): array

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
136
    {
137 7
        $min = $lower ? DateTime::createFromFormat('Y-m-d H:i:s', $lower) : null;
138 7
        $max = $upper ? DateTime::createFromFormat('Y-m-d H:i:s', $upper) : null;
139
140 7
        return [$min, $max];
141
    }
142
143 6
    private static function parseTsTzRange(?string $lower, ?string $upper, bool $includeLower, bool $includeUpper): array
0 ignored issues
show
Unused Code introduced by
The parameter $includeLower is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

143
    private static function parseTsTzRange(?string $lower, ?string $upper, /** @scrutinizer ignore-unused */ bool $includeLower, bool $includeUpper): array

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $includeUpper is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

143
    private static function parseTsTzRange(?string $lower, ?string $upper, bool $includeLower, /** @scrutinizer ignore-unused */ bool $includeUpper): array

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
144
    {
145 6
        $min = $lower ? DateTime::createFromFormat('Y-m-d H:i:sP', $lower) : null;
146 6
        $max = $upper ? DateTime::createFromFormat('Y-m-d H:i:sP', $upper) : null;
147
148 6
        return [$min, $max];
149
    }
150
151 85
    public static function isAllowedType(string $type): bool
152
    {
153 85
        return in_array($type, self::RANGES, true);
154
    }
155
156
    /**
157
     * Find range type from value format
158
     *
159
     * @param string $lower
160
     * @param string $upper
161
     *
162
     * @return string|null
163
     */
164
    private static function parseType(?string $lower, ?string $upper): ?string
165
    {
166
        if ($lower !== null && $upper !== null) {
167
            if (filter_var($lower, FILTER_VALIDATE_INT) && filter_var($upper, FILTER_VALIDATE_INT)) {
168
                return Schema::TYPE_INT_4_RANGE;
169
            }
170
171
            if (filter_var($lower, FILTER_VALIDATE_FLOAT) && filter_var($upper, FILTER_VALIDATE_FLOAT)) {
172
                return Schema::TYPE_NUM_RANGE;
173
            }
174
        }
175
176
        $value = $lower ?? $upper;
177
178
        if (filter_var($value, FILTER_VALIDATE_INT)) {
179
            return Schema::TYPE_INT_4_RANGE;
180
        }
181
182
183
        if (filter_var($value, FILTER_VALIDATE_FLOAT)) {
184
            return Schema::TYPE_NUM_RANGE;
185
        }
186
187
        if (DateTime::createFromFormat('Y-m-d', $value)) {
188
            return Schema::TYPE_DATE_RANGE;
189
        }
190
191
        if (DateTime::createFromFormat('Y-m-d H:i:s', $value)) {
192
            return Schema::TYPE_TS_RANGE;
193
        }
194
195
        if (DateTime::createFromFormat('Y-m-d H:i:sP', $value)) {
196
            return Schema::TYPE_TS_TZ_RANGE;
197
        }
198
199
        return null;
200
    }
201
}
202