Passed
Push — master ( a4db9e...071710 )
by Nelson
02:32
created

Version::getMinor()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
ccs 2
cts 2
cp 1
crap 1
1
<?php declare(strict_types=1);
2
/**
3
 * PHP: Nelson Martell Library file
4
 *
5
 * Copyright © 2015-2019 Nelson Martell (http://nelson6e65.github.io)
6
 *
7
 * Licensed under The MIT License (MIT)
8
 * For full copyright and license information, please see the LICENSE
9
 * Redistributions of files must retain the above copyright notice.
10
 *
11
 * @copyright 2015-2019 Nelson Martell
12
 * @link      http://nelson6e65.github.io/php_nml/
13
 * @since     0.1.1
14
 * @license   http://www.opensource.org/licenses/mit-license.php The MIT License (MIT)
15
 * */
16
17
namespace NelsonMartell;
18
19
use InvalidArgumentException;
20
21
/**
22
 * Representa el número de versión de un programa o ensamblado, de la forma "1.2.3.4". Sólo
23
 * siendo obligatorios el primer y segundo componente.
24
 * No se puede heredar esta clase.
25
 *
26
 * @author Nelson Martell <[email protected]>
27
 * @since 0.1.1
28
 *
29
 * @property-read int               $major    Obtiene el valor del componente principal del número de versión. Esta
30
 *   propiedad es de sólo lectura.
31
 * @property-read int               $minor    Obtiene el valor del componente secundario del número de versión. Esta
32
 *   propiedad es de sólo lectura.
33
 * @property-read VersionComponent  $build    Obtiene el valor del componente de compilación del número de versión.
34
 *   Esta propiedad es de sólo lectura.
35
 * @property-read VersionComponent  $revision Obtiene el valor del componente de revisión del número de versión. Esta
36
 *   propiedad es de sólo lectura.
37
 *
38
 * */
