This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Flying\Struct\Property; |
||
4 | |||
5 | use Flying\Struct\Common\ComplexPropertyInterface; |
||
6 | use Flying\Struct\Exception; |
||
7 | |||
8 | /** |
||
9 | * Basic implementation of collection of elements as structure property |
||
10 | * Code of this class is partially taken from Doctrine\Common\Collections\Collection |
||
11 | * with respect to authors of original code |
||
12 | */ |
||
13 | class Collection extends Property implements ComplexPropertyInterface, \IteratorAggregate |
||
14 | { |
||
15 | /** |
||
16 | * Collection elements |
||
17 | * |
||
18 | * @var array |
||
19 | */ |
||
20 | private $elements = []; |
||
21 | /** |
||
22 | * Cached value of "allowed" configuration option |
||
23 | * |
||
24 | * @var array |
||
25 | */ |
||
26 | private $allowed; |
||
27 | |||
28 | /** |
||
29 | * {@inheritdoc} |
||
30 | * @return array |
||
31 | */ |
||
32 | 1 | public function getValue() |
|
33 | { |
||
34 | 1 | return $this->elements; |
|
35 | } |
||
36 | |||
37 | /** |
||
38 | * {@inheritdoc} |
||
39 | * @throws \InvalidArgumentException |
||
40 | */ |
||
41 | 46 | public function setValue($value) |
|
42 | { |
||
43 | 46 | if (!is_array($value)) { |
|
44 | 6 | if (is_object($value) && method_exists($value, 'toArray')) { |
|
45 | 1 | $value = $value->toArray(); |
|
46 | 1 | } else { |
|
47 | 5 | throw new \InvalidArgumentException('Only array values are accepted for collections'); |
|
48 | } |
||
49 | 1 | } |
|
50 | 41 | $elements = []; |
|
51 | 41 | foreach ((array)$value as $k => $v) { |
|
52 | 38 | if ($this->normalize($v, $k)) { |
|
53 | 38 | $elements[$k] = $v; |
|
54 | 38 | } |
|
55 | 41 | } |
|
56 | 41 | if (count($value) && (!count($elements))) { |
|
57 | // There is no valid elements into given value |
||
58 | 8 | $this->onInvalidValue($value); |
|
59 | 8 | return false; |
|
60 | } |
||
61 | |||
62 | 41 | $this->elements = $elements; |
|
63 | 41 | $this->onChange(); |
|
64 | 41 | return true; |
|
65 | } |
||
66 | |||
67 | /** |
||
68 | * Normalize given value to make it compatible with property requirements |
||
69 | * |
||
70 | * @param mixed $value Given property value (passed by reference) |
||
71 | * @param int|string $key OPTIONAL Key for given value in a case if multiple values are given |
||
72 | * @return boolean TRUE if value can be accepted, FALSE otherwise |
||
73 | */ |
||
74 | 96 | protected function normalize(&$value, $key = null) |
|
0 ignored issues
–
show
|
|||
75 | { |
||
76 | 96 | if (!parent::normalize($value)) { |
|
77 | 1 | return false; |
|
78 | } |
||
79 | 96 | $allowed = $this->allowed; |
|
80 | 96 | if (is_callable($allowed) && (!$allowed($value))) { |
|
81 | 2 | return false; |
|
82 | } |
||
83 | 96 | if (is_string($allowed) && ((!is_object($value)) || (!$value instanceof $allowed))) { |
|
84 | 2 | return false; |
|
85 | } |
||
86 | 95 | if (is_array($allowed) && (!is_callable($allowed)) && (!in_array($value, $allowed, true))) { |
|
87 | 22 | return false; |
|
88 | } |
||
89 | 90 | return true; |
|
90 | } |
||
91 | |||
92 | /** |
||
93 | * Invalid value setting handler |
||
94 | * |
||
95 | * @param mixed $value Invalid value given to property |
||
96 | * @param int|string $key OPTIONAL Key of this value |
||
97 | * @return void |
||
98 | */ |
||
99 | 25 | protected function onInvalidValue($value, $key = null) |
|
0 ignored issues
–
show
|
|||
100 | { |
||
101 | |||
102 | 25 | } |
|
103 | |||
104 | /** |
||
105 | * Toggle given element in collection. |
||
106 | * Adds element in collection if it is missed, removes if it is available |
||
107 | * |
||
108 | * @param mixed $element The element to toggle. |
||
109 | * @return void |
||
110 | * @throws \RuntimeException |
||
111 | */ |
||
112 | 7 | public function toggle($element) |
|
113 | { |
||
114 | 7 | if ($this->normalize($element)) { |
|
115 | // contains() and other methods are not used here |
||
116 | // to avoid performance penalty from multiple calls to normalize() |
||
117 | 7 | if (in_array($element, $this->elements, true)) { |
|
118 | // Copy from removeElement() |
||
119 | 4 | $changed = false; |
|
120 | View Code Duplication | do { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
121 | 4 | $key = array_search($element, $this->elements, true); |
|
122 | 4 | if ($key !== false) { |
|
123 | 4 | unset($this->elements[$key]); |
|
124 | 4 | $changed = true; |
|
125 | 4 | } |
|
126 | 4 | } while ($key !== false); |
|
127 | 4 | if ($changed) { |
|
128 | 4 | $this->onChange(); |
|
129 | 4 | } |
|
130 | 4 | } else { |
|
131 | // Copy from add() |
||
132 | 4 | $this->elements[] = $element; |
|
133 | 4 | $this->onChange(); |
|
134 | } |
||
135 | 7 | } else { |
|
136 | 2 | $this->onInvalidValue($element); |
|
137 | } |
||
138 | 7 | } |
|
139 | |||
140 | /** |
||
141 | * Removes the specified element from the collection, if it is found. |
||
142 | * |
||
143 | * @param mixed $element The element to remove. |
||
144 | * @return boolean TRUE if this collection contained the specified element, FALSE otherwise. |
||
145 | * @throws \RuntimeException |
||
146 | */ |
||
147 | 6 | public function removeElement($element) |
|
148 | { |
||
149 | 6 | $changed = false; |
|
150 | 6 | if (!$this->normalize($element)) { |
|
151 | 2 | $this->onInvalidValue($element); |
|
152 | 2 | return $changed; |
|
153 | } |
||
154 | View Code Duplication | do { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
155 | 6 | $key = array_search($element, $this->elements, true); |
|
156 | 6 | if ($key !== false) { |
|
157 | 4 | unset($this->elements[$key]); |
|
158 | 4 | $changed = true; |
|
159 | 4 | } |
|
160 | 6 | } while ($key !== false); |
|
161 | 6 | if ($changed) { |
|
162 | 4 | $this->onChange(); |
|
163 | 4 | } |
|
164 | 6 | return $changed; |
|
165 | } |
||
166 | |||
167 | /** |
||
168 | * Checks whether an element is contained in the collection. |
||
169 | * |
||
170 | * @param mixed $element The element to search for. |
||
171 | * @return boolean |
||
172 | */ |
||
173 | 4 | public function contains($element) |
|
174 | { |
||
175 | 4 | if (!$this->normalize($element)) { |
|
176 | 1 | return false; |
|
177 | } |
||
178 | 4 | return in_array($element, $this->elements, true); |
|
179 | } |
||
180 | |||
181 | /** |
||
182 | * Gets the index/key of a given element. |
||
183 | * |
||
184 | * @param mixed $element The element to search for. |
||
185 | * @return int|string|boolean The key/index of the element or FALSE if the element was not found. |
||
186 | */ |
||
187 | 4 | public function indexOf($element) |
|
188 | { |
||
189 | 4 | if (!$this->normalize($element)) { |
|
190 | 1 | return false; |
|
191 | } |
||
192 | 4 | return array_search($element, $this->elements, true); |
|
193 | } |
||
194 | |||
195 | /** |
||
196 | * Gets all keys/indices of the collection. |
||
197 | * |
||
198 | * @return array |
||
199 | */ |
||
200 | 1 | public function getKeys() |
|
201 | { |
||
202 | 1 | return array_keys($this->elements); |
|
203 | } |
||
204 | |||
205 | /** |
||
206 | * Gets all values of the collection. |
||
207 | * |
||
208 | * @return array |
||
209 | */ |
||
210 | 3 | public function getValues() |
|
211 | { |
||
212 | 3 | return array_values($this->elements); |
|
213 | } |
||
214 | |||
215 | /** |
||
216 | * Checks whether the collection is empty. |
||
217 | * |
||
218 | * @return boolean |
||
219 | */ |
||
220 | 2 | public function isEmpty() |
|
221 | { |
||
222 | 2 | return !$this->elements; |
|
223 | } |
||
224 | |||
225 | /** |
||
226 | * Clears the collection, removing all elements. |
||
227 | * |
||
228 | * @return void |
||
229 | * @throws \RuntimeException |
||
230 | */ |
||
231 | 4 | public function clear() |
|
232 | { |
||
233 | 4 | $this->elements = []; |
|
234 | 4 | $this->onChange(); |
|
235 | 4 | } |
|
236 | |||
237 | /** |
||
238 | * {@inheritdoc} |
||
239 | */ |
||
240 | 20 | public function count() |
|
241 | { |
||
242 | 20 | return count($this->elements); |
|
243 | } |
||
244 | |||
245 | /** |
||
246 | * {@inheritdoc} |
||
247 | */ |
||
248 | 2 | public function getIterator() |
|
249 | { |
||
250 | 2 | return new \ArrayIterator($this->elements); |
|
251 | } |
||
252 | |||
253 | /** |
||
254 | * {@inheritDoc} |
||
255 | */ |
||
256 | 4 | public function offsetExists($offset) |
|
257 | { |
||
258 | 4 | return $this->containsKey($offset); |
|
259 | } |
||
260 | |||
261 | /** |
||
262 | * Checks whether the collection contains an element with the specified key/index. |
||
263 | * |
||
264 | * @param string|integer $key The key/index to check for. |
||
265 | * @return boolean |
||
266 | */ |
||
267 | 8 | public function containsKey($key) |
|
268 | { |
||
269 | 8 | return array_key_exists($key, $this->elements) || isset($this->elements[$key]); |
|
270 | } |
||
271 | |||
272 | /** |
||
273 | * {@inheritDoc} |
||
274 | */ |
||
275 | 2 | public function offsetGet($offset) |
|
276 | { |
||
277 | 2 | return $this->get($offset); |
|
278 | } |
||
279 | |||
280 | /** |
||
281 | * Gets the element at the specified key/index. |
||
282 | * |
||
283 | * @param string|integer $key The key/index of the element to retrieve. |
||
284 | * @return mixed |
||
285 | */ |
||
286 | 3 | public function get($key) |
|
287 | { |
||
288 | 3 | if (array_key_exists($key, $this->elements)) { |
|
289 | 3 | return $this->elements[$key]; |
|
290 | } |
||
291 | 1 | return null; |
|
292 | } |
||
293 | |||
294 | /** |
||
295 | * {@inheritDoc} |
||
296 | * @throws \RuntimeException |
||
297 | */ |
||
298 | 9 | public function offsetSet($offset, $value) |
|
299 | { |
||
300 | 9 | if ($offset !== null) { |
|
301 | 4 | $this->set($offset, $value); |
|
302 | 4 | } else { |
|
303 | 6 | $this->add($value); |
|
304 | } |
||
305 | 9 | } |
|
306 | |||
307 | /** |
||
308 | * Sets an element in the collection at the specified key/index. |
||
309 | * |
||
310 | * @param string|integer $key The key/index of the element to set. |
||
311 | * @param mixed $element The element to set. |
||
312 | * @return void |
||
313 | * @throws \RuntimeException |
||
314 | */ |
||
315 | 8 | public function set($key, $element) |
|
316 | { |
||
317 | 8 | if ($this->normalize($element)) { |
|
318 | 8 | $this->elements[$key] = $element; |
|
319 | 8 | $this->onChange(); |
|
320 | 8 | } else { |
|
321 | 2 | $this->onInvalidValue($element, $key); |
|
322 | } |
||
323 | 8 | } |
|
324 | |||
325 | /** |
||
326 | * Adds an element at the end of the collection. |
||
327 | * |
||
328 | * @param mixed $element The element to add. |
||
329 | * @return void |
||
330 | * @throws \RuntimeException |
||
331 | */ |
||
332 | 26 | public function add($element) |
|
333 | { |
||
334 | 26 | if ($this->normalize($element)) { |
|
335 | 20 | $this->elements[] = $element; |
|
336 | 20 | $this->onChange(); |
|
337 | 20 | } else { |
|
338 | 14 | $this->onInvalidValue($element); |
|
339 | } |
||
340 | 26 | } |
|
341 | |||
342 | /** |
||
343 | * {@inheritDoc} |
||
344 | * @throws \RuntimeException |
||
345 | */ |
||
346 | 6 | public function offsetUnset($offset) |
|
347 | { |
||
348 | 6 | $this->remove($offset); |
|
349 | 6 | } |
|
350 | |||
351 | /** |
||
352 | * Removes the element at the specified index from the collection. |
||
353 | * |
||
354 | * @param string|integer $key The kex/index of the element to remove. |
||
355 | * @return mixed The removed element or NULL, if the collection did not contain the element. |
||
356 | * @throws \RuntimeException |
||
357 | */ |
||
358 | 12 | public function remove($key) |
|
359 | { |
||
360 | 12 | if (array_key_exists($key, $this->elements) || isset($this->elements[$key])) { |
|
361 | 7 | $removed = $this->elements[$key]; |
|
362 | 7 | unset($this->elements[$key]); |
|
363 | 7 | $this->onChange(); |
|
364 | 7 | return $removed; |
|
365 | } |
||
366 | 8 | return null; |
|
367 | } |
||
368 | |||
369 | /** |
||
370 | * {@inheritdoc} |
||
371 | */ |
||
372 | 22 | public function toArray() |
|
373 | { |
||
374 | 22 | return $this->elements; |
|
375 | } |
||
376 | |||
377 | /** |
||
378 | * {@inheritdoc} |
||
379 | * @throws \InvalidArgumentException |
||
380 | */ |
||
381 | 108 | public function validateConfig($name, &$value) |
|
382 | { |
||
383 | switch ($name) { |
||
384 | 108 | View Code Duplication | case 'default': |
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
385 | 33 | if (!is_array($value)) { |
|
386 | 7 | if (is_object($value) && method_exists($value, 'toArray')) { |
|
387 | 1 | $value = $value->toArray(); |
|
388 | 1 | } else { |
|
389 | 6 | throw new \InvalidArgumentException('Only arrays are accepted as default values for collection properties'); |
|
390 | } |
||
391 | 1 | } |
|
392 | 27 | break; |
|
393 | 97 | case 'allowed': |
|
394 | 65 | $valid = false; |
|
395 | 65 | if (($value === null) || is_callable($value)) { |
|
396 | // Explicitly defined validator or empty validator |
||
397 | 4 | $valid = true; |
|
398 | 65 | } elseif (is_array($value) && (count($value) === 1) && isset($value[0]) && is_string($value[0])) { |
|
399 | // This is probably validator defined through annotation's "allowed" parameter |
||
400 | 3 | $v = $value[0]; |
|
401 | 3 | if (class_exists($v)) { |
|
402 | // Class name for validation |
||
403 | 1 | $value = $v; |
|
404 | 1 | $valid = true; |
|
405 | 3 | View Code Duplication | } elseif (method_exists($this, $v)) { |
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
406 | // Name of validation method |
||
407 | $value = [$this, $v]; |
||
408 | $valid = true; |
||
409 | } else { |
||
410 | // Explicitly given list of valid values |
||
411 | 2 | $valid = true; |
|
412 | } |
||
413 | 61 | } elseif (is_string($value)) { |
|
414 | 5 | if (class_exists($value)) { |
|
415 | // Explicitly given class name for validation |
||
416 | 3 | $valid = true; |
|
417 | 5 | View Code Duplication | } elseif (method_exists($this, $value)) { |
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
418 | // Explicitly given name of validation method |
||
419 | 1 | $value = [$this, $value]; |
|
420 | 1 | $valid = true; |
|
421 | 1 | } |
|
422 | 58 | } /** @noinspection NotOptimalIfConditionsInspection */ elseif (is_array($value)) { |
|
423 | // Explicitly given list of valid values |
||
424 | 49 | $valid = true; |
|
425 | 49 | } |
|
426 | 65 | if (!$valid) { |
|
427 | 5 | throw new \InvalidArgumentException('Unable to recognize given validator for collection'); |
|
428 | } |
||
429 | 60 | break; |
|
430 | 73 | default: |
|
431 | 73 | return parent::validateConfig($name, $value); |
|
432 | 73 | } |
|
433 | 67 | return true; |
|
434 | } |
||
435 | |||
436 | /** |
||
437 | * {@inheritdoc} |
||
438 | */ |
||
439 | 95 | public function reset() |
|
440 | { |
||
441 | // No change notification should be made for reset, |
||
442 | // property value should be set to its default |
||
443 | 95 | $flag = $this->skipNotify; |
|
444 | 95 | $this->skipNotify = true; |
|
445 | /** @var array $default */ |
||
446 | 95 | $default = (array)$this->getConfig('default'); |
|
447 | 95 | foreach ($default as $k => &$v) { |
|
448 | 25 | if (!$this->normalize($v, $k)) { |
|
449 | throw new Exception('Default value for property class ' . get_class($this) . ' is not acceptable for property validation rules'); |
||
450 | } |
||
451 | 95 | } |
|
452 | 95 | unset($v); |
|
453 | 95 | $this->elements = $default; |
|
454 | 95 | $this->skipNotify = $flag; |
|
455 | 95 | } |
|
456 | |||
457 | /** |
||
458 | * {@inheritdoc} |
||
459 | */ |
||
460 | 1 | protected function initConfig() |
|
461 | { |
||
462 | 1 | parent::initConfig(); |
|
463 | 1 | $this->mergeConfig([ |
|
464 | 1 | 'default' => [], // Default value for collection |
|
465 | 1 | 'allowed' => null, // Either list of allowed values for collection elements |
|
466 | // or callable to test if element is allowed to be in collection |
||
467 | 1 | ]); |
|
468 | 1 | } |
|
469 | |||
470 | /** |
||
471 | * {@inheritdoc} |
||
472 | */ |
||
473 | 67 | protected function onConfigChange($name, $value) |
|
474 | { |
||
475 | /** @noinspection DegradedSwitchInspection */ |
||
476 | switch ($name) { |
||
477 | 67 | case 'allowed': |
|
478 | 60 | $this->allowed = $value; |
|
479 | 60 | break; |
|
480 | 28 | default: |
|
481 | 28 | parent::onConfigChange($name, $value); |
|
482 | 28 | break; |
|
483 | 28 | } |
|
484 | 67 | } |
|
485 | } |
||
486 |
This check looks from parameters that have been defined for a function or method, but which are not used in the method body.