Completed
Push — master ( 8d7014...4fa85a )
by brian
05:27
created

ComparatorVersionParser::hasIllegalTokens()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 19
ccs 7
cts 7
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 12
nc 3
nop 1
crap 3
1
<?php
2
3
/**
4
 * @copyright   (c) 2014-2017 brian ridley
5
 * @author      brian ridley <[email protected]>
6
 * @license     http://opensource.org/licenses/MIT MIT
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace ptlis\SemanticVersion\Parse\Matcher;
13
14
use ptlis\SemanticVersion\Comparator\ComparatorFactory;
15
use ptlis\SemanticVersion\Parse\Token;
16
use ptlis\SemanticVersion\Version\VersionBuilder;
17
use ptlis\SemanticVersion\VersionRange\ComparatorVersion;
18
use ptlis\SemanticVersion\VersionRange\VersionRangeInterface;
19
20
/**
21
 * Comparator versions store a comparator & version specifying part of a version range.
22
 */
23
final class ComparatorVersionParser implements RangeParserInterface
24
{
25
    /**
26
     * @var ComparatorFactory
27
     */
28
    private $comparatorFactory;
29
30
    /**
31
     * @var VersionBuilder
32
     */
33
    private $versionBuilder;
34
35
36
    /**
37
     * Constructor.
38
     *
39
     * @param ComparatorFactory $comparatorFactory
40
     * @param VersionBuilder $versionBuilder
41
     */
42 5
    public function __construct(
43
        ComparatorFactory $comparatorFactory,
44
        VersionBuilder $versionBuilder
45
    ) {
46 5
        $this->comparatorFactory = $comparatorFactory;
47 5
        $this->versionBuilder = $versionBuilder;
48 5
    }
49
50
    /**
51
     * Returns true if the tokens can be parsed as a ComparatorVersion.
52
     *
53
     * @param Token[] $tokenList
54
     *
55
     * @return boolean
56
     */
57 5
    public function canParse(array $tokenList)
58
    {
59 5
        $canParse = false;
60
61
        // No illegal tokens present
62 5
        if (!$this->hasIllegalTokens($tokenList)) {
63 5
            $chunkedList = $this->chunk($tokenList);
64
65
            if (
66 5
                1 === count($chunkedList)
67 5
                || (2 === count($chunkedList) && Token::LABEL_STRING === $chunkedList[1][0]->getType())
68
            ) {
69 5
                $canParse = true;
70
            }
71
        }
72
73 5
        return $canParse;
74
    }
75
76
    /**
77
     * Build a ComparatorVersion representing the comparator & version.
78
     *
79
     * @param Token[] $tokenList
80
     *
81
     * @return VersionRangeInterface
82
     */
83 5
    public function parse(array $tokenList)
84
    {
85
        $comparatorList = [
86 5
            '<',
87
            '<=',
88
            '>',
89
            '>=',
90
            '='
91
        ];
92
93
        // Prefixed comparator, hydrate & remove
94 5
        if (count($tokenList) > 0 && in_array($tokenList[0]->getValue(), $comparatorList)) {
95 4
            $comparator = $this->comparatorFactory->get($tokenList[0]->getValue());
96 4
            $tokenList = array_slice($tokenList, 1);
97
98
        // Default to equality
99
        } else {
100 1
            $comparator = $this->comparatorFactory->get('=');
101
        }
102
103 5
        $chunkList = $this->chunk($tokenList);
104 5
        $versionTokenList = $chunkList[0];
105 5
        $labelTokenList = [];
106 5
        if (count($chunkList) > 1) {
107 1
            $labelTokenList = $chunkList[1];
108
        }
109
110 5
        return new ComparatorVersion(
111
            $comparator,
0 ignored issues
show
Bug introduced by
It seems like $comparator can be null; however, __construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
112 5
            $this->versionBuilder->buildFromTokens($versionTokenList, $labelTokenList)
0 ignored issues
show
Bug introduced by
It seems like $this->versionBuilder->b...nList, $labelTokenList) can be null; however, __construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
113
        );
114
    }
115
116
    /**
117
     * Returns true if an illegal token is found.
118
     *
119
     * @param Token[] $tokenList
120
     *
121
     * @return boolean
122
     */
123 5
    public function hasIllegalTokens(array $tokenList)
124
    {
125
        $illegalTokenList = [
126 5
            Token::CARET_RANGE,
127
            Token::TILDE_RANGE,
128
            Token::WILDCARD_DIGITS,
129
            Token::LOGICAL_AND,
130
            Token::LOGICAL_OR
131
        ];
132
133 5
        $hasIllegalToken = false;
134 5
        foreach ($tokenList as $token) {
135 5
            if (in_array($token->getType(), $illegalTokenList)) {
136 5
                $hasIllegalToken = true;
137
            }
138
        }
139
140 5
        return $hasIllegalToken;
141
    }
142
143
    /**
144
     * Chuck the tokens, splitting on hyphen.
145
     *
146
     * @todo Copy & pasted from hyphenated range parser
147
     *
148
     * @param Token[] $tokenList
149
     *
150
     * @return Token[][]
151
     */
152 5
    private function chunk(array $tokenList)
153
    {
154 5
        $tokenListCount = count($tokenList);
155 5
        $chunkedList = [];
156 5
        $accumulator = [];
157
158 5
        for ($i = 0; $i < $tokenListCount; $i++) {
159 5
            $token = $tokenList[$i];
160
161
            // Accumulate until we hit a dash
162 5
            if (Token::DASH_SEPARATOR !== $token->getType()) {
163 5
                $accumulator[] = $token;
164
1 ignored issue
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
165
            } else {
166 1
                $chunkedList[] = $accumulator;
167 1
                $accumulator = [];
168
            }
169
        }
170
171 5
        if (count($accumulator)) {
172 5
            $chunkedList[] = $accumulator;
173
        }
174
175 5
        return $chunkedList;
176
    }
177
}
178