Completed
Pull Request — master (#8)
by Nikola
04:18
created

Version::toArray()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 10
ccs 7
cts 7
cp 1
rs 9.4285
cc 1
eloc 7
nc 1
nop 0
crap 1
1
<?php
2
3
/**
4
 * This file is part of the Version package.
5
 *
6
 * Copyright (c) Nikola Posa <[email protected]>
7
 *
8
 * For full copyright and license information, please refer to the LICENSE file,
9
 * located at the package root folder.
10
 */
11
12
namespace Version;
13
14
use JsonSerializable;
15
use Version\Metadata\PreRelease;
16
use Version\Metadata\Build;
17
use Version\Exception\InvalidVersionElementException;
18
use Version\Exception\InvalidVersionStringException;
19
use Version\Constraint\ConstraintInterface;
20
use Version\Constraint\Constraint;
21
22
/**
23
 * @author Nikola Posa <[email protected]>
24
 */
25
final class Version implements JsonSerializable
26
{
27
    /**
28
     * @var int
29
     */
30
    private $major;
31
32
    /**
33
     * @var int
34
     */
35
    private $minor;
36
37
    /**
38
     * @var int
39
     */
40
    private $patch;
41
42
    /**
43
     * @var PreRelease
44
     */
45
    private $preRelease;
46
47
    /**
48
     * @var Build
49
     */
50
    private $build;
51
52 81
    private function __construct($major, $minor, $patch, PreRelease $preRelease, Build $build)
53
    {
54 81
        $this->major = $major;
55 81
        $this->minor = $minor;
56 81
        $this->patch = $patch;
57 81
        $this->preRelease = $preRelease;
58 81
        $this->build = $build;
59 81
    }
60
61
    /**
62
     * @param int $major
63
     * @param int $minor
64
     * @param int $patch
65
     * @param PreRelease|array|string $preRelease
66
     * @param Build|array|string $build
67
     * @return self
68
     */
69 85
    public static function fromAllElements($major, $minor, $patch, $preRelease, $build)
70
    {
71 85
        self::validateVersionElement('major', $major);
72
73 84
        self::validateVersionElement('minor', $minor);
74
75 83
        self::validateVersionElement('patch', $patch);
76
77 82
        if (!$preRelease instanceof PreRelease) {
78 34
            $preRelease = PreRelease::create($preRelease);
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $preRelease. This often makes code more readable.
Loading history...
79 33
        }
80
81 81
        if (!$build instanceof Build) {
82 13
            $build = Build::create($build);
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $build. This often makes code more readable.
Loading history...
83 13
        }
84
85 81
        return new self($major, $minor, $patch, $preRelease, $build);
86
    }
87
88 85
    private static function validateVersionElement($element, $value)
89
    {
90 85
        if (!is_int($value) || $value < 0) {
91 3
            throw InvalidVersionElementException::forElement($element);
92
        }
93 84
    }
94
95
    /**
96
     * @param int $major
97
     * @return self
98
     */
99 10
    public static function fromMajor($major)
100
    {
101 10
        return self::fromAllElements($major, 0, 0, PreRelease::createEmpty(), Build::createEmpty());
102
    }
103
104
    /**
105
     * @param int $major
106
     * @param int $minor
107
     * @return self
108
     */
109 2
    public static function fromMinor($major, $minor)
110
    {
111 2
        return self::fromAllElements($major, $minor, 0, PreRelease::createEmpty(), Build::createEmpty());
112
    }
113
114
    /**
115
     * @param int $major
116
     * @param int $minor
117
     * @param int $patch
118
     * @return self
119
     */
120 2
    public static function fromPatch($major, $minor, $patch)
121
    {
122 2
        return self::fromAllElements($major, $minor, $patch, PreRelease::createEmpty(), Build::createEmpty());
123
    }
124
125
    /**
126
     * @param int $major
127
     * @param int $minor
128
     * @param int $patch
129
     * @param @param PreRelease|array|string $preRelease
130
     * @return self
131
     */
132 1
    public static function fromPreRelease($major, $minor, $patch, $preRelease)
133
    {
134 1
        return self::fromAllElements($major, $minor, $patch, $preRelease, Build::createEmpty());
135
    }
136
137
    /**
138
     * @param int $major
139
     * @param int $minor
140
     * @param int $patch
141
     * @param Build|array|string $build
142
     * @return self
143
     */
144 1
    public static function fromBuild($major, $minor, $patch, $build)
145
    {
146 1
        return self::fromAllElements($major, $minor, $patch, PreRelease::createEmpty(), $build);
147
    }
148
149
    /**
150
     * @param string $versionString
151
     * @return self
152
     * @throws InvalidVersionStringException
153
     */
154 78
    public static function fromString($versionString)
155
    {
156 78
        $parts = [];
157
158 78
        if (!preg_match(
159
            '#^'
160
            . '(?P<core>(?:[0-9]|[1-9][0-9]+)(?:\.(?:[0-9]|[1-9][0-9]+)){2})'
161 78
            . '(?:\-(?P<preRelease>[0-9A-Za-z\-\.]+))?'
162 78
            . '(?:\+(?P<build>[0-9A-Za-z\-\.]+))?'
163 78
            . '$#',
164 78
            (string) $versionString,
165
            $parts
166 78
        )) {
167 4
            throw new InvalidVersionStringException("Version string is not valid and cannot be parsed");
168
        }
169
170 74
        list($major, $minor, $patch) = explode('.', $parts['core']);
171 74
        $major = (int) $major;
172 74
        $minor = (int) $minor;
173 74
        $patch = (int) $patch;
174
175 74
        $preRelease = (!empty($parts['preRelease'])) ? $parts['preRelease'] : PreRelease::createEmpty();
176
177 74
        $build = (!empty($parts['build'])) ? $parts['build'] : Build::createEmpty();
178
179 74
        return self::fromAllElements($major, $minor, $patch, $preRelease, $build);
180
    }
181
182
    /**
183
     * @return int
184
     */
185 18
    public function getMajor()
186
    {
187 18
        return $this->major;
188
    }
189
190
    /**
191
     * @return int
192
     */
193 18
    public function getMinor()
194
    {
195 18
        return $this->minor;
196
    }
197
198
    /**
199
     * @return int
200
     */
201 18
    public function getPatch()
202
    {
203 18
        return $this->patch;
204
    }
205
206
    /**
207
     * @return PreRelease
208
     */
209 9
    public function getPreRelease()
210
    {
211 9
        return $this->preRelease;
212
    }
213
214
    /**
215
     * @return Build
216
     */
217 7
    public function getBuild()
218
    {
219 7
        return $this->build;
220
    }
221
222
    /**
223
     * @return bool
224
     */
225 58
    public function isPreRelease()
226
    {
227 58
        return !$this->preRelease->isEmpty();
228
    }
229
230
    /**
231
     * @return bool
232
     */
233 42
    public function isBuild()
234
    {
235 42
        return !$this->build->isEmpty();
236
    }
237
238
    /**
239
     * @param self|string $version
240
     * @return int (1 if $this > $version, -1 if $this < $version, 0 if equal)
241
     */
242 41
    public function compareTo($version)
243
    {
244 41
        if (!$version instanceof self) {
245 29
            $version = self::fromString((string) $version);
1 ignored issue
show
Coding Style introduced by
Consider using a different name than the parameter $version. This often makes code more readable.
Loading history...
246 29
        }
247
248 41
        if ($this->major > $version->major) {
249 4
            return 1;
250
        }
251
252 40
        if ($this->major < $version->major) {
253 7
            return -1;
254
        }
255
256 37
        if ($this->minor > $version->minor) {
257 6
            return 1;
258
        }
259
260 33
        if ($this->minor < $version->minor) {
261 1
            return -1;
262
        }
263
264 33
        if ($this->patch > $version->patch) {
265 4
            return 1;
266
        }
267
268 30
        if ($this->patch < $version->patch) {
269
            return -1;
270
        }
271
272 30
        if (!$this->isPreRelease() && $version->isPreRelease()) {
273
            // normal version has greater precedence than a pre-release version version
274 4
            return 1;
275
        }
276
277 26
        if ($this->isPreRelease() && !$version->isPreRelease()) {
278
            // pre-release version has lower precedence than a normal version
279 1
            return -1;
280
        }
281
282 25
        if ($this->isPreRelease() && $version->isPreRelease()) {
283 16
            $result = $this->preRelease->compareTo($version->preRelease);
284
285 16
            if ($result > 0) {
286 12
                return 1;
287 4
            } elseif ($result < 0) {
288 2
                return -1;
289
            }
290 2
        }
291
292 11
        return 0;
293
    }
294
295
    /**
296
     * @param self|string $version
297
     * @return bool
298
     */
299 5
    public function isEqualTo($version)
300
    {
301 5
        return $this->compareTo($version) == 0;
302
    }
303
304
    /**
305
     * @param self|string $version
306
     * @return bool
307
     */
308 12
    public function isGreaterThan($version)
309
    {
310 12
        return $this->compareTo($version) > 0;
311
    }
312
313
    /**
314
     * @param self|string $version
315
     * @return bool
316
     */
317 3
    public function isGreaterOrEqualTo($version)
318
    {
319 3
        return $this->compareTo($version) >= 0;
320
    }
321
322
    /**
323
     * @param self|string $version
324
     * @return bool
325
     */
326 4
    public function isLessThan($version)
327
    {
328 4
        return $this->compareTo($version) < 0;
329
    }
330
331
    /**
332
     * @param self|string $version
333
     * @return bool
334
     */
335 3
    public function isLessOrEqualTo($version)
336
    {
337 3
        return $this->compareTo($version) <= 0;
338
    }
339
340
    /**
341
     * @param ConstraintInterface|string $constraint
342
     * @return bool
343
     */
344 2
    public function matches($constraint)
345
    {
346 2
        if (!$constraint instanceof ConstraintInterface) {
347 1
            $constraint = Constraint::fromString($constraint);
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $constraint. This often makes code more readable.
Loading history...
348 1
        }
349
350 2
        return $constraint->assert($this);
351
    }
352
353
    /**
354
     * @return self
355
     */
356 1
    public function withMajorIncremented()
357
    {
358 1
        return self::fromAllElements($this->major + 1, 0, 0, PreRelease::createEmpty(), Build::createEmpty());
359
    }
360
361
    /**
362
     * @return self
363
     */
364 2
    public function withMinorIncremented()
365
    {
366 2
        return self::fromAllElements($this->major, $this->minor + 1, 0, PreRelease::createEmpty(), Build::createEmpty());
367
    }
368
369
    /**
370
     * @return self
371
     */
372 1
    public function withPatchIncremented()
373
    {
374 1
        return self::fromAllElements($this->major, $this->minor, $this->patch + 1, PreRelease::createEmpty(), Build::createEmpty());
375
    }
376
377
    /**
378
     * @param PreRelease|array|string $preRelease
379
     * @return self
380
     */
381 2
    public function withPreRelease($preRelease)
382
    {
383 2
        return self::fromAllElements($this->major, $this->minor, $this->patch, $preRelease, Build::createEmpty());
384
    }
385
386
    /**
387
     * @param Build|array|string $build
388
     * @return self
389
     */
390 1
    public function withBuild($build)
391
    {
392 1
        return self::fromAllElements($this->major, $this->minor, $this->patch, $this->preRelease, $build);
393
    }
394
395
    /**
396
     * @return string
397
     */
398 28
    public function getVersionString()
399
    {
400
        return
401 28
            $this->major
402 28
            . '.' . $this->minor
403 28
            . '.' . $this->patch
404 28
            . ($this->isPreRelease() ? '-' . (string) $this->preRelease : '')
405 28
            . ($this->isBuild() ? '+' . (string) $this->build : '')
406 28
            ;
407
    }
408
409
    /**
410
     * @return string
411
     */
412 24
    public function __toString()
413
    {
414 24
        return $this->getVersionString();
415
    }
416
417
    /**
418
     * @return string
419
     */
420 4
    public function jsonSerialize()
421
    {
422 4
        return $this->getVersionString();
423
    }
424
425
    /**
426
     * @return array
427
     */
428 4
    public function toArray()
429
    {
430
        return [
431 4
            'major' => $this->major,
432 4
            'minor' => $this->minor,
433 4
            'patch' => $this->patch,
434 4
            'preRelease' => $this->preRelease->toArray(),
435 4
            'build' => $this->build->toArray(),
436 4
        ];
437
    }
438
}
439