Completed
Push — master ( 9aa0e4...520f00 )
by Julien
02:19
created

VersionComparator::comparePreReleaseIdentifiers()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 19
rs 9.2
c 0
b 0
f 0
cc 4
eloc 11
nc 4
nop 2
1
<?php
2
3
/*
4
 * This file is part of semver/semver.
5
 *
6
 * (c) SemVer <https://github.com/git-pull-request>
7
 *
8
 * For the full copyright and license information, please view
9
 * the LICENSE file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace SemVer\SemVer;
15
16
/**
17
 * Compare two Version objects.
18
 */
19
final class VersionComparator
20
{
21
    /** @var Version */
22
    private $first;
23
    /** @var Version */
24
    private $second;
25
26
    /**
27
     * @param Version $first
28
     * @param Version $second
29
     */
30
    private function __construct(Version $first, Version $second)
31
    {
32
        $this->first  = $first;
33
        $this->second = $second;
34
    }
35
36
    /**
37
     * @param Version $first
38
     * @param Version $second
39
     *
40
     * @return int
41
     */
42
    public static function compare(Version $first, Version $second) : int
43
    {
44
        $obj = new self($first, $second);
45
46
        return $obj->doCompare();
47
    }
48
49
    /**
50
     * @return int
51
     */
52
    private function doCompare() : int
53
    {
54
        $compare = $this->compareNumericParts();
55
        if (0 !== $compare) {
56
            return $compare;
57
        }
58
59
        return $this->comparePreRelease();
60
    }
61
62
    /**
63
     * @return int
64
     */
65
    private function compareNumericParts() : int
66
    {
67
        $compare = $this->first->getMajor() <=> $this->second->getMajor();
68
        if (0 !== $compare) {
69
            return $compare;
70
        }
71
        $compare = $this->first->getMinor() <=> $this->second->getMinor();
72
        if (0 !== $compare) {
73
            return $compare;
74
        }
75
        $compare = $this->first->getPatch() <=> $this->second->getPatch();
76
77
        return $compare;
78
    }
79
80
    /**
81
     * @return int
82
     */
83
    private function comparePreRelease() : int
84
    {
85
        $preRelease1 = $this->first->getPreRelease();
86
        $preRelease2 = $this->second->getPreRelease();
87
88
        $leftPreReleaseIsEmpty  = '' === $preRelease1;
89
        $rightPreReleaseIsEmpty = '' === $preRelease2;
90
        if ($rightPreReleaseIsEmpty !== $leftPreReleaseIsEmpty) {
91
            return $leftPreReleaseIsEmpty ? 1 : -1;
92
        }
93
94
        if ($leftPreReleaseIsEmpty) {
95
            return 0;
96
        }
97
98
        return $this->comparePreReleaseIdentifiers(explode('.', $preRelease1), explode('.', $preRelease2));
99
    }
100
101
    /**
102
     * @param array $identifiers1
103
     * @param array $identifiers2
104
     *
105
     * @return int
106
     */
107
    private function comparePreReleaseIdentifiers(array $identifiers1, array $identifiers2) : int
108
    {
109
        $preReleasePart1 = array_shift($identifiers1);
110
        $preReleasePart2 = array_shift($identifiers2);
111
        if (null === $preReleasePart2) {
112
            return (int) (null !== $preReleasePart1);
113
        }
114
115
        if (null === $preReleasePart1) {
116
            return -1;
117
        }
118
119
        $compare = $this->comparePreReleaseIdentifier($preReleasePart1, $preReleasePart2);
120
        if (0 === $compare) {
121
            return $this->comparePreReleaseIdentifiers($identifiers1, $identifiers2);
122
        }
123
124
        return $compare;
125
    }
126
127
    /**
128
     * @param $identifier1
129
     * @param $identifier2
130
     *
131
     * @return int
132
     */
133
    private function comparePreReleaseIdentifier($identifier1, $identifier2) : int
134
    {
135
        $mineIsInt  = $this->isIdentifierInt($identifier1);
136
        $theirIsInt = $this->isIdentifierInt($identifier2);
137
138
        if ($mineIsInt !== $theirIsInt) {
139
            return $mineIsInt ? -1 : 1;
140
        }
141
142
        if ($mineIsInt) {
143
            return ((int) $identifier1) <=> ((int) $identifier2);
144
        }
145
146
        return $identifier1 <=> $identifier2;
147
    }
148
149
    /**
150
     * @param string $identifier
151
     *
152
     * @return bool
153
     */
154
    private function isIdentifierInt(string $identifier) : bool
155
    {
156
        return ctype_digit($identifier) && strpos($identifier, '00') !== 0;
157
    }
158
}
159