39
final class Version extends StrictObject implements IEquatable, IComparable, IMagicPropertiesContainer
40
{
41
    /**
42
     * The version metadata.
43
     *
44
     * @var array
45
     */
46
    private $versionMetaData = [];
47
48
    /**
49
     * Crea una nueva instancia con los números principal, secundario, de
50
     * compilación (opcional) y revisión (opcional).
51
     * Para comprobar si la versión es válida, usar el método isValid.
52
     *
53
     * @param int                              $major    Componente principal
54
     * @param int                              $minor    Componente secundario
55
     * @param int|string|VersionComponent|null $build    Componente de compilación
56
     * @param int|string|VersionComponent|null $revision Componente de revisión
57
     *
58
     * @throws InvalidArgumentException
59
     * */
60 27
    public function __construct(int $major, int $minor, $build = null, $revision = null)
61
    {
62 27
        parent::__construct();
63
64 27
        if ($major < 0) {
65
            $args = [
66 1
                'name'     => 'major',
67 1
                'pos'      => 0,
68 1
                'actual'   => $major,
69
            ];
70
71 1
            $msg  = msg('Invalid argument value.');
72 1
            $msg .= msg(
73 1
                ' "{name}" (position {pos}) must to be a positive number; "{actual}" given.',
74 1
                $args
75
            );
76
77 1
            throw new InvalidArgumentException($msg);
78
        }
79
80 26
        if ($minor < 0) {
81
            $args = [
82 1
                'name'     => 'minor',
83 1
                'pos'      => 1,
84 1
                'actual'   => $minor,
85
            ];
86
87 1
            $msg  = msg('Invalid argument value.');
88 1
            $msg .= msg(
89 1
                ' "{name}" (position {pos}) must to be a positive number; "{actual}" given.',
90 1
                $args
91
            );
92
93 1
            throw new InvalidArgumentException($msg);
94
        }
95
96 25
        $build    = VersionComponent::parse($build);
97 24
        $revision = VersionComponent::parse($revision);
98
99 22
        $this->versionMetaData = compact('major', 'minor', 'build', 'revision');
100 22
    }
101
102
    /**
103
     * Convierte una cadena a su representación del tipo Version.
104
     *
105
     * @param Version|string|int|float|array $value Objeto a convertir.
106
     *
107
     * @return Version Objeto convertido desde $value.
108
     * */
109 11
    public static function parse($value) : Version
110
    {
111 11
        if ($value instanceof Version) {
112
            return $value;
113
        }
114
115 11
        $version = [];
116
117
        // Try to convert into an array
118 11
        if (is_integer($value)) {
119
            // Integer for major value
120
            $version = [$value, 0];
121 11
        } elseif (is_float($value)) {
122
            // Integer part as major, and decimal part as minor
123
            $version = sprintf('%F', $value);
124
            $version = explode('.', $version);
125 11
        } elseif (is_array($value)) {
126
            // Implode first 4 places for major, minor, build and revision respectivally.
127 5
            $version = array_slice($value, 0, 4);
128 6
        } elseif (is_string($value)) {
0 ignored issues
show
introduced by
The condition is_string($value) is always true.
Loading history...
129 6
            $version = explode('.', $value);
130
        } else {
131
            $msg = msg('Unable to parse. Argument passed has an invalid type: "{0}".', typeof($value));
132
            throw new InvalidArgumentException($msg);
133
        }
134
135
        // $value ya debería ser un array.
136 11
        $c = count($version);
137
138 11
        if ($c > 4 || $c < 2) {
139 4
            $msg = msg('Unable to parse. Argument passed has an invalid format: "{0}".', $value);
140 4
            throw new InvalidArgumentException($msg);
141
        }
142
143
144 8
        $major    = (int) $version[0];
145 8
        $minor    = (int) $version[1];
146 8
        $build    = null;
147 8
        $revision = null;
148
149 8
        if (count($version) >= 3) {
150 6
            $build = VersionComponent::parse($version[2]);
151
152 6
            if (count($version) == 4) {
153 1
                $revision = VersionComponent::parse($version[3]);
154
            }
155
        }
156
157 8
        return new Version($major, $minor, $build, $revision);
158
    }
159
160
    /**
161
     * Getter for major property.
162
     *
163
     * @return int
164
     * @see    Version::$major
165
     */
166 41
    protected function getMajor()
167
    {
168 41
        return $this->versionMetaData['major'];
169
    }
170
171
    /**
172
     * Getter for minor property.
173
     *
174
     * @return int
175
     * @see    Version::$minor
176
     */
177 20
    protected function getMinor()
178
    {
179 20
        return $this->versionMetaData['minor'];
180
    }
181
182
    /**
183
     * Getter for build property.
184
     *
185
     * @return VersionComponent
186
     * @see    Version::$build
187
     */
188 32
    protected function getBuild() : VersionComponent
189
    {
190 32
        return $this->versionMetaData['build'];
191
    }
192
193
    /**
194
     * Getter for revision property.
195
     *
196
     * @return VersionComponent
197
     * @see    Version::$revision
198
     */
199 27
    protected function getRevision() : VersionComponent
200
    {
201 27
        return $this->versionMetaData['revision'];
202
    }
203
204
205
    /**
206
     * Convierte la instancia actual en su representación en cadena.
207
     * Por defecto, si no están definidos los componentes de compilación y
208
     * revisión, no se incluyen en la salida.
209
     * Use el método isValid si quiere determinar si la versión es válida
210
     * antes de devolver esta cadena.
211
     *
212
     * @return string Representación de la versión en forma de cadena:
213
     *   'major.minor[.build[.revision]]'
214
     * @see    VersionComponent::isNull()
215
     * @see    Version::isValid()
216
     * */
217 8
    public function toString() : string
218
    {
219 8
        $s[0] = $this->major;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$s was never initialized. Although not strictly required by PHP, it is generally a good practice to add $s = array(); before regardless.
Loading history...
220 8
        $s[1] = $this->minor;
221
222 8
        if ($this->revision->isNotNull()) {
223 3
            $s[2] = $this->build;
224 3
            $s[3] = $this->revision;
225
        } else {
226 5
            if ($this->build->isNotNull()) {
227 3
                $s[2] = $this->build;
228
            }
229
        }
230 8
        $v = implode('.', $s);
231
232 8
        return $v;
233
    }
234
235
    /**
236
     * Indica si la instancia actual es un número de versión válido.
237
     *
238
     * Se considera válido si:
239
     * 1. major o minor es mayor a cero (0). No puede ser '0.0'.
240
     * 2. build y revision son nulos (no están definidos).
241
     * 3. build está definido pero revision no.
242
     * 4. Ambos están definidos, pero no poseen la parte de la cadena.
243
     * 5. Ambos están definidos, pero build no posee la parte de cadena.
244
     * 6. build está definido y tiene la cadena, pero revision no está definido.
245
     * 7. revision posee cadena, pero build no.
246
     *
247
     * @return bool Un valor que indica si la instancia actual es válida.
248
     * */
249 16
    public function isValid() : bool
250
    {
251
        // Validación de major y minor:
252 16
        $r = ($this->major > 0 || $this->minor > 0); // 1
253
254
        // Validación de build y revision:
255 16
        if ($r) {
256 15
            $r = ($this->build->isNull() && $this->revision->isNull()); // 2
257
258 15
            if (!$r) {
259 13
                if ($this->build->isNotNull() && $this->revision->isNotNull()) {
260
                    // Si ambos están definidos...
261
262 9
                    $r = (bool) ($this->build->stringValue == ''); // 5
263
264 9
                    if (!$r) {
265
                        // 4
266 6
                        $r = (bool) (($this->build->stringValue == '') && ($this->revision->stringValue == ''));
267
268 6
                        if (!$r) {
269 6
                            if ($this->build->stringValue != '') {
270 6
                                $r = $this->revision->isNull(); // 6
271
                            }
272
273 6
                            if ($this->revision->stringValue != '') {
274 9
                                $r = ($this->build->stringValue == ''); // 7
275
                            }
276
                        }
277
                    }
278
                } else {
279 4
                    $r = ($this->build->isNotNull() && $this->revision->isNull()); // 3
280
                }
281
            }
282
        }
283
284 16
        return (bool) $r;
285
    }
286
287
    /**
288
     * Indicates whether the specified object is equal to the current instance.
289
     *
290
     * @param Version $other El otro objeto a comparar.
291
     *
292
     * @return bool `true` si $other es igual esta instancia; caso contrario,
293
     *   `false`.
294
     * */
295 32
    public function equals($other)
296
    {
297 32
        if ($other instanceof Version) {
0 ignored issues
show
introduced by
$other is always a sub-type of NelsonMartell\Version.
Loading history...
298 24
            if ($this->major == $other->major && $this->minor == $other->minor) {
299 16
                if ($this->build->equals($other->build)) {
300 11
                    if ($this->revision->equals($other->revision)) {
301 10
                        return true;
302
                    }
303
                }
304
            }
305
        }
306
307 29
        return false;
308
    }
309
310
311
    // region IComparable
312
313
    /**
314
     * Determina la posición relativa de esta instancia con respecto al objeto especificado.
315
     *
316
     * For types different than ``Version``:
317
     * - ``integer`` and ``null`` are always < 0;
318
     * - ``string`` and ``array`` are parsed and then evaluated (if is not parseable, always > 0);
319
     * - other types are always > 0
320
     *
321
     * @param Version|int|string|mixed $other
322
     *   The other object to compare with.
323
     *
324
     * @return int|null
325
     *   Returns:
326
     *   - ``= 0`` if this instance is considered equivalent to $other;
327
     *   - ``> 0`` si esta instancia se considera mayor a $other;
328
     *   - ``< 0`` si esta instancia se considera menor a $other.
329
     *   - ``null`` if this instance can't be compared against $other .
330
     * @see \NelsonMartell\Extensions\Objects::compare()
331
     * */
332 24
    public function compareTo($other)
333
    {
334 24
        $r = $this->equals($other) ? 0 : 9999;
0 ignored issues
show
Bug introduced by
It seems like $other can also be of type integer and string; however, parameter $other of NelsonMartell\Version::equals() does only seem to accept NelsonMartell\Version, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

334
        $r = $this->equals(/** @scrutinizer ignore-type */ $other) ? 0 : 9999;
Loading history...
335
336 24
        if (!($other instanceof Version)) {
337 17
            switch (typeof($other)->toString()) {
338 17
                case 'integer':
339 14
                case 'float':
340 14
                case 'double':
341 13
                case 'null':
342 13
                case 'NULL':
343 4
                    $r = 1; // Siempre es mayor a cualquier número o null
344 4
                    break;
345
346 13
                case 'string':
347 7
                case 'array':
348
                    // Se tratan de convertir las cadenas y arrays
349
                    try {
350 11
                        $tmp = Version::parse($other);
351 8
                        $r   = $this->compareTo($tmp);
352 4
                    } catch (InvalidArgumentException $e) {
353
                        // Siempre es mayor a strings o arrays que no se puedan convertir
354 4
                        $r = 1;
355
                    }
356 11
                    break;
357
358
                default:
359
                    // No se puede determinar comparando a otros objetos.
360 2
                    $r = null;
361
            }
362
363 17
            return $r;
364
        }
365
366 16
        if ($r !== 0) {
367 14
            $r = $this->major - $other->major;
368
369 14
            if ($r === 0) {
370 7
                $r = $this->minor - $other->minor;
371
372 7
                if ($r === 0) {
373 6
                    $r = $this->build->compareTo($other->build);
374
375 6
                    if ($r === 0) {
376 1
                        $r = $this->revision->compareTo($other->revision);
377
                    }
378
                }
379
            }
380
        }
381
382 16
        return $r;
383
    }
384
385
    // endregion
386
}
387