Completed
Push — master ( bbe9ae...ef0fc3 )
by Nikola
02:11
created

Version   B

Complexity

Total Complexity 45

Size/Duplication

Total Lines 285
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 45
lcom 1
cbo 9
dl 0
loc 285
c 0
b 0
f 0
ccs 99
cts 99
cp 1
rs 8.8

33 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 1
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 10 3
A __toString() 0 4 1
A jsonSerialize() 0 4 1
A toArray() 0 10 1
A setComparator() 0 4 1
A getComparator() 0 8 2

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