Completed
Push — master ( d64bc8...bbe9ae )
by Nikola
01:45 queued 41s
created

Version   B

Complexity

Total Complexity 47

Size/Duplication

Total Lines 292
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 47
lcom 1
cbo 7
dl 0
loc 292
ccs 103
cts 103
cp 1
rs 8.64
c 0
b 0
f 0

34 Methods

Rating   Name   Duplication   Size   Complexity  
A getComparator() 0 8 2
A __construct() 0 12 1
A validateNumber() 0 6 2
A fromParts() 0 4 1
A fromString() 0 21 4
A getMajor() 0 4 1
A getMinor() 0 4 1
A getPatch() 0 4 1
A getPreRelease() 0 4 1
A getBuild() 0 4 1
A isEqualTo() 0 4 1
A isNotEqualTo() 0 4 1
A isGreaterThan() 0 4 1
A isGreaterOrEqualTo() 0 4 1
A isLessThan() 0 4 1
A isLessOrEqualTo() 0 4 1
A compareTo() 0 8 2
A isMajorRelease() 0 4 3
A isMinorRelease() 0 4 2
A isPatchRelease() 0 4 1
A isPreRelease() 0 4 1
A isBuild() 0 4 1
A hasBuild() 0 4 1
A incrementMajor() 0 4 1
A incrementMinor() 0 4 1
A incrementPatch() 0 4 1
A withPreRelease() 0 8 2
A withBuild() 0 8 2
A matches() 0 4 1
A __toString() 0 4 1
A jsonSerialize() 0 4 1
A toArray() 0 10 1
A setComparator() 0 4 1
A toString() 0 10 3

How to fix   Complexity   

Complex Class

