1+ <?php
2+
3+ namespace z4kn4fein \SemVer ;
4+
5+ class PreRelease
6+ {
7+ /** @var array */
8+ private $ preReleaseParts ;
9+
10+ /**
11+ * @return PreRelease The incremented prerelease
12+ */
13+ public function increment ()
14+ {
15+ $ result = $ this ->copy ();
16+ $ lastNumericIndex = 0 ;
17+ foreach ($ result ->preReleaseParts as $ key => $ part ) {
18+ if (is_numeric ($ part )) {
19+ $ lastNumericIndex = $ key ;
20+ }
21+ }
22+
23+ if ($ lastNumericIndex != 0 ) {
24+ $ result ->preReleaseParts [$ lastNumericIndex ] = intval ($ result ->preReleaseParts [$ lastNumericIndex ]) + 1 ;
25+ } else {
26+ $ result ->preReleaseParts [] = 0 ;
27+ }
28+
29+ return $ result ;
30+ }
31+
32+ /**
33+ * @return string The string representation of the prerelease.
34+ */
35+ public function __toString ()
36+ {
37+ return implode ('. ' , $ this ->preReleaseParts );
38+ }
39+
40+ private function copy ()
41+ {
42+ $ result = new PreRelease ();
43+ $ result ->preReleaseParts = $ this ->preReleaseParts ;
44+ return $ result ;
45+ }
46+
47+ /**
48+ * @throws VersionFormatException When the $preReleaseString is invalid.
49+ */
50+ private function validate ()
51+ {
52+ foreach ($ this ->preReleaseParts as $ part ) {
53+ if ($ this ->hasOnlyNumbers ($ part )) {
54+ if (strlen ($ part ) > 1 && $ part [0 ] == "0 " ) {
55+ throw new VersionFormatException (sprintf ("The prerelease part '%s' is numeric but contains a leading zero. " , $ part ));
56+ } else {
57+ continue ;
58+ }
59+ }
60+
61+ if (!$ this ->hasOnlyAlphanumericsAndHyphen ($ part )) {
62+ throw new VersionFormatException (sprintf ("The prerelease part '%s' contains invalid character. " , $ part ));
63+ }
64+ }
65+ }
66+
67+ /**
68+ * @param $part string part to check.
69+ * @return bool True when the part is containing only numbers.
70+ */
71+ private function hasOnlyNumbers ($ part )
72+ {
73+ return !preg_match ("/[^0-9]/ " , $ part );
74+ }
75+
76+ /**
77+ * @param $part string The part to check.
78+ * @return bool True when the part is only containing alphanumerics.
79+ */
80+ private function hasOnlyAlphanumericsAndHyphen ($ part )
81+ {
82+ return !preg_match ("/[^0-9A-Za-z-]/ " , $ part );
83+ }
84+
85+ /**
86+ * @param $preReleaseString string The prerelease string.
87+ * @return PreRelease The parsed prerelease part.
88+ * @throws VersionFormatException When the given prerelease string is invalid.
89+ */
90+ public static function parse ($ preReleaseString )
91+ {
92+ $ preReleaseString = trim ($ preReleaseString );
93+ if ($ preReleaseString == null || $ preReleaseString == "" ) {
94+ throw new VersionFormatException ("preReleaseString cannot be empty. " );
95+ }
96+
97+ $ preRelease = new PreRelease ();
98+
99+ $ preRelease ->preReleaseParts = explode ('. ' , $ preReleaseString );
100+ $ preRelease ->validate ();
101+
102+ return $ preRelease ;
103+ }
104+
105+ /**
106+ * @param $p1 string|PreRelease The left side of the comparison.
107+ * @param $p2 string|PreRelease The right side of the comparison.
108+ * @return int -1 when $p1 < $p2, 0 when $p1 == $p2, 1 when $p1 > $p2.
109+ * @throws VersionFormatException When the given prerelease values are invalid.
110+ */
111+ public static function compare ($ p1 , $ p2 )
112+ {
113+ if (!$ p1 instanceof PreRelease) {
114+ $ p1 = self ::parse ($ p1 );
115+ }
116+
117+ if (!$ p2 instanceof PreRelease) {
118+ $ p2 = self ::parse ($ p2 );
119+ }
120+
121+ $ v1Size = count ($ p1 ->preReleaseParts );
122+ $ v2Size = count ($ p2 ->preReleaseParts );
123+
124+ $ count = $ v1Size > $ v2Size ? $ v2Size : $ v1Size ;
125+
126+ for ($ i = 0 ; $ i < $ count ; $ i ++) {
127+ $ part = self ::comparePart ($ p1 ->preReleaseParts [$ i ], $ p2 ->preReleaseParts [$ i ]);
128+ if ($ part != 0 ) {
129+ return $ part ;
130+ }
131+ }
132+
133+ return Utils::comparePrimitive ($ v1Size , $ v2Size );
134+ }
135+
136+ /**
137+ * @param $a mixed The left side of the comparison.
138+ * @param $b mixed The right side of the comparison.
139+ * @return int -1 when $a < $b, 0 when $a == $b, 1 when $v1 > $b.
140+ */
141+ private static function comparePart ($ a , $ b )
142+ {
143+ if (is_numeric ($ a ) && !is_numeric ($ b )) {
144+ return -1 ;
145+ }
146+
147+ if (!is_numeric ($ a ) && is_numeric ($ b )) {
148+ return 1 ;
149+ }
150+
151+ return is_numeric ($ a ) && is_numeric ($ b )
152+ ? Utils::comparePrimitive (intval ($ a ), intval ($ b ))
153+ : Utils::comparePrimitive ($ a , $ b );
154+ }
155+ }
0 commit comments