Completed
Push — master ( 560cb9...87ab65 )
by Nikola
02:55
created

Version   B

Complexity

Total Complexity 48

Size/Duplication

Total Lines 263
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 97.98%

Importance

Changes 0
Metric Value
wmc 48
lcom 1
cbo 7
dl 0
loc 263
ccs 97
cts 99
cp 0.9798
rs 8.5599
c 0
b 0
f 0

32 Methods

Rating   Name   Duplication   Size   Complexity  
A __toString() 0 4 1
A jsonSerialize() 0 4 1
A setComparator() 0 4 1
A getComparator() 0 8 2
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 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 __construct() 0 12 1
A from() 0 4 1
A fromString() 0 17 6
A toString() 0 11 3
A toArray() 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\Assert\VersionAssert;
9
use Version\Extension\Build;
10
use Version\Exception\InvalidVersionString;
11
use Version\Comparison\Comparator;
12
use Version\Comparison\SemverComparator;
13
use Version\Comparison\Constraint\Constraint;
14
use Version\Extension\PreRelease;
15
16
class Version implements JsonSerializable
17
{
18
    public const REGEX = '#^(?P<prefix>v|release\-)?(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:\-(?P<preRelease>(?:0|[1-9]\d*|\d*[a-zA-Z\-][0-9a-zA-Z\-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z\-][0-9a-zA-Z\-]*))*))?(?:\+(?P<build>[0-9a-zA-Z\-]+(?:\.[0-9a-zA-Z\-]+)*))?$#';
19
20
    protected $major;
21
    protected $minor;
22
    protected $patch;
23
    protected $preRelease;
24
    protected $build;
25
26
    protected $prefix;
27
28
    protected static $comparator;
29
30 86
    final protected function __construct(int $major, int $minor, int $patch, PreRelease $preRelease = null, Build $build = null)
31
    {
32 86
        VersionAssert::that($major)->greaterOrEqualThan(0, 'Major version must be positive integer');
33 85
        VersionAssert::that($minor)->greaterOrEqualThan(0, 'Minor version must be positive integer');
34 84
        VersionAssert::that($patch)->greaterOrEqualThan(0, 'Patch version must be positive integer');
35
36 83
        $this->major = $major;
37 83
        $this->minor = $minor;
38 83
        $this->patch = $patch;
39 83
        $this->preRelease = $preRelease;
40 83
        $this->build = $build;
41 83
    }
42
43 28
    public static function from(int $major, int $minor = 0, int $patch = 0, PreRelease $preRelease = null, Build $build = null)
44
    {
45 28
        return new static($major, $minor, $patch, $preRelease, $build);
46
    }
47
48
    /**
49
     * @throws InvalidVersionString
50
     */
51 84
    public static function fromString(string $versionString)
52
    {
53 84
        if (!preg_match(self::REGEX, $versionString, $parts)) {
54 4
            throw InvalidVersionString::notParsable($versionString);
55
        }
56
57 80
        $version = new static(
58 80
            (int) $parts['major'],
59 80
            (int) $parts['minor'],
60 80
            (int) $parts['patch'],
61 80
            (isset($parts['preRelease']) && '' !== $parts['preRelease']) ? PreRelease::fromString($parts['preRelease']) : null,
62 80
            (isset($parts['build']) && '' !== $parts['build']) ? Build::fromString($parts['build']) : null
63
        );
64 80
        $version->prefix = $parts['prefix'] ?? '';
65
66 80
        return $version;
67
    }
68
69 57
    public function getMajor(): int
70
    {
71 57
        return $this->major;
72
    }
73
74 57
    public function getMinor(): int
75
    {
76 57
        return $this->minor;
77
    }
78
79 57
    public function getPatch(): int
80
    {
81 57
        return $this->patch;
82
    }
83
84 18
    public function getPreRelease(): ?PreRelease
85
    {
86 18
        return $this->preRelease;
87
    }
88
89 6
    public function getBuild(): ?Build
90
    {
91 6
        return $this->build;
92
    }
93
94
    /**
95
     * @param Version|string $version
96
     * @return bool
97
     */
98 6
    public function isEqualTo($version): bool
99
    {
100 6
        return $this->compareTo($version) === 0;
101
    }
102
103
    /**
104
     * @param Version|string $version
105
     * @return bool
106
     */
107 1
    public function isNotEqualTo($version): bool
108
    {
109 1
        return !$this->isEqualTo($version);
110
    }
111
112
    /**
113
     * @param Version|string $version
114
     * @return bool
115
     */
116 3
    public function isGreaterThan($version): bool
117
    {
118 3
        return $this->compareTo($version) > 0;
119
    }
120
121
    /**
122
     * @param Version|string $version
123
     * @return bool
124
     */
125 4
    public function isGreaterOrEqualTo($version): bool
126
    {
127 4
        return $this->compareTo($version) >= 0;
128
    }
129
130
    /**
131
     * @param Version|string $version
132
     * @return bool
133
     */
134 3
    public function isLessThan($version): bool
135
    {
136 3
        return $this->compareTo($version) < 0;
137
    }
138
139
    /**
140
     * @param Version|string $version
141
     * @return bool
142
     */
143 2
    public function isLessOrEqualTo($version): bool
144
    {
145 2
        return $this->compareTo($version) <= 0;
146
    }
147
148
    /**
149
     * @param Version|string $version
150
     * @return int (1 if $this > $version, -1 if $this < $version, 0 if equal)
151
     */
152 23
    public function compareTo($version): int
153
    {
154 23
        if (is_string($version)) {
155 7
            $version = static::fromString($version);
156
        }
157
158 23
        return $this->getComparator()->compare($this, $version);
159
    }
160
161 2
    public function isMajorRelease(): bool
162
    {
163 2
        return $this->major > 0 && $this->minor === 0 && $this->patch === 0;
164
    }
165
166 1
    public function isMinorRelease(): bool
167
    {
168 1
        return $this->minor > 0 && $this->patch === 0;
169
    }
170
171 1
    public function isPatchRelease(): bool
172
    {
173 1
        return $this->patch > 0;
174
    }
175
176 70
    public function isPreRelease(): bool
177
    {
178 70
        return null !== $this->preRelease;
179
    }
180
181 49
    public function hasBuild(): bool
182
    {
183 49
        return null !== $this->build;
184
    }
185
186 1
    public function incrementMajor(): Version
187
    {
188 1
        return new static($this->major + 1, 0, 0);
189
    }
190
191 2
    public function incrementMinor(): Version
192
    {
193 2
        return new static($this->major, $this->minor + 1, 0);
194
    }
195
196 1
    public function incrementPatch(): Version
197
    {
198 1
        return new static($this->major, $this->minor, $this->patch + 1);
199
    }
200
201
    /**
202
     * @param PreRelease|string|null $preRelease
203
     * @return Version
204
     */
205 2
    public function withPreRelease($preRelease): Version
206
    {
207 2
        if (is_string($preRelease)) {
208 2
            $preRelease = PreRelease::fromString($preRelease);
209
        }
210
211 2
        return new static($this->major, $this->minor, $this->patch, $preRelease);
212
    }
213
214
    /**
215
     * @param Build|string|null $build
216
     * @return Version
217
     */
218 1
    public function withBuild($build): Version
219
    {
220 1
        if (is_string($build)) {
221 1
            $build = Build::fromString($build);
222
        }
223
224 1
        return new static($this->major, $this->minor, $this->patch, $this->preRelease, $build);
225
    }
226
227 2
    public function matches(Constraint $constraint): bool
228
    {
229 2
        return $constraint->assert($this);
230
    }
231
232 21
    public function toString(): string
233
    {
234
        return
235 21
            $this->prefix
236 21
            . $this->major
237 21
            . '.' . $this->minor
238 21
            . '.' . $this->patch
239 21
            . ($this->isPreRelease() ? '-' . $this->preRelease->toString() : '')
240 21
            . ($this->hasBuild() ? '+' . $this->build->toString() : '')
241
        ;
242
    }
243
244
    public function __toString(): string
245
    {
246
        return $this->toString();
247
    }
248
249 4
    public function jsonSerialize(): string
250
    {
251 4
        return $this->toString();
252
    }
253
254 4
    public function toArray(): array
255
    {
256
        return [
257 4
            'major' => $this->major,
258 4
            'minor' => $this->minor,
259 4
            'patch' => $this->patch,
260 4
            'preRelease' => $this->isPreRelease() ? $this->preRelease->getIdentifiers() : null,
261 4
            'build' => $this->hasBuild() ? $this->build->getIdentifiers() : null,
262
        ];
263
    }
264
265 1
    public static function setComparator(?Comparator $comparator): void
266
    {
267 1
        static::$comparator = $comparator;
268 1
    }
269
270 23
    protected function getComparator(): Comparator
271
    {
272 23
        if (null === static::$comparator) {
273 1
            static::$comparator = new SemverComparator();
274
        }
275
276 23
        return static::$comparator;
277
    }
278
}
279