Complex classes like Version 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 Version, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Version;
6
7
use JsonSerializable;
8
use Version\Extension\Build;
9
use Version\Extension\NoBuild;
10
use Version\Extension\NoPreRelease;
11
use Version\Exception\InvalidVersion;
12
use Version\Exception\InvalidVersionString;
13
use Version\Comparison\Comparator;
14
use Version\Comparison\SemverComparator;
15
use Version\Comparison\Constraint\Constraint;
16
use Version\Extension\PreRelease;
17
18
class Version implements JsonSerializable
19
{
20
    /** @var int */
21
    protected $major;
22
23
    /** @var int */
24
    protected $minor;
25
26
    /**  @var int */
27
    protected $patch;
28
29
    /** @var PreRelease */
30
    protected $preRelease;
31
32
    /** @var Build */
33
    protected $build;
34
35
    /** @var Comparator|null */
36
    protected static $comparator;
37
38 82
    protected function __construct(int $major, int $minor, int $patch, PreRelease $preRelease, Build $build)
39
    {
40 82
        $this->validateNumber('major', $major);
41 81
        $this->validateNumber('minor', $minor);
42 80
        $this->validateNumber('patch', $patch);
43
44 79
        $this->major = $major;
45 79
        $this->minor = $minor;
46 79
        $this->patch = $patch;
47 79
        $this->preRelease = $preRelease;
48 79
        $this->build = $build;
49 79
    }
50
51 82
    protected function validateNumber(string $name, int $value): void
52
    {
53 82
        if ($value < 0) {
54 3
            throw InvalidVersion::negativeNumber($name, $value);
55
        }
56 81
    }
57
58 82
    public static function fromParts(int $major, int $minor = 0, int $patch = 0, PreRelease $preRelease = null, Build $build = null): Version
59
    {
60 82
        return new static($major, $minor, $patch, $preRelease ?? new NoPreRelease(), $build ?? new NoBuild());
61
    }
62
63
    /**
64
     * @param string $versionString
65
     *
66
     * @return Version
67
     * @throws InvalidVersionString
68
     *
69
     */
70 80
    public static function fromString(string $versionString): Version
71
    {
72 80
        if (!preg_match(
73
            '#^'
74
            . '(v|release\-)?'
75
            . '(?P<core>(?:[0-9]|[1-9][0-9]+)(?:\.(?:[0-9]|[1-9][0-9]+)){2})'
76
            . '(?:\-(?P<preRelease>[0-9A-Za-z\-\.]+))?'
77
            . '(?:\+(?P<build>[0-9A-Za-z\-\.]+))?'
78 80
            . '$#',
79 80
            $versionString,
80 80
            $parts
81
        )) {
82 5
            throw InvalidVersionString::notParsable($versionString);
83
        }
84
85 76
        [$major, $minor, $patch] = explode('.', $parts['core']);
0 ignored issues
show
Bug introduced by
The variable $major does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $minor does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $patch does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
86 76
        $preRelease = !empty($parts['preRelease']) ? PreRelease::fromIdentifiersString($parts['preRelease']) : new NoPreRelease();
87 76
        $build = !empty($parts['build']) ? Build::fromIdentifiersString($parts['build']) : new NoBuild();
88
89 76
        return static::fromParts((int) $major, (int) $minor, (int) $patch, $preRelease, $build);
90
    }
91
92 60
    public function getMajor(): int
93
    {
94 60
        return $this->major;
95
    }
96
97 55
    public function getMinor(): int
98
    {
99 55
        return $this->minor;
100
    }
101
102 51
    public function getPatch(): int
103
    {
104 51
        return $this->patch;
105
    }
106
107 48
    public function getPreRelease(): PreRelease
108
    {
109 48
        return $this->preRelease;
110
    }
111
112 28
    public function getBuild(): Build
113
    {
114 28
        return $this->build;
115
    }
116
117
    /**
118
     * @param Version|string $version
119
     * @return bool
120
     */
121 6
    public function isEqualTo($version): bool
122
    {
123 6
        return $this->compareTo($version) === 0;
124
    }
125
126
    /**
127
     * @param Version|string $version
128
     * @return bool
129
     */
130 1
    public function isNotEqualTo($version): bool
131
    {
132 1
        return !$this->isEqualTo($version);
133
    }
134
135
    /**
136
     * @param Version|string $version
137
     * @return bool
138
     */
139 3
    public function isGreaterThan($version): bool
140
    {
141 3
        return $this->compareTo($version) > 0;
142
    }
143
144
    /**
145
     * @param Version|string $version
146
     * @return bool
147
     */
148 6
    public function isGreaterOrEqualTo($version): bool
149
    {
150 6
        return $this->compareTo($version) >= 0;
151
    }
152
153
    /**
154
     * @param Version|string $version
155
     * @return bool
156
     */
157 3
    public function isLessThan($version): bool
158
    {
159 3
        return $this->compareTo($version) < 0;
160
    }
161
162
    /**
163
     * @param Version|string $version
164
     * @return bool
165
     */
166 2
    public function isLessOrEqualTo($version): bool
167
    {
168 2
        return $this->compareTo($version) <= 0;
169
    }
170
171
    /**
172
     * @param Version|string $version
173
     * @return int (1 if $this > $version, -1 if $this < $version, 0 if equal)
174
     */
175 25
    public function compareTo($version): int
176
    {
177 25
        if (is_string($version)) {
178 7
            $version = static::fromString($version);
179
        }
180
181 25
        return $this->getComparator()->compare($this, $version);
182
    }
183
184 2
    public function isMajorRelease(): bool
185
    {
186 2
        return $this->major > 0 && $this->minor === 0 && $this->patch === 0;
187
    }
188
189 1
    public function isMinorRelease(): bool
190
    {
191 1
        return $this->minor > 0 && $this->patch === 0;
192
    }
193
194 1
    public function isPatchRelease(): bool
195
    {
196 1
        return $this->patch > 0;
197
    }
198
199 38
    public function isPreRelease(): bool
200
    {
201 38
        return !$this->preRelease->isEmpty();
202
    }
203
204
    /**
205
     * @deprecated Use hasBuild() instead
206
     * @return bool
207
     */
208 1
    public function isBuild(): bool
209
    {
210 1
        return !$this->build->isEmpty();
211
    }
212
213 15
    public function hasBuild(): bool
214
    {
215 15
        return !$this->build->isEmpty();
216
    }
217
218 1
    public function incrementMajor(): Version
219
    {
220 1
        return static::fromParts($this->major + 1, 0, 0, new NoPreRelease(), new NoBuild());
221
    }
222
223 2
    public function incrementMinor(): Version
224
    {
225 2
        return static::fromParts($this->major, $this->minor + 1, 0, new NoPreRelease(), new NoBuild());
226
    }
227
228 1
    public function incrementPatch(): Version
229
    {
230 1
        return static::fromParts($this->major, $this->minor, $this->patch + 1, new NoPreRelease(), new NoBuild());
231
    }
232
233
    /**
234
     * @param PreRelease|string|null $preRelease
235
     * @return Version
236
     */
237 2
    public function withPreRelease($preRelease): Version
238
    {
239 2
        if (is_string($preRelease)) {
240 2
            $preRelease = PreRelease::fromIdentifiersString($preRelease);
241
        }
242
243 2
        return static::fromParts($this->major, $this->minor, $this->patch, $preRelease, new NoBuild());
244
    }
245
246
    /**
247
     * @param Build|string|null $build
248
     * @return Version
249
     */
250 1
    public function withBuild($build): Version
251
    {
252 1
        if (is_string($build)) {
253 1
            $build = Build::fromIdentifiersString($build);
254
        }
255
256 1
        return static::fromParts($this->major, $this->minor, $this->patch, $this->preRelease, $build);
257
    }
258
259 4
    public function matches(Constraint $constraint): bool
260
    {
261 4
        return $constraint->assert($this);
262
    }
263
264 14
    public function toString(): string
265
    {
266
        return
267 14
            $this->major
268 14
            . '.' . $this->minor
269 14
            . '.' . $this->patch
270 14
            . ($this->isPreRelease() ? '-' . $this->preRelease : '')
271 14
            . ($this->hasBuild() ? '+' . $this->build : '')
272
        ;
273
    }
274
275 10
    public function __toString(): string
276
    {
277 10
        return $this->toString();
278
    }
279
280 4
    public function jsonSerialize(): string
281
    {
282 4
        return $this->toString();
283
    }
284
285 4
    public function toArray(): array
286
    {
287
        return [
288 4
            'major' => $this->major,
289 4
            'minor' => $this->minor,
290 4
            'patch' => $this->patch,
291 4
            'preRelease' => $this->preRelease->getIdentifiers(),
292 4
            'build' => $this->build->getIdentifiers(),
293
        ];
294
    }
295
296 1
    public static function setComparator(?Comparator $comparator): void
297
    {
298 1
        static::$comparator = $comparator;
299 1
    }
300
301 25
    protected function getComparator(): Comparator
302
    {
303 25
        if (null === static::$comparator) {
304 1
            static::$comparator = new SemverComparator();
305
        }
306
307 25
        return static::$comparator;
308
    }
309
}
310