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