GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 5fc822...87ff31 )
by Norbert
9s
created

ArrayMatcher::arrayPropertyExists()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 5
rs 9.2
cc 4
eloc 3
nc 5
nop 2
1
<?php
2
3
namespace Coduo\PHPMatcher\Matcher;
4
5
use Coduo\PHPMatcher\Parser;
6
use Coduo\ToString\StringConverter;
7
use Symfony\Component\PropertyAccess\PropertyAccess;
8
use Symfony\Component\PropertyAccess\PropertyAccessor;
9
use Symfony\Component\PropertyAccess\PropertyPath;
10
11
final class ArrayMatcher extends Matcher
12
{
13
    const UNBOUNDED_PATTERN = '@...@';
14
15
    /**
16
     * @var ValueMatcher
17
     */
18
    private $propertyMatcher;
19
20
    /**
21
     * @var PropertyAccessor
22
     */
23
    private $accessor;
24
25
    /**
26
     * @var Parser
27
     */
28
    private $parser;
29
30
    /**
31
     * @param ValueMatcher $propertyMatcher
32
     */
33
    public function __construct(ValueMatcher $propertyMatcher, Parser $parser)
34
    {
35
        $this->propertyMatcher = $propertyMatcher;
36
        $this->parser = $parser;
37
    }
38
39
    /**
40
     * {@inheritDoc}
41
     */
42
    public function match($value, $pattern)
43
    {
44
        if (parent::match($value, $pattern)) {
45
            return true;
46
        }
47
48
        if (!is_array($value)) {
49
            $this->error = sprintf("%s \"%s\" is not a valid array.", gettype($value), new StringConverter($value));
50
            return false;
51
        }
52
53
        if ($this->isArrayPattern($pattern)) {
54
            return $this->allExpandersMatch($value, $pattern);
55
        }
56
57
        if (false === $this->iterateMatch($value, $pattern)) {
58
            return false;
59
        }
60
61
        return true;
62
    }
63
64
    /**
65
     * {@inheritDoc}
66
     */
67
    public function canMatch($pattern)
68
    {
69
        return is_array($pattern) || $this->isArrayPattern($pattern);
70
    }
71
72
    private function isArrayPattern($pattern)
73
    {
74
        if (!is_string($pattern)) {
75
            return false;
76
        }
77
78
        return $this->parser->hasValidSyntax($pattern) && $this->parser->parse($pattern)->is('array');
79
    }
80
81
    /**
82
     * @param  array $values
83
     * @param  array $patterns
84
     * @param string $parentPath
85
     * @return bool
86
     */
87
    private function iterateMatch(array $values, array $patterns, $parentPath = "")
88
    {
89
        $pattern = null;
90
        foreach ($values as $key => $value) {
91
            $path = $this->formatAccessPath($key);
92
93
            if ($this->shouldSkippValueMatchingFor($pattern)) {
94
                continue;
95
            }
96
97
            if ($this->valueExist($path, $patterns)) {
98
                $pattern = $this->getValueByPath($patterns, $path);
99
            } else {
100
                $this->setMissingElementInError('pattern', $this->formatFullPath($parentPath, $path));
101
                return false;
102
            }
103
104
            if ($this->shouldSkippValueMatchingFor($pattern)) {
105
                continue;
106
            }
107
108
            if ($this->valueMatchPattern($value, $pattern)) {
109
                continue;
110
            }
111
112
            if (!is_array($value) || !$this->canMatch($pattern)) {
113
                return false;
114
            }
115
116
            if ($this->isArrayPattern($pattern)) {
117
                if (!$this->allExpandersMatch($value, $pattern)) {
118
                    return false;
119
                }
120
121
                continue;
122
            }
123
124
            if (false === $this->iterateMatch($value, $pattern, $this->formatFullPath($parentPath, $path))) {
125
                return false;
126
            }
127
        }
128
129
        if (!$this->isPatternValid($patterns, $values, $parentPath)) {
130
            return false;
131
        }
132
133
        return true;
134
    }
135
136
    /**
137
     * Check if pattern elements exist in value array
138
     *
139
     * @param array $pattern
140
     * @param array $values
141
     * @param $parentPath
142
     * @return bool
143
     */
144
    private function isPatternValid(array $pattern, array $values, $parentPath)
145
    {
146
        if (is_array($pattern)) {
147
            $notExistingKeys = array_diff_key($pattern, $values);
148
149
            if (count($notExistingKeys) > 0) {
150
                $keyNames = array_keys($notExistingKeys);
151
                $path = $this->formatFullPath($parentPath, $this->formatAccessPath($keyNames[0]));
152
                $this->setMissingElementInError('value', $path);
153
                return false;
154
            }
155
        }
156
157
        return true;
158
    }
159
160
    /**
161
     * @param $value
162
     * @param $pattern
163
     * @return bool
164
     */
165
    private function valueMatchPattern($value, $pattern)
166
    {
167
        $match = $this->propertyMatcher->canMatch($pattern) &&
168
            true === $this->propertyMatcher->match($value, $pattern);
169
170
        if (!$match) {
171
            $this->error = $this->propertyMatcher->getError();
172
        }
173
174
        return $match;
175
    }
176
177
    /**
178
     * @param $path
179
     * @param $haystack
180
     * @return bool
181
     */
182
    private function valueExist($path, array $haystack)
183
    {
184
        $propertyPath = new PropertyPath($path);
185
        $length = $propertyPath->getLength();
186
        $valueExist = true;
187
        for ($i = 0; $i < $length; ++$i) {
188
            $property = $propertyPath->getElement($i);
189
            $isIndex = $propertyPath->isIndex($i);
190
            $propertyExist = $this->arrayPropertyExists($property, $haystack);
191
192
            if ($isIndex && !$propertyExist) {
193
                $valueExist = false;
194
                break;
195
            }
196
        }
197
198
        unset($propertyPath);
199
        return $valueExist;
200
    }
201
202
    /**
203
     * @param string $property
204
     * @param array $objectOrArray
205
     * @return bool
206
     */
207
    private function arrayPropertyExists($property, array $objectOrArray)
208
    {
209
        return ($objectOrArray instanceof \ArrayAccess && isset($objectOrArray[$property])) ||
210
            (is_array($objectOrArray) && array_key_exists($property, $objectOrArray));
211
    }
212
213
    /**
214
     * @param $array
215
     * @param $path
216
     * @return mixed
217
     */
218
    private function getValueByPath($array, $path)
219
    {
220
        return $this->getPropertyAccessor()->getValue($array, $path);
221
    }
222
223
    /**
224
     * @return \Symfony\Component\PropertyAccess\PropertyAccessorInterface
225
     */
226
    private function getPropertyAccessor()
227
    {
228
        if (isset($this->accessor)) {
229
            return $this->accessor;
230
        }
231
232
        $accessorBuilder = PropertyAccess::createPropertyAccessorBuilder();
233
        $this->accessor = $accessorBuilder->getPropertyAccessor();
234
235
        return $this->accessor;
236
    }
237
238
    /**
239
     * @param $place
240
     * @param $path
241
     */
242
    private function setMissingElementInError($place, $path)
243
    {
244
        $this->error = sprintf('There is no element under path %s in %s.', $path, $place);
245
    }
246
247
    /**
248
     * @param $key
249
     * @return string
250
     */
251
    private function formatAccessPath($key)
252
    {
253
        return sprintf("[%s]", $key);
254
    }
255
256
    /**
257
     * @param $parentPath
258
     * @param $path
259
     * @return string
260
     */
261
    private function formatFullPath($parentPath, $path)
262
    {
263
        return sprintf("%s%s", $parentPath, $path);
264
    }
265
266
    /**
267
     * @param $lastPattern
268
     * @return bool
269
     */
270
    private function shouldSkippValueMatchingFor($lastPattern)
271
    {
272
        return $lastPattern === self::UNBOUNDED_PATTERN;
273
    }
274
275
    /**
276
     * @param $value
277
     * @param $pattern
278
     * @return bool
279
     * @throws \Coduo\PHPMatcher\Exception\UnknownExpanderException
280
     */
281
    private function allExpandersMatch($value, $pattern)
282
    {
283
        $typePattern = $this->parser->parse($pattern);
284
        if (!$typePattern->matchExpanders($value)) {
285
            $this->error = $typePattern->getError();
286
            return false;
287
        }
288
289
        return true;
290
    }
291
}
292