Completed
Push — master ( a2c643...e562f7 )
by Nelson
04:00
created

Version::getMajor()   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
2
/**
3
 * PHP: Nelson Martell Library file
4
 *
5
 * Content:
6
 * - Class definition:  [NelsonMartell]  Version
7
 *
8
 * Copyright © 2015-2017 Nelson Martell (http://nelson6e65.github.io)
9
 *
10
 * Licensed under The MIT License (MIT)
11
 * For full copyright and license information, please see the LICENSE
12
 * Redistributions of files must retain the above copyright notice.
13
 *
14
 * @copyright 2015-2017 Nelson Martell
15
 * @link      http://nelson6e65.github.io/php_nml/
16
 * @since     0.1.1
17
 * @license   http://www.opensource.org/licenses/mit-license.php The MIT License (MIT)
18
 * */
19
20
namespace NelsonMartell;
21
22
use \InvalidArgumentException;
23
24
/**
25
 * Representa el número de versión de un programa o ensamblado, de la forma "1.2.3.4". Sólo
26
 * siendo obligatorios el primer y segundo componente.
27
 * No se puede heredar esta clase.
28
 *
29
 * @author Nelson Martell <[email protected]>
30
 * @since 0.1.1
31
 * */
32
final class Version extends StrictObject implements IEquatable, IComparable
33
{
34
35
    /**
36
     * Crea una nueva instancia con los números principal, secundario, de
37
     * compilación (opcional) y revisión (opcional).
38
     * Para comprobar si la versión es válida, usar el método isValid.
39
     *
40
     * @param int                              $major    Componente principal
41
     * @param int                              $minor    Componente secundario
42
     * @param int|string|VersionComponent|null $build    Componente de compilación
43
     * @param int|string|VersionComponent|null $revision Componente de revisión
44
     *
45
     * @throws InvalidArgumentException
46
     * */
47 32
    public function __construct($major, $minor, $build = null, $revision = null)
48
    {
49 32
        parent::__construct();
50 32
        unset($this->Major, $this->Minor, $this->Build, $this->Revision);
51
52 32
        if (!is_integer($major)) {
0 ignored issues
show
introduced by
The condition is_integer($major) is always true.
Loading history...
53
            $args = [
54 3
                'class'    => typeof($this)->Name,
55 3
                'name'     => 'major',
56 3
                'pos'      => 0,
57 3
                'expected' => typeof(0),
58 3
                'actual'   => typeof($major),
59
            ];
60
61 3
            $msg = msg('Invalid argument type.');
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 2 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
62 3
            $msg .= msg(
63 3
                ' "{name}" (position {pos}) must to be an instance of "{expected}"; "{actual}" given.',
1 ignored issue
show
Coding Style introduced by
This line exceeds maximum limit of 100 characters; contains 103 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
64 3
                $args
65
            );
66 3
            $msg .= msg(' Convert value or use the "{class}::parse" (static) method.', $args);
67
68 3
            throw new InvalidArgumentException($msg);
69
        }
70
71 29
        if (!is_integer($minor)) {
0 ignored issues
show
introduced by
The condition is_integer($minor) is always true.
Loading history...
72
            $args = [
73 2
                'class'    => typeof($this)->Name,
74 2
                'name'     => 'minor',
75 2
                'pos'      => 1,
76 2
                'expected' => typeof(0),
77 2
                'actual'   => typeof($minor),
78
            ];
79
80 2
            $msg = msg('Invalid argument type.');
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 2 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
81 2
            $msg .= msg(
82 2
                ' "{name}" (position {pos}) must to be an instance of "{expected}"; "{actual}" given.',
1 ignored issue
show
Coding Style introduced by
This line exceeds maximum limit of 100 characters; contains 103 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
83 2
                $args
84
            );
85 2
            $msg .= msg(' Convert value or use the "{class}::parse" (static) method.', $args);
86
87 2
            throw new InvalidArgumentException($msg);
88
        }
89
90 27
        if ($major < 0) {
91
            $args = [
92 1
                'name'     => 'major',
93 1
                'pos'      => 0,
94 1
                'actual'   => $major,
95
            ];
96
97 1
            $msg = msg('Invalid argument value.');
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 2 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
98 1
            $msg .= msg(
99 1
                ' "{name}" (position {pos}) must to be a positive number; "{actual}" given.',
100 1
                $args
101
            );
102
103 1
            throw new InvalidArgumentException($msg);
104
        }
105
106 26
        if ($minor < 0) {
107
            $args = [
108 1
                'name'     => 'minor',
109 1
                'pos'      => 1,
110 1
                'actual'   => $minor,
111
            ];
112
113 1
            $msg = msg('Invalid argument value.');
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 2 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
114 1
            $msg .= msg(
115 1
                ' "{name}" (position {pos}) must to be a positive number; "{actual}" given.',
116 1
                $args
117
            );
118
119 1
            throw new InvalidArgumentException($msg);
120
        }
121
122 25
        $this->major = $major;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
123 25
        $this->minor = $minor;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
124 25
        $this->build = VersionComponent::parse($build);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
125 24
        $this->revision = VersionComponent::parse($revision);
126 22
    }
127
128
    /**
129
     * Convierte una cadena a su representación del tipo Version.
130
     *
131
     * @param Version|string|int|float|array $value Objeto a convertir.
132
     *
133
     * @return Version Objeto convertido desde $value.
134
     * */
135 11
    public static function parse($value)
136
    {
137 11
        if ($value instanceof Version) {
138
            return $value;
139
        }
140
141 11
        $version = [];
142
143
        // Try to convert into an array
144 11
        if (is_integer($value)) {
145
            // Integer for major value
146
            $version = [$value, 0];
147 11
        } elseif (is_float($value)) {
148
            // Integer part as major, and decimal part as minor
149
            $version = sprintf("%F", $value);
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal %F does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
150
            $version = explode('.', $version);
151 11
        } elseif (is_array($value)) {
152
            // Implode first 4 places for major, minor, build and revision respectivally.
153 5
            $version = array_slice($value, 0, 4);
154 6
        } elseif (is_string($value)) {
0 ignored issues
show
introduced by
The condition is_string($value) is always true.
Loading history...
155 6
            $version = explode('.', $value);
156
        } else {
157
            $msg = msg('Unable to parse. Argument passed has an invalid type: "{0}".', typeof($value));
1 ignored issue
show
Coding Style introduced by
This line exceeds maximum limit of 100 characters; contains 103 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
158
            throw new InvalidArgumentException($msg);
159
        }
160
161
        // $value ya debería ser un array.
162 11
        $c = count($version);
163
164 11
        if ($c > 4 || $c < 2) {
165 3
            $msg = msg('Unable to parse. Argument passed has an invalid format: "{0}".', $value);
166
            //var_dump($version);
167 3
            throw new InvalidArgumentException($msg);
168
        }
169
170
171 8
        $major = (int) $version[0];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
172 8
        $minor = (int) $version[1];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
173 8
        $build = null;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
174 8
        $revision = null;
175
176 8
        if (count($version) >= 3) {
177 6
            $build = VersionComponent::Parse($version[2]);
178
179 6
            if (count($version) == 4) {
180 1
                $revision = VersionComponent::Parse($version[3]);
181
            }
182
        }
183
184 8
        return new Version($major, $minor, $build, $revision);
185
    }
186
187
    /**
188
     * Obtiene el valor del componente principal del número de versión del
189
     * objeto actual.
190
     * Esta propiedad es de sólo lectura.
191
     *
192
     * @var int Componente principal del número de versión.
193
     * */
194
    public $Major;
195
    private $major;
196
197
    /**
198
     * Getter for Major property.
199
     *
200
     * @return int
201
     * @see    Version::$major
202
     */
203 57
    public function getMajor()
204
    {
205 57
        return $this->major;
206
    }
207
208
209
    /**
210
     * Obtiene el valor del componente secundario del número de versión del
211
     * objeto actual.
212
     * Esta propiedad es de sólo lectura.
213
     *
214
     * @var int Componente secundario del número de versión.
215
     * */
216
    public $Minor;
217
    private $minor;
218
219
    /**
220
     * Getter for minor property.
221
     *
222
     * @return int
223
     * @see    Version::$minor
224
     */
225 36
    public function getMinor()
226
    {
227 36
        return $this->minor;
228
    }
229
230
    /**
231
     * Obtiene el valor del componente de compilación del número de versión
232
     * del objeto actual.
233
     * Esta propiedad es de sólo lectura.
234
     *
235
     * @var VersionComponent Componente de compilación del número de versión.
236
     * */
237
    public $Build;
238
    private $build;
239
240
    /**
241
     * Getter for Build property.
242
     *
243
     * @return VersionComponent
244
     * @see    Version::$build
245
     */
246 48
    public function getBuild()
247
    {
248 48
        return $this->build;
249
    }
250
251
    /**
252
     * Obtiene el valor del componente de revisión del número de versión del
253
     * objeto actual.
254
     * Esta propiedad es de sólo lectura.
255
     *
256
     * @var VersionComponent Componente de revisión del número de versión.
257
     * */
258
    public $Revision;
259
    private $revision;
260
261
    /**
262
     * Getter for Revision property.
263
     *
264
     * @return VersionComponent
265
     * @see    Version::$revision
266
     */
267 43
    public function getRevision()
268
    {
269 43
        return $this->revision;
270
    }
271
272
273
    /**
274
     * Convierte la instancia actual en su representación en cadena.
275
     * Por defecto, si no están definidos los componentes de compilación y
276
     * revisión, no se incluyen en la salida.
277
     * Use el método isValid si quiere determinar si la versión es válida
278
     * antes de devolver esta cadena.
279
     *
280
     * @return string Representación de la versión en forma de cadena:
281
     *   'major.minor[.build[.revision]]'
282
     * @see    VersionComponent::isNull()
283
     * @see    Version::isValid()
284
     * */
285 16
    public function toString()
286
    {
287 16
        $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...
288 16
        $s[1] = $this->Minor;
289
290 16
        if ($this->Revision->isNotNull()) {
291 6
            $s[2] = $this->Build;
292 6
            $s[3] = $this->Revision;
293
        } else {
294 10
            if ($this->Build->isNotNull()) {
295 6
                $s[2] = $this->Build;
296
            }
297
        }
298 16
        $v = implode('.', $s);
299
300 16
        return $v;
301
    }
302
303
    /**
304
     * Indica si la instancia actual es un número de versión válido.
305
     *
306
     * Se considera válido si:
307
     * 1. Major o Minor es mayor a cero (0). No puede ser '0.0'.
308
     * 2. Build y Revision son nulos (no están definidos).
309
     * 3. Build está definido pero Revision no.
310
     * 4. Ambos están definidos, pero no poseen la parte de la cadena.
311
     * 5. Ambos están definidos, pero Build no posee la parte de cadena.
312
     * 6. Build está definido y tiene la cadena, pero Revision no está definido.
313
     * 7. Revision posee cadena, pero Build no.
314
     *
315
     * @return bool Un valor que indica si la instancia actual es válida.
316
     * */
317 16
    public function isValid()
318
    {
319
        // Validación de Major y Minor:
320 16
        $r = ($this->Major > 0 or $this->Minor > 0); //#1
321
322
        // Validación de Build y Revision:
323 16
        if ($r) {
324 15
            $r = ($this->Build->isNull() and $this->Revision->isNull()); // #2
325
326 15
            if (!$r) {
327 13
                if ($this->Build->isNotNull() and $this->Revision->isNotNull()) {
328
                    // Si ambos están definidos...
329
330 9
                    $r = (bool) ($this->Build->StringValue == ''); //#5
331
332 9
                    if (!$r) {
333
                        //#4
334 6
                        $r = (bool) (($this->Build->StringValue == '') and ($this->Revision->StringValue == ''));
1 ignored issue
show
Coding Style introduced by
This line exceeds maximum limit of 100 characters; contains 113 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
335
336 6
                        if (!$r) {
337 6
                            if ($this->Build->StringValue != '') {
338 6
                                $r = $this->Revision->isNull(); #6
0 ignored issues
show
Coding Style introduced by
Perl-style comments are not allowed. Use "// Comment." or "/* comment */" instead.
Loading history...
339
                            }
340
341 6
                            if ($this->Revision->StringValue != '') {
342 9
                                $r = ($this->Build->StringValue == ''); #7
0 ignored issues
show
Coding Style introduced by
Perl-style comments are not allowed. Use "// Comment." or "/* comment */" instead.
Loading history...
343
                            }
344
                        }
345
                    }
346
                } else {
347 4
                    $r = ($this->Build->isNotNull() and $this->Revision->isNull()); //#3
348
                }
349
            }
350
        }
351
352 16
        return (bool) $r;
353
    }
354
355
    /**
356
     * Determina si el objeto $other especificado es igual a la instancia actual.
357
     *
358
     * @param Version $other El otro objeto a comparar.
359
     *
360
     * @return bool `true` si $other es igual esta instancia; caso contrario,
361
     *   `false`.
362
     * */
363 32
    public function equals($other)
364
    {
365 32
        if ($other instanceof Version) {
0 ignored issues
show
introduced by
$other is always a sub-type of NelsonMartell\Version.
Loading history...
366 24
            if ($this->Major == $other->Major && $this->Minor == $other->Minor) {
367 16
                if ($this->Build->equals($other->Build)) {
368 11
                    if ($this->Revision->equals($other->Revision)) {
369 10
                        return true;
370
                    }
371
                }
372
            }
373
        }
374
375 29
        return false;
376
    }
377
378
379
    #region IComparable
0 ignored issues
show
Coding Style introduced by
Perl-style comments are not allowed. Use "// Comment." or "/* comment */" instead.
Loading history...
380
381
    /**
382
     * Determina la posición relativa de esta instancia con respecto al objeto especificado.
383
     *
384
     * For types different than ``Version``:
385
     * - ``integer`` and ``null`` are always < 0;
386
     * - ``string`` and ``array`` are parsed and then evaluated (if is not parseable, always > 0);
387
     * - other types are always > 0
388
     *
389
     * @param Version|int|string|mixed $other
390
     *   The other object to compare with.
391
     *
392
     * @return int|null
393
     *   Returns:
394
     *   - ``= 0`` if this instance is considered equivalent to $other;
395
     *   - ``> 0`` si esta instancia se considera mayor a $other;
396
     *   - ``< 0`` si esta instancia se considera menor a $other.
397
     *   - ``null`` if this instance can't be compared against $other .
398
     * @see StrictObject::compare()
399
     * */
400 24
    public function compareTo($other)
401
    {
402 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

402
        $r = $this->equals(/** @scrutinizer ignore-type */ $other) ? 0 : 9999;
Loading history...
403
404 24
        if (!($other instanceof Version)) {
405 17
            switch (typeof($other)->toString()) {
406 17
                case 'integer':
407 14
                case 'float':
408 14
                case 'double':
409 13
                case 'null':
410 13
                case 'NULL':
411 4
                    $r = 1; // Siempre es mayor a cualquier número o null
412 4
                    break;
413
414 13
                case 'string':
415 7
                case 'array':
416
                    // Se tratan de convertir las cadenas y arrays
417
                    try {
418 11
                        $tmp = Version::parse($other);
419 8
                        $r = $this->compareTo($tmp);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
420 3
                    } catch (InvalidArgumentException $e) {
421
                        // Siempre es mayor a strings o arrays que no se puedan convertir
422 3
                        $r = 1;
423
                    }
424 11
                    break;
425
426
                default:
427
                    // No se puede determinar comparando a otros objetos.
428 2
                    $r = null;
429
            }
430
431 17
            return $r;
432
        }
433
434 16
        if ($r !== 0) {
435 14
            $r = $this->Major - $other->Major;
436
437 14
            if ($r === 0) {
438 7
                $r = $this->Minor - $other->Minor;
439
440 7
                if ($r === 0) {
441 6
                    $r = $this->Build->compareTo($other->Build);
442
443 6
                    if ($r === 0) {
444 1
                        $r = $this->Revision->compareTo($other->Revision);
445
                    }
446
                }
447
            }
448
        }
449
450 16
        return $r;
451
    }
452
453
    #endregion
0 ignored issues
show
Coding Style introduced by
Perl-style comments are not allowed. Use "// Comment." or "/* comment */" instead.
Loading history...
454
}
455