Passed
Pull Request — master (#85)
by
unknown
02:46
created

RangeParser   B

Complexity

Total Complexity 52

Size/Duplication

Total Lines 168
Duplicated Lines 0 %

Test Coverage

Coverage 2.7%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 80
c 1
b 0
f 0
dl 0
loc 168
ccs 2
cts 74
cp 0.027
rs 7.44
wmc 52

9 Methods

Rating   Name   Duplication   Size   Complexity  
B parseDateRange() 0 15 7
C parse() 0 35 13
A __construct() 0 7 3
A parseNumRange() 0 6 3
A isAllowedType() 0 3 1
B parseIntRange() 0 14 7
A parseTsRange() 0 6 3
C parseType() 0 36 12
A parseTsTzRange() 0 6 3

How to fix   Complexity   

Complex Class

Complex classes like RangeParser often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use RangeParser, and based on these observations, apply Extract Interface, too.

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 RuntimeException;
11
use function preg_match;
12
13
final class RangeParser
14
{
15
    private const RANGES = [
16
        Schema::TYPE_INT_4_RANGE,
17
        Schema::TYPE_INT_8_RANGE,
18
        Schema::TYPE_NUM_RANGE,
19
        Schema::TYPE_TS_RANGE,
20
        Schema::TYPE_TS_TZ_RANGE,
21
        Schema::TYPE_DATE_RANGE,
22
    ];
23
24
    private ?string $type = null;
25
26
    public function __construct(?string $type = null)
27
    {
28
        if ($type !== null) {
29
            if (self::isAllowedType($type)) {
30
                $this->type = $type;
31
            } else {
32
                throw new InvalidArgumentException('Unsupported range type "' . $type . '"');
33
            }
34
        }
35
    }
36
37
    public function parse(?string $value): ?array
38
    {
39
        if ($value === null) {
40
            return null;
41
        }
42
43
        if (!preg_match('/^(\[|\()([^,]*),([^\(\]]*)(\)|\])$/', $value, $matches)) {
44
            throw new InvalidArgumentException();
45
        }
46
47
        $lower = $matches[2] ? trim($matches[2], '"') : null;
48
        $upper = $matches[3] ? trim($matches[3], '"') : null;
49
        $includeLower = $matches[0] === '[';
50
        $includeUpper = $matches[4] === ']';
51
52
        if ($lower === null && $upper === null) {
53
            return [null, null];
54
        }
55
56
        $type = $this->type ?? self::parseType($lower, $upper);
57
58
        switch ($type) {
59
            case Schema::TYPE_INT_4_RANGE:
60
            case Schema::TYPE_INT_8_RANGE:
61
                return self::parseIntRange($lower, $upper, $includeLower, $includeUpper);
62
            case Schema::TYPE_NUM_RANGE:
63
                return self::parseNumRange($lower, $upper, $includeLower, $includeUpper);
64
            case Schema::TYPE_DATE_RANGE:
65
                return self::parseDateRange($lower, $upper, $includeLower, $includeUpper);
66
            case Schema::TYPE_TS_RANGE:
67
                return self::parseTsRange($lower, $upper, $includeLower, $includeUpper);
68
            case Schema::TYPE_TS_TZ_RANGE:
69
                return self::parseTsTzRange($lower, $upper, $includeLower, $includeUpper);
70
            default:
71
                throw new RuntimeException();
72
        }
73
    }
74
75
    private static function parseIntRange(?string $lower, ?string $upper, bool $includeLower, bool $includeUpper): array
76
    {
77
        $min = $lower === null ? null : (int) $lower;
78
        $max = $upper === null ? null : (int) $upper;
79
80
        if ($min !== null && $includeLower === false) {
81
            $min += 1;
82
        }
83
84
        if ($max !== null && $includeUpper === false) {
85
            $max -= 1;
86
        }
87
88
        return [$min, $max];
89
    }
90
91
    private static function parseNumRange(?string $lower, ?string $upper, bool $includeLower, bool $includeUpper): array
0 ignored issues
show
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

91
    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...
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

91
    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...
92
    {
93
        $min = $lower === null ? null : (float) $lower;
94
        $max = $upper === null ? null : (float) $upper;
95
96
        return [$min, $max];
97
    }
98
99
    private static function parseDateRange(?string $lower, ?string $upper, bool $includeLower, bool $includeUpper): array
100
    {
101
        $interval = new DateInterval('P1D');
102
        $min = $lower ? DateTime::createFromFormat('Y-m-d', $lower) : null;
103
        $max = $upper ? DateTime::createFromFormat('Y-m-d', $upper) : null;
104
105
        if ($min && $includeLower === false) {
106
            $min->add($interval);
107
        }
108
109
        if ($max && $includeUpper === false) {
110
            $max->sub($interval);
111
        }
112
113
        return [$min, $max];
114
    }
115
116
    private static function parseTsRange(?string $lower, ?string $upper, bool $includeLower, bool $includeUpper): array
0 ignored issues
show
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

116
    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...
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

116
    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...
117
    {
118
        $min = $lower ? DateTime::createFromFormat('Y-m-d H:i:s', $lower) : null;
119
        $max = $upper ? DateTime::createFromFormat('Y-m-d H:i:s', $upper) : null;
120
121
        return [$min, $max];
122
    }
123
124
    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

124
    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

124
    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...
125
    {
126
        $min = $lower ? DateTime::createFromFormat('Y-m-d H:i:sP', $lower) : null;
127
        $max = $upper ? DateTime::createFromFormat('Y-m-d H:i:sP', $upper) : null;
128
129
        return [$min, $max];
130
    }
131
132 32
    public static function isAllowedType(string $type): bool
133
    {
134 32
        return in_array($type, self::RANGES, true);
135
    }
136
137
    /**
138
     * Find range type from value format
139
     *
140
     * @param string $lower
141
     * @param string $upper
142
     *
143
     * @return string|null
144
     */
145
    private static function parseType(?string $lower, ?string $upper): ?string
146
    {
147
        if ($lower !== null && $upper !== null) {
148
            if (filter_var($lower, FILTER_VALIDATE_INT) && filter_var($upper, FILTER_VALIDATE_INT)) {
149
                return Schema::TYPE_INT_4_RANGE;
150
            }
151
152
            if (filter_var($lower, FILTER_VALIDATE_FLOAT) && filter_var($upper, FILTER_VALIDATE_FLOAT)) {
153
                return Schema::TYPE_NUM_RANGE;
154
            }
155
        }
156
157
        $value = $lower ?? $upper;
158
159
        if (filter_var($value, FILTER_VALIDATE_INT)) {
160
            return Schema::TYPE_INT_4_RANGE;
161
        }
162
163
164
        if (filter_var($value, FILTER_VALIDATE_FLOAT)) {
165
            return Schema::TYPE_NUM_RANGE;
166
        }
167
168
        if (DateTime::createFromFormat('Y-m-d', $value)) {
169
            return Schema::TYPE_DATE_RANGE;
170
        }
171
172
        if (DateTime::createFromFormat('Y-m-d H:i:s', $value)) {
173
            return Schema::TYPE_TS_RANGE;
174
        }
175
176
        if (DateTime::createFromFormat('Y-m-d H:i:sP', $value)) {
177
            return Schema::TYPE_TS_TZ_RANGE;
178
        }
179
180
        return null;
181
    }
182
}
183