Passed
Push — master ( e9fb1f...55fa4a )
by Zhengchao
03:45
created

VersionComparator::compareStandardVersion()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 7
c 0
b 0
f 0
ccs 4
cts 4
cp 1
rs 9.4285
cc 1
eloc 4
nc 1
nop 2
crap 1
1
<?php
2
3
/*
4
 * This file is part of questocat/version-comparator package.
5
 *
6
 * (c) questocat <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace Questocat\VersionComparator;
13
14
/**
15
 * Compare the version number strings according to the "Semantic Versioning 2.0.0".
16
 *
17
 * @see http://semver.org Semantic Versioning
18
 */
19
class VersionComparator
20
{
21
    const COMPARE_LESS_THAN = -1;
22
    const COMPARE_EQUAL_TO = 0;
23
    const COMPARE_GREATER_THAN = 1;
24
25
    /**
26
     * Compares version number strings.
27
     *
28
     * returns -1 if the first version is lower than the second, 0 if they are equal, and 1 if the second is lower
29
     *
30
     * @param Version $version1
31
     * @param Version $version2
32
     *
33
     * @return int
34
     */
35 8
    public function versionCompare(Version $version1, Version $version2)
36
    {
37 8
        $compare = $this->compareStandardVersion($version1, $version2);
38
39 8
        if (0 == $compare) {
40 6
            $compare = $this->comparePreReleaseVersion($version1, $version2);
41 6
        }
42
43 8
        return $compare;
44
    }
45
46
    /**
47
     * Returns a Boolean value.
48
     *
49
     * Can use the comparison operator
50
     * <、 lt、<=、 le、>、 gt、>=、 ge、==、 =、eq、 !=、<> and ne
51
     *
52
     * @param int    $compare
53
     * @param string $operator
54
     *
55
     * @return bool|null
56
     */
57 3
    public function returnBool($compare, $operator)
58
    {
59 3
        $compareLen = strlen($operator);
60
61 3
        if (!strncmp($operator, '<', $compareLen) || !strncmp($operator, 'lt', $compareLen)) {
62 3
            return self::COMPARE_LESS_THAN == $compare;
63
        }
64
65 3 View Code Duplication
        if (!strncmp($operator, '<=', $compareLen) || !strncmp($operator, 'le', $compareLen)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
66 1
            return self::COMPARE_GREATER_THAN != $compare;
67
        }
68
69 3
        if (!strncmp($operator, '>', $compareLen) || !strncmp($operator, 'gt', $compareLen)) {
70 3
            return self::COMPARE_GREATER_THAN == $compare;
71
        }
72
73 2 View Code Duplication
        if (!strncmp($operator, '>=', $compareLen) || !strncmp($operator, 'ge', $compareLen)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
74 1
            return self::COMPARE_LESS_THAN != $compare;
75
        }
76
77 2 View Code Duplication
        if (!strncmp($operator, '==', $compareLen) || !strncmp($operator, '=', $compareLen) || !strncmp($operator, 'eq', $compareLen)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
78 2
            return self::COMPARE_EQUAL_TO == $compare;
79
        }
80
81 1 View Code Duplication
        if (!strncmp($operator, '!=', $compareLen) || !strncmp($operator, '<>', $compareLen) || !strncmp($operator, 'ne', $compareLen)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
82 1
            return self::COMPARE_EQUAL_TO != $compare;
83
        }
84
85 1
        return null;
86
    }
87
88
    /**
89
     * Compares the standard version.
90
     *
91
     * 1.0.0 < 2.0.0 < 2.1.0 < 2.1.1
92
     *
93
     * @param Version $version1
94
     * @param Version $version2
95
     *
96
     * @return int
97
     */
98 8
    protected function compareStandardVersion(Version $version1, Version $version2)
99
    {
100 8
        $version1Str = strval($version1->getMajor().$version1->getMinor().$version1->getPatch());
101 8
        $version2Str = strval($version2->getMajor().$version2->getMinor().$version2->getPatch());
102
103 8
        return version_compare($version1Str, $version2Str);
104
    }
105
106
    /**
107
     * Compares the pre-release version.
108
     *
109
     * 1.0.0-alpha < 1.0.0
110
     *
111
     * @param Version $version1
112
     * @param Version $version2
113
     *
114
     * @return int
115
     */
116 6
    protected function comparePreReleaseVersion(Version $version1, Version $version2)
117
    {
118 6
        $preRelease1 = $version1->getPreRelease();
119 6
        $preRelease2 = $version2->getPreRelease();
120
121 6
        if (!empty($preRelease1) || !empty($preRelease2)) {
122 6
            if (!empty($preRelease1) && empty($preRelease2)) {
123 1
                return self::COMPARE_LESS_THAN;
124
            }
125
126 6
            if (empty($preRelease1) && !empty($preRelease2)) {
127 3
                return self::COMPARE_GREATER_THAN;
128
            }
129
130 5
            $left = $preRelease1;
131 5
            $right = $preRelease2;
132 5
            $lt = self::COMPARE_LESS_THAN;
133 5
            $gt = self::COMPARE_GREATER_THAN;
134
135 5
            if (count($preRelease1) < count($preRelease2)) {
136 1
                $left = $preRelease2;
137 1
                $right = $preRelease1;
138 1
                $lt = self::COMPARE_GREATER_THAN;
139 1
                $gt = self::COMPARE_LESS_THAN;
140 1
            }
141
142 5
            foreach ($left as $index => $leftItem) {
143 5
                if (!isset($right[$index])) {
144 1
                    return $gt;
145
                }
146
147 5
                $rightItem = $right[$index];
148
149 5
                if ($leftItem == $rightItem) {
150 5
                    continue;
151
                }
152
153 4
                $leftIsNumeric = is_numeric($leftItem);
154 4
                $rightIsNumeric = is_numeric($rightItem);
155
156 4
                if ($leftIsNumeric && $rightIsNumeric) {
157 3
                    return $leftItem < $rightItem ? $lt : $gt;
158
                }
159
160 1
                if ($leftIsNumeric && !$rightIsNumeric) {
161 1
                    return $lt;
162
                }
163
164 1
                if (!$leftIsNumeric && $rightIsNumeric) {
165 1
                    return $gt;
166
                }
167
168 1
                $compare = strcmp($leftItem, $rightItem);
169
170 1
                if ($compare) {
171 1
                    return $compare > 0 ? $gt : $lt;
172
                }
173 3
            }
174 3
        }
175
176 3
        return self::COMPARE_EQUAL_TO;
177
    }
178
}
179