Constraint   F
last analyzed

Complexity

Total Complexity 81

Size/Duplication

Total Lines 253
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 81
eloc 148
dl 0
loc 253
rs 2
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A getVersion() 0 3 1
A getOperator() 0 3 1
D matchSpecific() 0 30 22
A __construct() 0 7 2
B versionCompare() 0 17 11
A setPrettyString() 0 3 1
A getSupportedOperators() 0 3 1
A getUpperBound() 0 4 1
A __toString() 0 3 1
A getOperatorConstant() 0 3 1
D compile() 0 64 25
A matches() 0 6 2
B extractBounds() 0 35 9
A getPrettyString() 0 6 2
A getLowerBound() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like Constraint 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 Constraint, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace HumbugBox451\Composer\Semver\Constraint;
4
5
/** @internal */
6
class Constraint implements ConstraintInterface
7
{
8
    const OP_EQ = 0;
9
    const OP_LT = 1;
10
    const OP_LE = 2;
11
    const OP_GT = 3;
12
    const OP_GE = 4;
13
    const OP_NE = 5;
14
    const STR_OP_EQ = '==';
15
    const STR_OP_EQ_ALT = '=';
16
    const STR_OP_LT = '<';
17
    const STR_OP_LE = '<=';
18
    const STR_OP_GT = '>';
19
    const STR_OP_GE = '>=';
20
    const STR_OP_NE = '!=';
21
    const STR_OP_NE_ALT = '<>';
22
    /**
23
    @phpstan-var
24
    */
25
    private static $transOpStr = array('=' => self::OP_EQ, '==' => self::OP_EQ, '<' => self::OP_LT, '<=' => self::OP_LE, '>' => self::OP_GT, '>=' => self::OP_GE, '<>' => self::OP_NE, '!=' => self::OP_NE);
26
    /**
27
    @phpstan-var
28
    */
29
    private static $transOpInt = array(self::OP_EQ => '==', self::OP_LT => '<', self::OP_LE => '<=', self::OP_GT => '>', self::OP_GE => '>=', self::OP_NE => '!=');
30
    /**
31
    @phpstan-var
32
    */
33
    protected $operator;
34
    protected $version;
35
    protected $prettyString;
36
    protected $lowerBound;
37
    protected $upperBound;
38
    /**
39
    @phpstan-param
40
    */
41
    public function __construct($operator, $version)
42
    {
43
        if (!isset(self::$transOpStr[$operator])) {
44
            throw new \InvalidArgumentException(\sprintf('Invalid operator "%s" given, expected one of: %s', $operator, \implode(', ', self::getSupportedOperators())));
45
        }
46
        $this->operator = self::$transOpStr[$operator];
47
        $this->version = $version;
48
    }
49
    public function getVersion()
50
    {
51
        return $this->version;
52
    }
53
    /**
54
    @phpstan-return
55
    */
56
    public function getOperator()
57
    {
58
        return self::$transOpInt[$this->operator];
59
    }
60
    public function matches(ConstraintInterface $provider)
61
    {
62
        if ($provider instanceof self) {
63
            return $this->matchSpecific($provider);
64
        }
65
        return $provider->matches($this);
66
    }
67
    public function setPrettyString($prettyString)
68
    {
69
        $this->prettyString = $prettyString;
70
    }
71
    public function getPrettyString()
72
    {
73
        if ($this->prettyString) {
74
            return $this->prettyString;
75
        }
76
        return $this->__toString();
77
    }
78
    /**
79
    @phpstan-return
80
    */
81
    public static function getSupportedOperators()
82
    {
83
        return \array_keys(self::$transOpStr);
84
    }
85
    /**
86
    @phpstan-param
87
    @phpstan-return
88
    */
89
    public static function getOperatorConstant($operator)
90
    {
91
        return self::$transOpStr[$operator];
92
    }
93
    /**
94
    @phpstan-param
95
    */
96
    public function versionCompare($a, $b, $operator, $compareBranches = \false)
97
    {
98
        if (!isset(self::$transOpStr[$operator])) {
99
            throw new \InvalidArgumentException(\sprintf('Invalid operator "%s" given, expected one of: %s', $operator, \implode(', ', self::getSupportedOperators())));
100
        }
101
        $aIsBranch = \strpos($a, 'dev-') === 0;
102
        $bIsBranch = \strpos($b, 'dev-') === 0;
103
        if ($operator === '!=' && ($aIsBranch || $bIsBranch)) {
104
            return $a !== $b;
105
        }
106
        if ($aIsBranch && $bIsBranch) {
107
            return $operator === '==' && $a === $b;
108
        }
109
        if (!$compareBranches && ($aIsBranch || $bIsBranch)) {
110
            return \false;
111
        }
112
        return \version_compare($a, $b, $operator);
113
    }
114
    public function compile($otherOperator)
115
    {
116
        if (\strpos($this->version, 'dev-') === 0) {
117
            if (self::OP_EQ === $this->operator) {
118
                if (self::OP_EQ === $otherOperator) {
119
                    return \sprintf('$b && $v === %s', \var_export($this->version, \true));
120
                }
121
                if (self::OP_NE === $otherOperator) {
122
                    return \sprintf('!$b || $v !== %s', \var_export($this->version, \true));
123
                }
124
                return 'false';
125
            }
126
            if (self::OP_NE === $this->operator) {
127
                if (self::OP_EQ === $otherOperator) {
128
                    return \sprintf('!$b || $v !== %s', \var_export($this->version, \true));
129
                }
130
                if (self::OP_NE === $otherOperator) {
131
                    return 'true';
132
                }
133
                return '!$b';
134
            }
135
            return 'false';
136
        }
137
        if (self::OP_EQ === $this->operator) {
138
            if (self::OP_EQ === $otherOperator) {
139
                return \sprintf('\\version_compare($v, %s, \'==\')', \var_export($this->version, \true));
140
            }
141
            if (self::OP_NE === $otherOperator) {
142
                return \sprintf('$b || \\version_compare($v, %s, \'!=\')', \var_export($this->version, \true));
143
            }
144
            return \sprintf('!$b && \\version_compare(%s, $v, \'%s\')', \var_export($this->version, \true), self::$transOpInt[$otherOperator]);
145
        }
146
        if (self::OP_NE === $this->operator) {
147
            if (self::OP_EQ === $otherOperator) {
148
                return \sprintf('$b || (!$b && \\version_compare($v, %s, \'!=\'))', \var_export($this->version, \true));
149
            }
150
            if (self::OP_NE === $otherOperator) {
151
                return 'true';
152
            }
153
            return '!$b';
154
        }
155
        if (self::OP_LT === $this->operator || self::OP_LE === $this->operator) {
156
            if (self::OP_LT === $otherOperator || self::OP_LE === $otherOperator) {
157
                return '!$b';
158
            }
159
        } else {
160
            if (self::OP_GT === $otherOperator || self::OP_GE === $otherOperator) {
161
                return '!$b';
162
            }
163
        }
164
        if (self::OP_NE === $otherOperator) {
165
            return 'true';
166
        }
167
        $codeComparison = \sprintf('\\version_compare($v, %s, \'%s\')', \var_export($this->version, \true), self::$transOpInt[$this->operator]);
168
        if ($this->operator === self::OP_LE) {
169
            if ($otherOperator === self::OP_GT) {
170
                return \sprintf('!$b && \\version_compare($v, %s, \'!=\') && ', \var_export($this->version, \true)) . $codeComparison;
171
            }
172
        } elseif ($this->operator === self::OP_GE) {
173
            if ($otherOperator === self::OP_LT) {
174
                return \sprintf('!$b && \\version_compare($v, %s, \'!=\') && ', \var_export($this->version, \true)) . $codeComparison;
175
            }
176
        }
177
        return \sprintf('!$b && %s', $codeComparison);
178
    }
179
    public function matchSpecific(Constraint $provider, $compareBranches = \false)
180
    {
181
        $noEqualOp = \str_replace('=', '', self::$transOpInt[$this->operator]);
182
        $providerNoEqualOp = \str_replace('=', '', self::$transOpInt[$provider->operator]);
183
        $isEqualOp = self::OP_EQ === $this->operator;
184
        $isNonEqualOp = self::OP_NE === $this->operator;
185
        $isProviderEqualOp = self::OP_EQ === $provider->operator;
186
        $isProviderNonEqualOp = self::OP_NE === $provider->operator;
187
        if ($isNonEqualOp || $isProviderNonEqualOp) {
188
            if ($isNonEqualOp && !$isProviderNonEqualOp && !$isProviderEqualOp && \strpos($provider->version, 'dev-') === 0) {
189
                return \false;
190
            }
191
            if ($isProviderNonEqualOp && !$isNonEqualOp && !$isEqualOp && \strpos($this->version, 'dev-') === 0) {
192
                return \false;
193
            }
194
            if (!$isEqualOp && !$isProviderEqualOp) {
195
                return \true;
196
            }
197
            return $this->versionCompare($provider->version, $this->version, '!=', $compareBranches);
198
        }
199
        if ($this->operator !== self::OP_EQ && $noEqualOp === $providerNoEqualOp) {
200
            return !(\strpos($this->version, 'dev-') === 0 || \strpos($provider->version, 'dev-') === 0);
201
        }
202
        $version1 = $isEqualOp ? $this->version : $provider->version;
203
        $version2 = $isEqualOp ? $provider->version : $this->version;
204
        $operator = $isEqualOp ? $provider->operator : $this->operator;
205
        if ($this->versionCompare($version1, $version2, self::$transOpInt[$operator], $compareBranches)) {
206
            return !(self::$transOpInt[$provider->operator] === $providerNoEqualOp && self::$transOpInt[$this->operator] !== $noEqualOp && \version_compare($provider->version, $this->version, '=='));
207
        }
208
        return \false;
209
    }
210
    public function __toString()
211
    {
212
        return self::$transOpInt[$this->operator] . ' ' . $this->version;
213
    }
214
    public function getLowerBound()
215
    {
216
        $this->extractBounds();
217
        return $this->lowerBound;
218
    }
219
    public function getUpperBound()
220
    {
221
        $this->extractBounds();
222
        return $this->upperBound;
223
    }
224
    private function extractBounds()
225
    {
226
        if (null !== $this->lowerBound) {
227
            return;
228
        }
229
        if (\strpos($this->version, 'dev-') === 0) {
230
            $this->lowerBound = Bound::zero();
231
            $this->upperBound = Bound::positiveInfinity();
232
            return;
233
        }
234
        switch ($this->operator) {
235
            case self::OP_EQ:
236
                $this->lowerBound = new Bound($this->version, \true);
237
                $this->upperBound = new Bound($this->version, \true);
238
                break;
239
            case self::OP_LT:
240
                $this->lowerBound = Bound::zero();
241
                $this->upperBound = new Bound($this->version, \false);
242
                break;
243
            case self::OP_LE:
244
                $this->lowerBound = Bound::zero();
245
                $this->upperBound = new Bound($this->version, \true);
246
                break;
247
            case self::OP_GT:
248
                $this->lowerBound = new Bound($this->version, \false);
249
                $this->upperBound = Bound::positiveInfinity();
250
                break;
251
            case self::OP_GE:
252
                $this->lowerBound = new Bound($this->version, \true);
253
                $this->upperBound = Bound::positiveInfinity();
254
                break;
255
            case self::OP_NE:
256
                $this->lowerBound = Bound::zero();
257
                $this->upperBound = Bound::positiveInfinity();
258
                break;
259
        }
260
    }
261
}
262