Vous êtes connecté en tant que anonymous Se Deconnecter
Browse code

Application modulaire fonctionnelle !

Emmanuel ROY authored on 12/08/2019 15:10:25
Showing 1 changed files
1 1
deleted file mode 100644
... ...
@@ -1,808 +0,0 @@
1
-<?php declare(strict_types=1);
2
-/**
3
- * Part of Windwalker project.
4
- *
5
- * @copyright  Copyright (C) 2019 LYRASOFT.
6
- * @license    LGPL-2.0-or-later
7
- */
8
-
9
-namespace Windwalker\Structure;
10
-
11
-/**
12
- * Structure class
13
- *
14
- * @since  2.0
15
- */
16
-class Structure implements \JsonSerializable, \ArrayAccess, \IteratorAggregate, \Countable
17
-{
18
-    /**
19
-     * Property separator.
20
-     *
21
-     * @var  string
22
-     */
23
-    protected $separator = '.';
24
-
25
-    /**
26
-     * Structure data store.
27
-     *
28
-     * @var    array
29
-     * @since  2.0
30
-     */
31
-    protected $data = [];
32
-
33
-    /**
34
-     * Property ignoreValues.
35
-     *
36
-     * @var  array
37
-     */
38
-    protected $ignoreValues = [null];
39
-
40
-    /**
41
-     * Create Value Reference.
42
-     *
43
-     * @param string      $path
44
-     * @param string|null $separator
45
-     *
46
-     * @return  ValueReference
47
-     *
48
-     * @since  3.5.1
49
-     */
50
-    public static function ref(string $path, string $separator = null): ValueReference
51
-    {
52
-        return new ValueReference($path, $separator);
53
-    }
54
-
55
-    /**
56
-     * Constructor
57
-     *
58
-     * @param mixed  $data    The data to bind to the new Structure object.
59
-     * @param string $format  The format of input, only work when first argument is string.
60
-     * @param array  $options The load options.
61
-     *
62
-     * @since   2.0
63
-     */
64
-    public function __construct($data = null, $format = Format::JSON, array $options = [])
65
-    {
66
-        $raw = $options['load_raw'] ?? false;
67
-
68
-        // Optionally load supplied data.
69
-        if (\is_array($data) || \is_object($data)) {
70
-            $this->bindData($this->data, $data, $raw, $options);
71
-        } elseif (!empty($data) && \is_string($data)) {
72
-            if (\strlen($data) < PHP_MAXPATHLEN && is_file($data)) {
73
-                $this->loadFile($data, $format, $options);
74
-            } else {
75
-                $this->loadString($data, $format, $options);
76
-            }
77
-        }
78
-    }
79
-
80
-    /**
81
-     * Magic function to clone the structure object.
82
-     *
83
-     * @return  Structure
84
-     *
85
-     * @since   2.0
86
-     */
87
-    public function __clone()
88
-    {
89
-        $this->data = unserialize(serialize($this->data));
90
-    }
91
-
92
-    /**
93
-     * Magic function to render this object as a string using default args of toString method.
94
-     *
95
-     * @return  string
96
-     *
97
-     * @since   2.0
98
-     */
99
-    public function __toString()
100
-    {
101
-        try {
102
-            return $this->toString();
103
-        } catch (\Exception $e) {
104
-            trigger_error((string) $e, E_USER_ERROR);
105
-
106
-            return '';
107
-        }
108
-    }
109
-
110
-    /**
111
-     * Implementation for the JsonSerializable interface.
112
-     * Allows us to pass Structure objects to json_encode.
113
-     *
114
-     * @return  array
115
-     *
116
-     * @since   2.0
117
-     */
118
-    public function jsonSerialize()
119
-    {
120
-        return $this->data;
121
-    }
122
-
123
-    /**
124
-     * Sets a default value if not already assigned.
125
-     *
126
-     * @param   string $path  The name of the parameter.
127
-     * @param   mixed  $value An optional value for the parameter.
128
-     *
129
-     * @return  static  Return self to support chaining.
130
-     *
131
-     * @since   2.0
132
-     */
133
-    public function def($path, $value = '')
134
-    {
135
-        $value = $this->get($path, $value);
136
-        $this->set($path, $value);
137
-
138
-        return $this;
139
-    }
140
-
141
-    /**
142
-     * Check if a structure path exists.
143
-     *
144
-     * @param   string $path Structure path (e.g. foo.content.showauthor)
145
-     *
146
-     * @return  boolean
147
-     *
148
-     * @since   2.0
149
-     */
150
-    public function exists($path)
151
-    {
152
-        return null !== $this->get($path);
153
-    }
154
-
155
-    /**
156
-     * Get a structure value.
157
-     *
158
-     * @param   string    $path       Structure path (e.g. foo.content.showauthor)
159
-     * @param   mixed     $default    Optional default value, returned if the internal value is null.
160
-     * @param   string    $separator  Force separate character.
161
-     *
162
-     * @return  mixed  Value of entry or null
163
-     *
164
-     * @since   2.0
165
-     */
166
-    public function get($path, $default = null, string $separator = null)
167
-    {
168
-        $result = StructureHelper::getByPath($this->data, $path, $separator ?: $this->separator);
169
-
170
-        return $result ?? $default;
171
-    }
172
-
173
-    /**
174
-     * remove
175
-     *
176
-     * @param   string $path
177
-     *
178
-     * @return  static
179
-     */
180
-    public function remove($path)
181
-    {
182
-        StructureHelper::removeByPath($this->data, $path, $this->separator);
183
-
184
-        return $this;
185
-    }
186
-
187
-    /**
188
-     * Reset all data.
189
-     *
190
-     * @return  static
191
-     */
192
-    public function reset()
193
-    {
194
-        $this->data = [];
195
-
196
-        return $this;
197
-    }
198
-
199
-    /**
200
-     * Load an array or object of values into the default namespace
201
-     *
202
-     * @param  array|object $data    The value to load into structure.
203
-     * @param  boolean      $raw     Set to false that we will convert all object to array.
204
-     * @param  array        $options The options to bind data.
205
-     *
206
-     * @return static Return this object to support chaining.
207
-     */
208
-    public function load($data, $raw = false, array $options = [])
209
-    {
210
-        $this->bindData($this->data, $data, $raw, $options);
211
-
212
-        return $this;
213
-    }
214
-
215
-    /**
216
-     * Load the contents of a file into the structure
217
-     *
218
-     * @param   string $file    Path to file to load
219
-     * @param   string $format  Format of the file [optional: defaults to JSON]
220
-     * @param   array  $options Options used by the formatter
221
-     *
222
-     * @return  static  Return this object to support chaining.
223
-     *
224
-     * @since   2.0
225
-     */
226
-    public function loadFile($file, $format = Format::JSON, $options = [])
227
-    {
228
-        $raw = isset($options['load_raw']) ? $options['load_raw'] : false;
229
-
230
-        $this->load(StructureHelper::loadFile($file, $format, $options), $raw, $options);
231
-
232
-        return $this;
233
-    }
234
-
235
-    /**
236
-     * Load a string into the structure
237
-     *
238
-     * @param   string $data    String to load into the structure
239
-     * @param   string $format  Format of the string
240
-     * @param   array  $options Options used by the formatter
241
-     *
242
-     * @return  static  Return this object to support chaining.
243
-     *
244
-     * @since   2.0
245
-     */
246
-    public function loadString($data, $format = Format::JSON, $options = [])
247
-    {
248
-        $raw = isset($options['load_raw']) ? $options['load_raw'] : false;
249
-
250
-        $this->load(StructureHelper::loadString($data, $format, $options), $raw, $options);
251
-
252
-        return $this;
253
-    }
254
-
255
-    /**
256
-     * Merge a structure data into this object.
257
-     *
258
-     * @param   Structure|mixed $source  Source structure data to merge.
259
-     * @param   boolean         $raw     Set to false to convert all object to array.
260
-     * @param   array           $options Options to bind data.
261
-     *
262
-     * @return  static  Return this object to support chaining.
263
-     *
264
-     * @since   2.0
265
-     */
266
-    public function merge($source, $raw = false, array $options = [])
267
-    {
268
-        if ($source instanceof self) {
269
-            $source = $source->getRaw();
270
-        }
271
-
272
-        $this->bindData($this->data, $source, $raw, $options);
273
-
274
-        return $this;
275
-    }
276
-
277
-    /**
278
-     * Merge a structure data to a node.
279
-     *
280
-     * @param   string    $path    The path to merge as root.
281
-     * @param   Structure $source  Source structure data to merge.
282
-     * @param   boolean   $raw     Set to false to convert all object to array.
283
-     * @param   array     $options Options to bind data.
284
-     *
285
-     * @return  static
286
-     */
287
-    public function mergeTo($path, $source, $raw = false, array $options = [])
288
-    {
289
-        $nodes = StructureHelper::getPathNodes($path);
290
-
291
-        $data = [];
292
-
293
-        $tmp =& $data;
294
-
295
-        foreach ($nodes as $node) {
296
-            $tmp[$node] = [];
297
-
298
-            $tmp =& $tmp[$node];
299
-        }
300
-
301
-        if ($source instanceof self) {
302
-            $source = $source->getRaw();
303
-        }
304
-
305
-        $tmp = $source;
306
-
307
-        $this->bindData($this->data, $data, $raw, $options);
308
-
309
-        return $this;
310
-    }
311
-
312
-    /**
313
-     * extract
314
-     *
315
-     * @param string $path
316
-     *
317
-     * @return  static
318
-     */
319
-    public function extract($path)
320
-    {
321
-        return (new static())->load((array) $this->get($path), true);
322
-    }
323
-
324
-    /**
325
-     * getRaw
326
-     *
327
-     * @return  array
328
-     */
329
-    public function getRaw()
330
-    {
331
-        return $this->data;
332
-    }
333
-
334
-    /**
335
-     * Checks whether an offset exists in the iterator.
336
-     *
337
-     * @param   mixed $offset The array offset.
338
-     *
339
-     * @return  boolean  True if the offset exists, false otherwise.
340
-     *
341
-     * @since   2.0
342
-     */
343
-    public function offsetExists($offset)
344
-    {
345
-        return $this->get($offset) !== null;
346
-    }
347
-
348
-    /**
349
-     * Gets an offset in the iterator.
350
-     *
351
-     * @param   mixed $offset The array offset.
352
-     *
353
-     * @return  mixed  The array value if it exists, null otherwise.
354
-     *
355
-     * @since   2.0
356
-     */
357
-    public function offsetGet($offset)
358
-    {
359
-        return $this->get($offset);
360
-    }
361
-
362
-    /**
363
-     * Sets an offset in the iterator.
364
-     *
365
-     * @param   mixed $offset The array offset.
366
-     * @param   mixed $value  The array value.
367
-     *
368
-     * @return  void
369
-     *
370
-     * @since   2.0
371
-     */
372
-    public function offsetSet($offset, $value)
373
-    {
374
-        $this->set($offset, $value);
375
-    }
376
-
377
-    /**
378
-     * Unsets an offset in the iterator.
379
-     *
380
-     * @param   mixed $offset The array offset.
381
-     *
382
-     * @return  void
383
-     *
384
-     * @since   2.0
385
-     */
386
-    public function offsetUnset($offset)
387
-    {
388
-        $this->set($offset, null);
389
-    }
390
-
391
-    /**
392
-     * Set a structure value and convert object to array.
393
-     *
394
-     * @param   string $path  Structure Path (e.g. foo.content.showauthor)
395
-     * @param   mixed  $value Value of entry.
396
-     *
397
-     * @return  static  Return self to support chaining.
398
-     *
399
-     * @since   2.0
400
-     */
401
-    public function set($path, $value)
402
-    {
403
-        if ($value instanceof ValueReference) {
404
-            $value = $value->get($this);
405
-        }
406
-
407
-        if (\is_array($value) || \is_object($value)) {
408
-            $value = StructureHelper::toArray($value, true);
409
-        }
410
-
411
-        StructureHelper::setByPath($this->data, $path, $value, $this->separator);
412
-
413
-        return $this;
414
-    }
415
-
416
-    /**
417
-     * Set a structure value.
418
-     *
419
-     * @param   string $path  Structure Path (e.g. foo.content.showauthor)
420
-     * @param   mixed  $value Value of entry.
421
-     *
422
-     * @return  static  Return self to support chaining.
423
-     *
424
-     * @since   2.1
425
-     */
426
-    public function setRaw($path, $value)
427
-    {
428
-        StructureHelper::setByPath($this->data, $path, $value, $this->separator);
429
-
430
-        return $this;
431
-    }
432
-
433
-    /**
434
-     * Transforms a namespace to an array
435
-     *
436
-     * @return  array  An associative array holding the namespace data
437
-     *
438
-     * @since   2.0
439
-     */
440
-    public function toArray()
441
-    {
442
-        return (array) $this->asArray($this->data);
443
-    }
444
-
445
-    /**
446
-     * Transforms a namespace to an object
447
-     *
448
-     * @param   string $class The class of object.
449
-     *
450
-     * @return  object   An an object holding the namespace data
451
-     *
452
-     * @since   2.0
453
-     */
454
-    public function toObject($class = 'stdClass')
455
-    {
456
-        return StructureHelper::toObject($this->data, $class);
457
-    }
458
-
459
-    /**
460
-     * Get a namespace in a given string format
461
-     *
462
-     * @param   string $format  Format to return the string in
463
-     * @param   mixed  $options Parameters used by the formatter, see formatters for more info
464
-     *
465
-     * @return  string   Namespace in string format
466
-     *
467
-     * @since   2.0
468
-     */
469
-    public function toString($format = Format::JSON, $options = [])
470
-    {
471
-        return StructureHelper::toString($this->data, $format, $options);
472
-    }
473
-
474
-    /**
475
-     * Method to recursively bind data to a parent object.
476
-     *
477
-     * @param   array   $parent  The parent object on which to attach the data values.
478
-     * @param   mixed   $data    An array or object of data to bind to the parent object.
479
-     * @param   boolean $raw     Set to false to convert all object to array.
480
-     * @param   array   $options The options to bind data.
481
-     *
482
-     * @return  void
483
-     */
484
-    protected function bindData(&$parent, $data, $raw = false, array $options = [])
485
-    {
486
-        // Ensure the input data is an array.
487
-        if (!$raw) {
488
-            $data = StructureHelper::toArray($data, true);
489
-        }
490
-
491
-        $onlyExists = !empty($options['only_exists']);
492
-
493
-        foreach ($data as $key => $value) {
494
-            if (\in_array($value, $this->ignoreValues, true)) {
495
-                continue;
496
-            }
497
-
498
-            if ($onlyExists && !isset($parent[$key])) {
499
-                continue;
500
-            }
501
-
502
-            if (\is_array($value)) {
503
-                if (!isset($parent[$key]) || !\is_array($parent[$key])) {
504
-                    $parent[$key] = [];
505
-                }
506
-
507
-                $this->bindData($parent[$key], $value, $raw);
508
-            } else {
509
-                $parent[$key] = $this->resolveValue($value);
510
-            }
511
-        }
512
-    }
513
-
514
-    /**
515
-     * Method to recursively convert an object of data to an array.
516
-     *
517
-     * @param   mixed $data An object of data to return as an array.
518
-     *
519
-     * @return  array  Array representation of the input object.
520
-     *
521
-     * @since   2.0
522
-     */
523
-    protected function asArray($data)
524
-    {
525
-        $array = [];
526
-
527
-        if (\is_object($data)) {
528
-            $data = get_object_vars($data);
529
-        }
530
-
531
-        foreach ($data as $k => $v) {
532
-            if (\is_object($v) || \is_array($v)) {
533
-                $array[$k] = $this->asArray($v);
534
-            } else {
535
-                $array[$k] = $v;
536
-            }
537
-        }
538
-
539
-        return $array;
540
-    }
541
-
542
-    /**
543
-     * Dump to on dimension array.
544
-     *
545
-     * @param string $separator The key separator.
546
-     *
547
-     * @return  string[] Dumped array.
548
-     */
549
-    public function flatten($separator = '.')
550
-    {
551
-        return StructureHelper::flatten($this->data, $separator);
552
-    }
553
-
554
-    /**
555
-     * Method to get property Separator
556
-     *
557
-     * @return  string
558
-     *
559
-     * @since   2.1
560
-     */
561
-    public function getSeparator()
562
-    {
563
-        return $this->separator;
564
-    }
565
-
566
-    /**
567
-     * Method to set property separator
568
-     *
569
-     * @param   string $separator
570
-     *
571
-     * @return  static  Return self to support chaining.
572
-     *
573
-     * @since   2.1
574
-     */
575
-    public function setSeparator($separator)
576
-    {
577
-        $this->separator = $separator;
578
-
579
-        return $this;
580
-    }
581
-
582
-    /**
583
-     * Push value to a path in structure
584
-     *
585
-     * @param   string $path  Parent structure Path (e.g. windwalker.content.showauthor)
586
-     * @param   mixed  $value Value of entry, one or more elements.
587
-     *
588
-     * @return  integer  the new number of elements in the array.
589
-     *
590
-     * @since   2.1
591
-     */
592
-    public function push($path, $value)
593
-    {
594
-        $node = $this->get($path);
595
-
596
-        if (!$node) {
597
-            $node = [];
598
-        } elseif (\is_object($node)) {
599
-            $node = get_object_vars($node);
600
-        }
601
-
602
-        if (!\is_array($node)) {
603
-            throw new \UnexpectedValueException(
604
-                sprintf(
605
-                    'The value at path: %s should be object or array but is %s.',
606
-                    $path,
607
-                    \gettype($node)
608
-                )
609
-            );
610
-        }
611
-
612
-        $args = \func_get_args();
613
-
614
-        if (count($args) <= 2) {
615
-            $num = array_push($node, $value);
616
-        } else {
617
-            $args[0] = &$node;
618
-
619
-            $num = call_user_func_array('array_push', $args);
620
-        }
621
-
622
-        $this->set($path, $node);
623
-
624
-        return $num;
625
-    }
626
-
627
-    /**
628
-     * Prepend value to a path in structure.
629
-     *
630
-     * @param   string $path  Parent structure Path (e.g. windwalker.content.showauthor)
631
-     * @param   mixed  $value Value of entry, one or more elements.
632
-     *
633
-     * @return  integer  the new number of elements in the array.
634
-     *
635
-     * @since   2.1
636
-     */
637
-    public function unshift($path, $value)
638
-    {
639
-        $node = $this->get($path);
640
-
641
-        if (!$node) {
642
-            $node = [];
643
-        } elseif (\is_object($node)) {
644
-            $node = get_object_vars($node);
645
-        }
646
-
647
-        if (!\is_array($node)) {
648
-            throw new \UnexpectedValueException(
649
-                sprintf(
650
-                    'The value at path: %s should be object or array but is %s.',
651
-                    $path,
652
-                    gettype($node)
653
-                )
654
-            );
655
-        }
656
-
657
-        $args = \func_get_args();
658
-
659
-        if (\count($args) <= 2) {
660
-            $key = array_unshift($node, $value);
661
-        } else {
662
-            $args[0] = &$node;
663
-
664
-            $key = call_user_func_array('array_unshift', $args);
665
-        }
666
-
667
-        $this->set($path, $node);
668
-
669
-        return $key;
670
-    }
671
-
672
-    /**
673
-     * To remove first element from the path of this structure.
674
-     *
675
-     * @param   string $path The structure path.
676
-     *
677
-     * @return  mixed  The shifted value, or null if array is empty.
678
-     */
679
-    public function shift($path)
680
-    {
681
-        $node = $this->get($path);
682
-
683
-        if (\is_object($node)) {
684
-            $node = get_object_vars($node);
685
-        }
686
-
687
-        if (!\is_array($node)) {
688
-            throw new \UnexpectedValueException(
689
-                sprintf(
690
-                    'The value at path: %s should be object or array but is %s.',
691
-                    $path,
692
-                    \gettype($node)
693
-                )
694
-            );
695
-        }
696
-
697
-        $value = array_shift($node);
698
-
699
-        $this->set($path, $node);
700
-
701
-        return $value;
702
-    }
703
-
704
-    /**
705
-     * To remove last element from the path of this structure.
706
-     *
707
-     * @param   string $path The structure path.
708
-     *
709
-     * @return  mixed  The shifted value, or &null; if array is empty.
710
-     */
711
-    public function pop($path)
712
-    {
713
-        $node = $this->get($path);
714
-
715
-        if (\is_object($node)) {
716
-            $node = get_object_vars($node);
717
-        }
718
-
719
-        if (!\is_array($node)) {
720
-            throw new \UnexpectedValueException(
721
-                sprintf(
722
-                    'The value at path: %s should be object or array but is %s.',
723
-                    $path,
724
-                    \gettype($node)
725
-                )
726
-            );
727
-        }
728
-
729
-        $value = array_pop($node);
730
-
731
-        $this->set($path, $node);
732
-
733
-        return $value;
734
-    }
735
-
736
-    /**
737
-     * Gets this object represented as an RecursiveArrayIterator.
738
-     *
739
-     * This allows the data properties to be accessed via a foreach statement.
740
-     *
741
-     * You can wrap this iterator by RecursiveIteratorIterator that will support recursive foreach.
742
-     * Example: `foreach (new \RecursiveIteratorIterator($structure) as $value)`
743
-     *
744
-     * @return  \RecursiveArrayIterator  This object represented as an RecursiveArrayIterator.
745
-     *
746
-     * @see     IteratorAggregate::getIterator()
747
-     * @since   2.1
748
-     */
749
-    public function getIterator()
750
-    {
751
-        return new \RecursiveArrayIterator($this->data);
752
-    }
753
-
754
-    /**
755
-     * Count elements of the data object
756
-     *
757
-     * @return  integer  The custom count as an integer.
758
-     *
759
-     * @link    http://php.net/manual/en/countable.count.php
760
-     * @since   2.1
761
-     */
762
-    public function count()
763
-    {
764
-        return \count($this->data);
765
-    }
766
-
767
-    /**
768
-     * resolveValue
769
-     *
770
-     * @param mixed|ValueReference $value
771
-     *
772
-     * @return  mixed
773
-     *
774
-     * @since  3.5.1
775
-     */
776
-    protected function resolveValue($value)
777
-    {
778
-        if ($value instanceof ValueReference) {
779
-            $value = $value->get($this);
780
-        }
781
-
782
-        return $value;
783
-    }
784
-
785
-    /**
786
-     * Method to get property IgnoreValues
787
-     *
788
-     * @return  array
789
-     */
790
-    public function getIgnoreValues()
791
-    {
792
-        return $this->ignoreValues;
793
-    }
794
-
795
-    /**
796
-     * Method to set property ignoreValues
797
-     *
798
-     * @param   array $ignoreValues
799
-     *
800
-     * @return  static  Return self to support chaining.
801
-     */
802
-    public function setIgnoreValues($ignoreValues)
803
-    {
804
-        $this->ignoreValues = (array) $ignoreValues;
805
-
806
-        return $this;
807
-    }
808
-}
Browse code

