PluginProbe
WPIDE – File Manager & Code Editor / 3.5.9
WPIDE – File Manager & Code Editor v3.5.9
3.5.9 3.5.8 3.5.7 2.0.14 2.0.15 2.0.16 2.0.2 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1 2.2 2.3 2.3.1 2.3.2 2.4.0 2.5 2.6 3.0 3.1 3.2 3.3 All 55 releases
wpide / vendor / adbario / php-dot-notation / src / Dot.php

Dot.php in WPIDE – File Manager & Code Editor 3.5.9, at vendor/adbario/php-dot-notation/src/Dot.php

676 lines 16.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Dot - PHP dot notation access to arrays
5 *
6 * @author Riku Särkinen <riku@adbar.io>
7 * @link https://github.com/adbario/php-dot-notation
8 * @license https://github.com/adbario/php-dot-notation/blob/3.x/LICENSE.md (MIT License)
9 */
10
11 namespace Adbar;
12
13 use Countable;
14 use ArrayAccess;
15 use ArrayIterator;
16 use JsonSerializable;
17 use IteratorAggregate;
18 use Traversable;
19
20 /**
21 * Dot
22 *
23 * This class provides a dot notation access and helper functions for
24 * working with arrays of data. Inspired by Laravel Collection.
25 *
26 * @template TKey of array-key
27 * @template TValue mixed
28 *
29 * @implements \ArrayAccess<TKey, TValue>
30 * @implements \IteratorAggregate<TKey, TValue>
31 */
32 class Dot implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable
33 {
34 /**
35 * The stored items
36 *
37 * @var array<TKey, TValue>
38 */
39 protected $items = [];
40
41 /**
42 * The character to use as a delimiter, defaults to dot (.)
43 *
44 * @var non-empty-string
45 */
46 protected $delimiter = ".";
47
48 /**
49 * Create a new Dot instance
50 *
51 * @param mixed $items
52 * @param bool $parse
53 * @param non-empty-string $delimiter
54 * @return void
55 */
56 public function __construct($items = [], $parse = false, $delimiter = ".")
57 {
58 $items = $this->getArrayItems($items);
59
60 $this->delimiter = $delimiter ?: ".";
61
62 if ($parse) {
63 $this->set($items);
64 } else {
65 $this->items = $items;
66 }
67 }
68
69 /**
70 * Set a given key / value pair or pairs
71 * if the key doesn't exist already
72 *
73 * @param array<TKey, TValue>|int|string $keys
74 * @param mixed $value
75 * @return $this
76 */
77 public function add($keys, $value = null)
78 {
79 if (is_array($keys)) {
80 foreach ($keys as $key => $value) {
81 $this->add($key, $value);
82 }
83 } elseif ($this->get($keys) === null) {
84 $this->set($keys, $value);
85 }
86
87 return $this;
88 }
89
90 /**
91 * Return all the stored items
92 *
93 * @return array<TKey, TValue>
94 */
95 public function all()
96 {
97 return $this->items;
98 }
99
100 /**
101 * Delete the contents of a given key or keys
102 *
103 * @param array<TKey>|int|string|null $keys
104 * @return $this
105 */
106 public function clear($keys = null)
107 {
108 if ($keys === null) {
109 $this->items = [];
110
111 return $this;
112 }
113
114 $keys = (array) $keys;
115
116 foreach ($keys as $key) {
117 $this->set($key, []);
118 }
119
120 return $this;
121 }
122
123 /**
124 * Delete the given key or keys
125 *
126 * @param array<TKey>|array<TKey, TValue>|int|string $keys
127 * @return $this
128 */
129 public function delete($keys)
130 {
131 $keys = (array) $keys;
132
133 foreach ($keys as $key) {
134 if ($this->exists($this->items, $key)) {
135 unset($this->items[$key]);
136
137 continue;
138 }
139
140 $items = &$this->items;
141 $segments = explode($this->delimiter, $key);
142 $lastSegment = array_pop($segments);
143
144 foreach ($segments as $segment) {
145 if (!isset($items[$segment]) || !is_array($items[$segment])) {
146 continue 2;
147 }
148
149 $items = &$items[$segment];
150 }
151
152 unset($items[$lastSegment]);
153 }
154
155 return $this;
156 }
157
158 /**
159 * Checks if the given key exists in the provided array.
160 *
161 * @param array<TKey, TValue> $array Array to validate
162 * @param int|string $key The key to look for
163 * @return bool
164 */
165 protected function exists($array, $key)
166 {
167 return array_key_exists($key, $array);
168 }
169
170 /**
171 * Flatten an array with the given character as a key delimiter
172 *
173 * @param string $delimiter
174 * @param mixed $items
175 * @param string $prepend
176 * @return array<TKey, TValue>
177 */
178 public function flatten($delimiter = '.', $items = null, $prepend = '')
179 {
180 $flatten = [];
181
182 if ($items === null) {
183 $items = $this->items;
184 }
185
186 foreach ($items as $key => $value) {
187 if (is_array($value) && !empty($value)) {
188 $flatten[] = $this->flatten($delimiter, $value, $prepend . $key . $delimiter);
189 } else {
190 $flatten[] = [$prepend . $key => $value];
191 }
192 }
193
194 return array_merge(...$flatten);
195 }
196
197 /**
198 * Return the value of a given key
199 *
200 * @param int|string|null $key
201 * @param mixed $default
202 * @return mixed
203 */
204 public function get($key = null, $default = null)
205 {
206 if ($key === null) {
207 return $this->items;
208 }
209
210 if ($this->exists($this->items, $key)) {
211 return $this->items[$key];
212 }
213
214 if (!is_string($key) || strpos($key, $this->delimiter) === false) {
215 return $default;
216 }
217
218 $items = $this->items;
219
220 foreach (explode($this->delimiter, $key) as $segment) {
221 if (!is_array($items) || !$this->exists($items, $segment)) {
222 return $default;
223 }
224
225 $items = &$items[$segment];
226 }
227
228 return $items;
229 }
230
231 /**
232 * Return the given items as an array
233 *
234 * @param array<TKey, TValue>|self<TKey, TValue>|object|string $items
235 * @return array<TKey, TValue>
236 */
237 protected function getArrayItems($items)
238 {
239 if (is_array($items)) {
240 return $items;
241 }
242
243 if ($items instanceof self) {
244 return $items->all();
245 }
246
247 return (array) $items;
248 }
249
250 /**
251 * Check if a given key or keys exists
252 *
253 * @param array<TKey>|int|string $keys
254 * @return bool
255 */
256 public function has($keys)
257 {
258 $keys = (array) $keys;
259
260 if (!$this->items || $keys === []) {
261 return false;
262 }
263
264 foreach ($keys as $key) {
265 $items = $this->items;
266
267 if ($this->exists($items, $key)) {
268 continue;
269 }
270
271 foreach (explode($this->delimiter, $key) as $segment) {
272 if (!is_array($items) || !$this->exists($items, $segment)) {
273 return false;
274 }
275
276 $items = $items[$segment];
277 }
278 }
279
280 return true;
281 }
282
283 /**
284 * Check if a given key or keys are empty
285 *
286 * @param array<TKey>|int|string|null $keys
287 * @return bool
288 */
289 public function isEmpty($keys = null)
290 {
291 if ($keys === null) {
292 return empty($this->items);
293 }
294
295 $keys = (array) $keys;
296
297 foreach ($keys as $key) {
298 if (!empty($this->get($key))) {
299 return false;
300 }
301 }
302
303 return true;
304 }
305
306 /**
307 * Merge a given array or a Dot object with the given key
308 * or with the whole Dot object
309 *
310 * @param array<TKey, TValue>|self<TKey, TValue>|string $key
311 * @param array<TKey, TValue>|self<TKey, TValue> $value
312 * @return $this
313 */
314 public function merge($key, $value = [])
315 {
316 if (is_array($key)) {
317 $this->items = array_merge($this->items, $key);
318 } elseif (is_string($key)) {
319 $items = (array) $this->get($key);
320 $value = array_merge($items, $this->getArrayItems($value));
321
322 $this->set($key, $value);
323 } elseif ($key instanceof self) {
324 $this->items = array_merge($this->items, $key->all());
325 }
326
327 return $this;
328 }
329
330 /**
331 * Recursively merge a given array or a Dot object with the given key
332 * or with the whole Dot object.
333 *
334 * Duplicate keys are converted to arrays.
335 *
336 * @param array<TKey, TValue>|self<TKey, TValue>|string $key
337 * @param array<TKey, TValue>|self<TKey, TValue> $value
338 * @return $this
339 */
340 public function mergeRecursive($key, $value = [])
341 {
342 if (is_array($key)) {
343 $this->items = array_merge_recursive($this->items, $key);
344 } elseif (is_string($key)) {
345 $items = (array) $this->get($key);
346 $value = array_merge_recursive($items, $this->getArrayItems($value));
347
348 $this->set($key, $value);
349 } elseif ($key instanceof self) {
350 $this->items = array_merge_recursive($this->items, $key->all());
351 }
352
353 return $this;
354 }
355
356 /**
357 * Recursively merge a given array or a Dot object with the given key
358 * or with the whole Dot object.
359 *
360 * Instead of converting duplicate keys to arrays, the value from
361 * given array will replace the value in Dot object.
362 *
363 * @param array<TKey, TValue>|self<TKey, TValue>|string $key
364 * @param array<TKey, TValue>|self<TKey, TValue> $value
365 * @return $this
366 */
367 public function mergeRecursiveDistinct($key, $value = [])
368 {
369 if (is_array($key)) {
370 $this->items = $this->arrayMergeRecursiveDistinct($this->items, $key);
371 } elseif (is_string($key)) {
372 $items = (array) $this->get($key);
373 $value = $this->arrayMergeRecursiveDistinct($items, $this->getArrayItems($value));
374
375 $this->set($key, $value);
376 } elseif ($key instanceof self) {
377 $this->items = $this->arrayMergeRecursiveDistinct($this->items, $key->all());
378 }
379
380 return $this;
381 }
382
383 /**
384 * Merges two arrays recursively. In contrast to array_merge_recursive,
385 * duplicate keys are not converted to arrays but rather overwrite the
386 * value in the first array with the duplicate value in the second array.
387 *
388 * @param array<TKey, TValue>|array<TKey, array<TKey, TValue>> $array1 Initial array to merge
389 * @param array<TKey, TValue>|array<TKey, array<TKey, TValue>> $array2 Array to recursively merge
390 * @return array<TKey, TValue>|array<TKey, array<TKey, TValue>>
391 */
392 protected function arrayMergeRecursiveDistinct(array $array1, array $array2)
393 {
394 $merged = &$array1;
395
396 foreach ($array2 as $key => $value) {
397 if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) {
398 $merged[$key] = $this->arrayMergeRecursiveDistinct($merged[$key], $value);
399 } else {
400 $merged[$key] = $value;
401 }
402 }
403
404 return $merged;
405 }
406
407 /**
408 * Return the value of a given key and
409 * delete the key
410 *
411 * @param int|string|null $key
412 * @param mixed $default
413 * @return mixed
414 */
415 public function pull($key = null, $default = null)
416 {
417 if ($key === null) {
418 $value = $this->all();
419 $this->clear();
420
421 return $value;
422 }
423
424 $value = $this->get($key, $default);
425 $this->delete($key);
426
427 return $value;
428 }
429
430 /**
431 * Push a given value to the end of the array
432 * in a given key
433 *
434 * @param mixed $key
435 * @param mixed $value
436 * @return $this
437 */
438 public function push($key, $value = null)
439 {
440 if ($value === null) {
441 $this->items[] = $key;
442
443 return $this;
444 }
445
446 $items = $this->get($key);
447
448 if (is_array($items) || $items === null) {
449 $items[] = $value;
450 $this->set($key, $items);
451 }
452
453 return $this;
454 }
455
456 /**
457 * Replace all values or values within the given key
458 * with an array or Dot object
459 *
460 * @param array<TKey, TValue>|self<TKey, TValue>|string $key
461 * @param array<TKey, TValue>|self<TKey, TValue> $value
462 * @return $this
463 */
464 public function replace($key, $value = [])
465 {
466 if (is_array($key)) {
467 $this->items = array_replace($this->items, $key);
468 } elseif (is_string($key)) {
469 $items = (array) $this->get($key);
470 $value = array_replace($items, $this->getArrayItems($value));
471
472 $this->set($key, $value);
473 } elseif ($key instanceof self) {
474 $this->items = array_replace($this->items, $key->all());
475 }
476
477 return $this;
478 }
479
480 /**
481 * Set a given key / value pair or pairs
482 *
483 * @param array<TKey, TValue>|int|string $keys
484 * @param mixed $value
485 * @return $this
486 */
487 public function set($keys, $value = null)
488 {
489 if (is_array($keys)) {
490 foreach ($keys as $key => $value) {
491 $this->set($key, $value);
492 }
493
494 return $this;
495 }
496
497 $items = &$this->items;
498
499 if (is_string($keys)) {
500 foreach (explode($this->delimiter, $keys) as $key) {
501 if (!isset($items[$key]) || !is_array($items[$key])) {
502 $items[$key] = [];
503 }
504
505 $items = &$items[$key];
506 }
507 }
508
509 $items = $value;
510
511 return $this;
512 }
513
514 /**
515 * Replace all items with a given array
516 *
517 * @param mixed $items
518 * @return $this
519 */
520 public function setArray($items)
521 {
522 $this->items = $this->getArrayItems($items);
523
524 return $this;
525 }
526
527 /**
528 * Replace all items with a given array as a reference
529 *
530 * @param array<TKey, TValue> $items
531 * @return $this
532 */
533 public function setReference(array &$items)
534 {
535 $this->items = &$items;
536
537 return $this;
538 }
539
540 /**
541 * Return the value of a given key or all the values as JSON
542 *
543 * @param mixed $key
544 * @param int $options
545 * @return string|false
546 */
547 public function toJson($key = null, $options = 0)
548 {
549 if (is_string($key)) {
550 return json_encode($this->get($key), $options);
551 }
552
553 $options = $key === null ? 0 : $key;
554
555 return json_encode($this->items, $options);
556 }
557
558 /**
559 * Output or return a parsable string representation of the
560 * given array when exported by var_export()
561 *
562 * @param array<TKey, TValue> $items
563 * @return object
564 */
565 public static function __set_state(array $items): object
566 {
567 return (object) $items;
568 }
569
570 /*
571 * --------------------------------------------------------------
572 * ArrayAccess interface
573 * --------------------------------------------------------------
574 */
575
576 /**
577 * Check if a given key exists
578 *
579 * @param int|string $key
580 * @return bool
581 */
582 public function offsetExists($key): bool
583 {
584 return $this->has($key);
585 }
586
587 /**
588 * Return the value of a given key
589 *
590 * @param int|string $key
591 * @return mixed
592 */
593 #[\ReturnTypeWillChange]
594 public function offsetGet($key)
595 {
596 return $this->get($key);
597 }
598
599 /**
600 * Set a given value to the given key
601 *
602 * @param int|string|null $key
603 * @param mixed $value
604 */
605 public function offsetSet($key, $value): void
606 {
607 if ($key === null) {
608 $this->items[] = $value;
609
610 return;
611 }
612
613 $this->set($key, $value);
614 }
615
616 /**
617 * Delete the given key
618 *
619 * @param int|string $key
620 * @return void
621 */
622 public function offsetUnset($key): void
623 {
624 $this->delete($key);
625 }
626
627 /*
628 * --------------------------------------------------------------
629 * Countable interface
630 * --------------------------------------------------------------
631 */
632
633 /**
634 * Return the number of items in a given key
635 *
636 * @param int|string|null $key
637 * @return int
638 */
639 public function count($key = null): int
640 {
641 return count($this->get($key));
642 }
643
644 /*
645 * --------------------------------------------------------------
646 * IteratorAggregate interface
647 * --------------------------------------------------------------
648 */
649
650 /**
651 * Get an iterator for the stored items
652 *
653 * @return \ArrayIterator<TKey, TValue>
654 */
655 public function getIterator(): Traversable
656 {
657 return new ArrayIterator($this->items);
658 }
659
660 /*
661 * --------------------------------------------------------------
662 * JsonSerializable interface
663 * --------------------------------------------------------------
664 */
665
666 /**
667 * Return items for JSON serialization
668 *
669 * @return array<TKey, TValue>
670 */
671 public function jsonSerialize(): array
672 {
673 return $this->items;
674 }
675 }
676