initial commit

Emmanuel ROY authored on 09/08/2019 08:39:02
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,808 @@
1
+<?php declare(strict_types=1);
2
+/**
3
+ * Part of Windwalker project.
4
+ *
5
+ * @copyright  Copyright (C) 2019 LYRASOFT.
6
+ * @license    LGPL-2.0-or-later
7
+ */
8
+
9
+namespace Windwalker\Structure;
10
+
11
+/**
12
+ * Structure class
13
+ *
14
+ * @since  2.0
15
+ */
16
+class Structure implements \JsonSerializable, \ArrayAccess, \IteratorAggregate, \Countable
17
+{
18
+    /**
19
+     * Property separator.
20
+     *
21
+     * @var  string
22
+     */
23
+    protected $separator = '.';
24
+
25
+    /**
26
+     * Structure data store.
27
+     *
28
+     * @var    array
29
+     * @since  2.0
30
+     */
31
+    protected $data = [];
32
+
33
+    /**
34
+     * Property ignoreValues.
35
+     *
36
+     * @var  array
37
+     */
38
+    protected $ignoreValues = [null];
39
+
40
+    /**
41
+     * Create Value Reference.
42
+     *
43
+     * @param string      $path
44
+     * @param string|null $separator
45
+     *
46
+     * @return  ValueReference
47
+     *
48
+     * @since  3.5.1
49
+     */
50
+    public static function ref(string $path, string $separator = null): ValueReference
51
+    {
52
+        return new ValueReference($path, $separator);
53
+    }
54
+
55
+    /**
56
+     * Constructor
57
+     *
58
+     * @param mixed  $data    The data to bind to the new Structure object.
59
+     * @param string $format  The format of input, only work when first argument is string.
60
+     * @param array  $options The load options.
61
+     *
62
+     * @since   2.0
63
+     */
64
+    public function __construct($data = null, $format = Format::JSON, array $options = [])
65
+    {
66
+        $raw = $options['load_raw'] ?? false;
67
+
68
+        // Optionally load supplied data.
69
+        if (\is_array($data) || \is_object($data)) {
70
+            $this->bindData($this->data, $data, $raw, $options);
71
+        } elseif (!empty($data) && \is_string($data)) {
72
+            if (\strlen($data) < PHP_MAXPATHLEN && is_file($data)) {
73
+                $this->loadFile($data, $format, $options);
74
+            } else {
75
+                $this->loadString($data, $format, $options);
76
+            }
77
+        }
78
+    }
79
+
80
+    /**
81
+     * Magic function to clone the structure object.
82
+     *
83
+     * @return  Structure
84
+     *
85
+     * @since   2.0
86
+     */
87
+    public function __clone()
88
+    {
89
+        $this->data = unserialize(serialize($this->data));
90
+    }
91
+
92
+    /**
93
+     * Magic function to render this object as a string using default args of toString method.
94
+     *
95
+     * @return  string
96
+     *
97
+     * @since   2.0
98
+     */
99
+    public function __toString()
100
+    {
101
+        try {
102
+            return $this->toString();
103
+        } catch (\Exception $e) {
104
+            trigger_error((string) $e, E_USER_ERROR);
105
+
106
+            return '';
107
+        }
108
+    }
109
+
110
+    /**
111
+     * Implementation for the JsonSerializable interface.
112
+     * Allows us to pass Structure objects to json_encode.
113
+     *
114
+     * @return  array
115
+     *
116
+     * @since   2.0
117
+     */
118
+    public function jsonSerialize()
119
+    {
120
+        return $this->data;
121
+    }
122
+
123
+    /**
124
+     * Sets a default value if not already assigned.
125
+     *
126
+     * @param   string $path  The name of the parameter.
127
+     * @param   mixed  $value An optional value for the parameter.
128
+     *
129
+     * @return  static  Return self to support chaining.
130
+     *
131
+     * @since   2.0
132
+     */
133
+    public function def($path, $value = '')
134
+    {
135
+        $value = $this->get($path, $value);
136
+        $this->set($path, $value);
137
+
138
+        return $this;
139
+    }
140
+
141
+    /**
142
+     * Check if a structure path exists.
143
+     *
144
+     * @param   string $path Structure path (e.g. foo.content.showauthor)
145
+     *
146
+     * @return  boolean
147
+     *
148
+     * @since   2.0
149
+     */
150
+    public function exists($path)
151
+    {
152
+        return null !== $this->get($path);
153
+    }
154
+
155
+    /**
156
+     * Get a structure value.
157
+     *
158
+     * @param   string    $path       Structure path (e.g. foo.content.showauthor)
159
+     * @param   mixed     $default    Optional default value, returned if the internal value is null.
160
+     * @param   string    $separator  Force separate character.
161
+     *
162
+     * @return  mixed  Value of entry or null
163
+     *
164
+     * @since   2.0
165
+     */
166
+    public function get($path, $default = null, string $separator = null)
167
+    {
168
+        $result = StructureHelper::getByPath($this->data, $path, $separator ?: $this->separator);
169
+
170
+        return $result ?? $default;
171
+    }
172
+
173
+    /**
174
+     * remove
175
+     *
176
+     * @param   string $path
177
+     *
178
+     * @return  static
179
+     */
180
+    public function remove($path)
181
+    {
182
+        StructureHelper::removeByPath($this->data, $path, $this->separator);
183
+
184
+        return $this;
185
+    }
186
+
187
+    /**
188
+     * Reset all data.
189
+     *
190
+     * @return  static
191
+     */
192
+    public function reset()
193
+    {
194
+        $this->data = [];
195
+
196
+        return $this;
197
+    }
198
+
199
+    /**
200
+     * Load an array or object of values into the default namespace
201
+     *
202
+     * @param  array|object $data    The value to load into structure.
203
+     * @param  boolean      $raw     Set to false that we will convert all object to array.
204
+     * @param  array        $options The options to bind data.
205
+     *
206
+     * @return static Return this object to support chaining.
207
+     */
208
+    public function load($data, $raw = false, array $options = [])
209
+    {
210
+        $this->bindData($this->data, $data, $raw, $options);
211
+
212
+        return $this;
213
+    }
214
+
215
+    /**
216
+     * Load the contents of a file into the structure
217
+     *
218
+     * @param   string $file    Path to file to load
219
+     * @param   string $format  Format of the file [optional: defaults to JSON]
220
+     * @param   array  $options Options used by the formatter
221
+     *
222
+     * @return  static  Return this object to support chaining.
223
+     *
224
+     * @since   2.0
225
+     */
226
+    public function loadFile($file, $format = Format::JSON, $options = [])
227
+    {
228
+        $raw = isset($options['load_raw']) ? $options['load_raw'] : false;
229
+
230
+        $this->load(StructureHelper::loadFile($file, $format, $options), $raw, $options);
231
+
232
+        return $this;
233
+    }
234
+
235
+    /**
236
+     * Load a string into the structure
237
+     *
238
+     * @param   string $data    String to load into the structure
239
+     * @param   string $format  Format of the string
240
+     * @param   array  $options Options used by the formatter
241
+     *
242
+     * @return  static  Return this object to support chaining.
243
+     *
244
+     * @since   2.0
245
+     */
246
+    public function loadString($data, $format = Format::JSON, $options = [])
247
+    {
248
+        $raw = isset($options['load_raw']) ? $options['load_raw'] : false;
249
+
250
+        $this->load(StructureHelper::loadString($data, $format, $options), $raw, $options);
251
+
252
+        return $this;
253
+    }
254
+
255
+    /**
256
+     * Merge a structure data into this object.
257
+     *
258
+     * @param   Structure|mixed $source  Source structure data to merge.
259
+     * @param   boolean         $raw     Set to false to convert all object to array.
260
+     * @param   array           $options Options to bind data.
261
+     *
262
+     * @return  static  Return this object to support chaining.
263
+     *
264
+     * @since   2.0
265
+     */
266
+    public function merge($source, $raw = false, array $options = [])
267
+    {
268
+        if ($source instanceof self) {
269
+            $source = $source->getRaw();
270
+        }
271
+
272
+        $this->bindData($this->data, $source, $raw, $options);
273
+
274
+        return $this;
275
+    }
276
+
277
+    /**
278
+     * Merge a structure data to a node.
279
+     *
280
+     * @param   string    $path    The path to merge as root.
281
+     * @param   Structure $source  Source structure data to merge.
282
+     * @param   boolean   $raw     Set to false to convert all object to array.
283
+     * @param   array     $options Options to bind data.
284
+     *
285
+     * @return  static
286
+     */
287
+    public function mergeTo($path, $source, $raw = false, array $options = [])
288
+    {
289
+        $nodes = StructureHelper::getPathNodes($path);
290
+
291
+        $data = [];
292
+
293
+        $tmp =& $data;
294
+
295
+        foreach ($nodes as $node) {
296
+            $tmp[$node] = [];
297
+
298
+            $tmp =& $tmp[$node];
299
+        }
300
+
301
+        if ($source instanceof self) {
302
+            $source = $source->getRaw();
303
+        }
304
+
305
+        $tmp = $source;
306
+
307
+        $this->bindData($this->data, $data, $raw, $options);
308
+
309
+        return $this;
310
+    }
311
+
312
+    /**
313
+     * extract
314
+     *
315
+     * @param string $path
316
+     *
317
+     * @return  static
318
+     */
319
+    public function extract($path)
320
+    {
321
+        return (new static())->load((array) $this->get($path), true);
322
+    }
323
+
324
+    /**
325
+     * getRaw
326
+     *
327
+     * @return  array
328
+     */
329
+    public function getRaw()
330
+    {
331
+        return $this->data;
332
+    }
333
+
334
+    /**
335
+     * Checks whether an offset exists in the iterator.
336
+     *
337
+     * @param   mixed $offset The array offset.
338
+     *
339
+     * @return  boolean  True if the offset exists, false otherwise.
340
+     *
341
+     * @since   2.0
342
+     */
343
+    public function offsetExists($offset)
344
+    {
345
+        return $this->get($offset) !== null;
346
+    }
347
+
348
+    /**
349
+     * Gets an offset in the iterator.
350
+     *
351
+     * @param   mixed $offset The array offset.
352
+     *
353
+     * @return  mixed  The array value if it exists, null otherwise.
354
+     *
355
+     * @since   2.0
356
+     */
357
+    public function offsetGet($offset)
358
+    {
359
+        return $this->get($offset);
360
+    }
361
+
362
+    /**
363
+     * Sets an offset in the iterator.
364
+     *
365
+     * @param   mixed $offset The array offset.
366
+     * @param   mixed $value  The array value.
367
+     *
368
+     * @return  void
369
+     *
370
+     * @since   2.0
371
+     */
372
+    public function offsetSet($offset, $value)
373
+    {
374
+        $this->set($offset, $value);
375
+    }
376
+
377
+    /**
378
+     * Unsets an offset in the iterator.
379
+     *
380
+     * @param   mixed $offset The array offset.
381
+     *
382
+     * @return  void
383
+     *
384
+     * @since   2.0
385
+     */
386
+    public function offsetUnset($offset)
387
+    {
388
+        $this->set($offset, null);
389
+    }
390
+
391
+    /**
392
+     * Set a structure value and convert object to array.
393
+     *
394
+     * @param   string $path  Structure Path (e.g. foo.content.showauthor)
395
+     * @param   mixed  $value Value of entry.
396
+     *
397
+     * @return  static  Return self to support chaining.
398
+     *
399
+     * @since   2.0
400
+     */
401
+    public function set($path, $value)
402
+    {
403
+        if ($value instanceof ValueReference) {
404
+            $value = $value->get($this);
405
+        }
406
+
407
+        if (\is_array($value) || \is_object($value)) {
408
+            $value = StructureHelper::toArray($value, true);
409
+        }
410
+
411
+        StructureHelper::setByPath($this->data, $path, $value, $this->separator);
412
+
413
+        return $this;
414
+    }
415
+
416
+    /**
417
+     * Set a structure value.
418
+     *
419
+     * @param   string $path  Structure Path (e.g. foo.content.showauthor)
420
+     * @param   mixed  $value Value of entry.
421
+     *
422
+     * @return  static  Return self to support chaining.
423
+     *
424
+     * @since   2.1
425
+     */
426
+    public function setRaw($path, $value)
427
+    {
428
+        StructureHelper::setByPath($this->data, $path, $value, $this->separator);
429
+
430
+        return $this;
431
+    }
432
+
433
+    /**
434
+     * Transforms a namespace to an array
435
+     *
436
+     * @return  array  An associative array holding the namespace data
437
+     *
438
+     * @since   2.0
439
+     */
440
+    public function toArray()
441
+    {
442
+        return (array) $this->asArray($this->data);
443
+    }
444
+
445
+    /**
446
+     * Transforms a namespace to an object
447
+     *
448
+     * @param   string $class The class of object.
449
+     *
450
+     * @return  object   An an object holding the namespace data
451
+     *
452
+     * @since   2.0
453
+     */
454
+    public function toObject($class = 'stdClass')
455
+    {
456
+        return StructureHelper::toObject($this->data, $class);
457
+    }
458
+
459
+    /**
460
+     * Get a namespace in a given string format
461
+     *
462
+     * @param   string $format  Format to return the string in
463
+     * @param   mixed  $options Parameters used by the formatter, see formatters for more info
464
+     *
465
+     * @return  string   Namespace in string format
466
+     *
467
+     * @since   2.0
468
+     */
469
+    public function toString($format = Format::JSON, $options = [])
470
+    {
471
+        return StructureHelper::toString($this->data, $format, $options);
472
+    }
473
+
474
+    /**
475
+     * Method to recursively bind data to a parent object.
476
+     *
477
+     * @param   array   $parent  The parent object on which to attach the data values.
478
+     * @param   mixed   $data    An array or object of data to bind to the parent object.
479
+     * @param   boolean $raw     Set to false to convert all object to array.
480
+     * @param   array   $options The options to bind data.
481
+     *
482
+     * @return  void
483
+     */
484
+    protected function bindData(&$parent, $data, $raw = false, array $options = [])
485
+    {
486
+        // Ensure the input data is an array.
487
+        if (!$raw) {
488
+            $data = StructureHelper::toArray($data, true);
489
+        }
490
+
491
+        $onlyExists = !empty($options['only_exists']);
492
+
493
+        foreach ($data as $key => $value) {
494
+            if (\in_array($value, $this->ignoreValues, true)) {
495
+                continue;
496
+            }
497
+
498
+            if ($onlyExists && !isset($parent[$key])) {
499
+                continue;
500
+            }
501
+
502
+            if (\is_array($value)) {
503
+                if (!isset($parent[$key]) || !\is_array($parent[$key])) {
504
+                    $parent[$key] = [];
505
+                }
506
+
507
+                $this->bindData($parent[$key], $value, $raw);
508
+            } else {
509
+                $parent[$key] = $this->resolveValue($value);
510
+            }
511
+        }
512
+    }
513
+
514
+    /**
515
+     * Method to recursively convert an object of data to an array.
516
+     *
517
+     * @param   mixed $data An object of data to return as an array.
518
+     *
519
+     * @return  array  Array representation of the input object.
520
+     *
521
+     * @since   2.0
522
+     */
523
+    protected function asArray($data)
524
+    {
525
+        $array = [];
526
+
527
+        if (\is_object($data)) {
528
+            $data = get_object_vars($data);
529
+        }
530
+
531
+        foreach ($data as $k => $v) {
532
+            if (\is_object($v) || \is_array($v)) {
533
+                $array[$k] = $this->asArray($v);
534
+            } else {
535
+                $array[$k] = $v;
536
+            }
537
+        }
538
+
539
+        return $array;
540
+    }
541
+
542
+    /**
543
+     * Dump to on dimension array.
544
+     *
545
+     * @param string $separator The key separator.
546
+     *
547
+     * @return  string[] Dumped array.
548
+     */
549
+    public function flatten($separator = '.')
550
+    {
551
+        return StructureHelper::flatten($this->data, $separator);
552
+    }
553
+
554
+    /**
555
+     * Method to get property Separator
556
+     *
557
+     * @return  string
558
+     *
559
+     * @since   2.1
560
+     */
561
+    public function getSeparator()
562
+    {
563
+        return $this->separator;
564
+    }
565
+
566
+    /**
567
+     * Method to set property separator
568
+     *
569
+     * @param   string $separator
570
+     *
571
+     * @return  static  Return self to support chaining.
572
+     *
573
+     * @since   2.1
574
+     */
575
+    public function setSeparator($separator)
576
+    {
577
+        $this->separator = $separator;
578
+
579
+        return $this;
580
+    }
581
+
582
+    /**
583
+     * Push value to a path in structure
584
+     *
585
+     * @param   string $path  Parent structure Path (e.g. windwalker.content.showauthor)
586
+     * @param   mixed  $value Value of entry, one or more elements.
587
+     *
588
+     * @return  integer  the new number of elements in the array.
589
+     *
590
+     * @since   2.1
591
+     */
592
+    public function push($path, $value)
593
+    {
594
+        $node = $this->get($path);
595
+
596
+        if (!$node) {
597
+            $node = [];
598
+        } elseif (\is_object($node)) {
599
+            $node = get_object_vars($node);
600
+        }
601
+
602
+        if (!\is_array($node)) {
603
+            throw new \UnexpectedValueException(
604
+                sprintf(
605
+                    'The value at path: %s should be object or array but is %s.',
606
+                    $path,
607
+                    \gettype($node)
608
+                )
609
+            );
610
+        }
611
+
612
+        $args = \func_get_args();
613
+
614
+        if (count($args) <= 2) {
615
+            $num = array_push($node, $value);
616
+        } else {
617
+            $args[0] = &$node;
618
+
619
+            $num = call_user_func_array('array_push', $args);
620
+        }
621
+
622
+        $this->set($path, $node);
623
+
624
+        return $num;
625
+    }
626
+
627
+    /**
628
+     * Prepend value to a path in structure.
629
+     *
630
+     * @param   string $path  Parent structure Path (e.g. windwalker.content.showauthor)
631
+     * @param   mixed  $value Value of entry, one or more elements.
632
+     *
633
+     * @return  integer  the new number of elements in the array.
634
+     *
635
+     * @since   2.1
636
+     */
637
+    public function unshift($path, $value)
638
+    {
639
+        $node = $this->get($path);
640
+
641
+        if (!$node) {
642
+            $node = [];
643
+        } elseif (\is_object($node)) {
644
+            $node = get_object_vars($node);
645
+        }
646
+
647
+        if (!\is_array($node)) {
648
+            throw new \UnexpectedValueException(
649
+                sprintf(
650
+                    'The value at path: %s should be object or array but is %s.',
651
+                    $path,
652
+                    gettype($node)
653
+                )
654
+            );
655
+        }
656
+
657
+        $args = \func_get_args();
658
+
659
+        if (\count($args) <= 2) {
660
+            $key = array_unshift($node, $value);
661
+        } else {
662
+            $args[0] = &$node;
663
+
664
+            $key = call_user_func_array('array_unshift', $args);
665
+        }
666
+
667
+        $this->set($path, $node);
668
+
669
+        return $key;
670
+    }
671
+
672
+    /**
673
+     * To remove first element from the path of this structure.
674
+     *
675
+     * @param   string $path The structure path.
676
+     *
677
+     * @return  mixed  The shifted value, or null if array is empty.
678
+     */
679
+    public function shift($path)
680
+    {
681
+        $node = $this->get($path);
682
+
683
+        if (\is_object($node)) {
684
+            $node = get_object_vars($node);
685
+        }
686
+
687
+        if (!\is_array($node)) {
688
+            throw new \UnexpectedValueException(
689
+                sprintf(
690
+                    'The value at path: %s should be object or array but is %s.',
691
+                    $path,
692
+                    \gettype($node)
693
+                )
694
+            );
695
+        }
696
+
697
+        $value = array_shift($node);
698
+
699
+        $this->set($path, $node);
700
+
701
+        return $value;
702
+    }
703
+
704
+    /**
705
+     * To remove last element from the path of this structure.
706
+     *
707
+     * @param   string $path The structure path.
708
+     *
709
+     * @return  mixed  The shifted value, or &null; if array is empty.
710
+     */
711
+    public function pop($path)
712
+    {
713
+        $node = $this->get($path);
714
+
715
+        if (\is_object($node)) {
716
+            $node = get_object_vars($node);
717
+        }
718
+
719
+        if (!\is_array($node)) {
720
+            throw new \UnexpectedValueException(
721
+                sprintf(
722
+                    'The value at path: %s should be object or array but is %s.',
723
+                    $path,
724
+                    \gettype($node)
725
+                )
726
+            );
727
+        }
728
+
729
+        $value = array_pop($node);
730
+
731
+        $this->set($path, $node);
732
+
733
+        return $value;
734
+    }
735
+
736
+    /**
737
+     * Gets this object represented as an RecursiveArrayIterator.
738
+     *
739
+     * This allows the data properties to be accessed via a foreach statement.
740
+     *
741
+     * You can wrap this iterator by RecursiveIteratorIterator that will support recursive foreach.
742
+     * Example: `foreach (new \RecursiveIteratorIterator($structure) as $value)`
743
+     *
744
+     * @return  \RecursiveArrayIterator  This object represented as an RecursiveArrayIterator.
745
+     *
746
+     * @see     IteratorAggregate::getIterator()
747
+     * @since   2.1
748
+     */
749
+    public function getIterator()
750
+    {
751
+        return new \RecursiveArrayIterator($this->data);
752
+    }
753
+
754
+    /**
755
+     * Count elements of the data object
756
+     *
757
+     * @return  integer  The custom count as an integer.
758
+     *
759
+     * @link    http://php.net/manual/en/countable.count.php
760
+     * @since   2.1
761
+     */
762
+    public function count()
763
+    {
764
+        return \count($this->data);
765
+    }
766
+
767
+    /**
768
+     * resolveValue
769
+     *
770
+     * @param mixed|ValueReference $value
771
+     *
772
+     * @return  mixed
773
+     *
774
+     * @since  3.5.1
775
+     */
776
+    protected function resolveValue($value)
777
+    {
778
+        if ($value instanceof ValueReference) {
779
+            $value = $value->get($this);
780
+        }
781
+
782
+        return $value;
783
+    }
784
+
785
+    /**
786
+     * Method to get property IgnoreValues
787
+     *
788
+     * @return  array
789
+     */
790
+    public function getIgnoreValues()
791
+    {
792
+        return $this->ignoreValues;
793
+    }
794
+
795
+    /**
796
+     * Method to set property ignoreValues
797
+     *
798
+     * @param   array $ignoreValues
799
+     *
800
+     * @return  static  Return self to support chaining.
801
+     */
802
+    public function setIgnoreValues($ignoreValues)
803
+    {
804
+        $this->ignoreValues = (array) $ignoreValues;
805
+
806
+        return $this;
807
+    }
808
+}