1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Charcoal\Config; |
4
|
|
|
|
5
|
|
|
use InvalidArgumentException; |
6
|
|
|
|
7
|
|
|
/** |
8
|
|
|
* Provides an object with the ability to perform lookups into multi-dimensional arrays. |
9
|
|
|
* |
10
|
|
|
* This is a full implementation of {@see SeparatorAwareInterface}. |
11
|
|
|
*/ |
12
|
|
|
trait SeparatorAwareTrait |
13
|
|
|
{ |
14
|
|
|
/** |
15
|
|
|
* Token for accessing nested data. |
16
|
|
|
* |
17
|
|
|
* Is empty by default (which disables the separator feature). |
18
|
|
|
* |
19
|
|
|
* @var string |
20
|
|
|
*/ |
21
|
|
|
protected $separator = ''; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* Sets the token for traversing a data-tree. |
25
|
|
|
* |
26
|
|
|
* @param string $separator The single-character token to delimit nested data. |
27
|
|
|
* If the token is an empty string, data-tree traversal is disabled. |
28
|
|
|
* @throws InvalidArgumentException If the $separator is invalid. |
29
|
|
|
* @return self |
30
|
|
|
*/ |
31
|
|
|
final public function setSeparator($separator) |
32
|
|
|
{ |
33
|
|
|
if (!is_string($separator)) { |
34
|
|
|
throw new InvalidArgumentException( |
35
|
|
|
'Separator must be a string' |
36
|
|
|
); |
37
|
|
|
} |
38
|
|
|
|
39
|
|
|
if (strlen($separator) > 1) { |
40
|
|
|
throw new InvalidArgumentException( |
41
|
|
|
'Separator must be one-character, or empty' |
42
|
|
|
); |
43
|
|
|
} |
44
|
|
|
|
45
|
|
|
$this->separator = $separator; |
46
|
|
|
return $this; |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* Gets the token for traversing a data-tree, if any. |
51
|
|
|
* |
52
|
|
|
* @return string |
53
|
|
|
*/ |
54
|
|
|
final public function separator() |
55
|
|
|
{ |
56
|
|
|
return $this->separator; |
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* Determines if this store contains the key-path and if its value is not NULL. |
61
|
|
|
* |
62
|
|
|
* Traverses each node in the key-path until the endpoint is located. |
63
|
|
|
* |
64
|
|
|
* @param string $key The key-path to check. |
65
|
|
|
* @return boolean TRUE if $key exists and has a value other than NULL, FALSE otherwise. |
66
|
|
|
*/ |
67
|
|
|
final protected function hasWithSeparator($key) |
68
|
|
|
{ |
69
|
|
|
$structure = $this; |
70
|
|
|
$splitKeys = explode($this->separator, $key); |
71
|
|
View Code Duplication |
foreach ($splitKeys as $key) { |
|
|
|
|
72
|
|
|
if (!isset($structure[$key])) { |
73
|
|
|
return false; |
74
|
|
|
} |
75
|
|
|
if (!is_array($structure[$key])) { |
76
|
|
|
return true; |
77
|
|
|
} |
78
|
|
|
$structure = $structure[$key]; |
79
|
|
|
} |
80
|
|
|
return true; |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Returns the value from the key-path found on this object. |
85
|
|
|
* |
86
|
|
|
* Traverses each node in the key-path until the endpoint is located. |
87
|
|
|
* |
88
|
|
|
* @param string $key The key-path to retrieve. |
89
|
|
|
* @return mixed Value of the requested $key on success, NULL if the $key is not set. |
90
|
|
|
*/ |
91
|
|
|
final protected function getWithSeparator($key) |
92
|
|
|
{ |
93
|
|
|
$structure = $this; |
94
|
|
|
$splitKeys = explode($this->separator, $key); |
95
|
|
View Code Duplication |
foreach ($splitKeys as $key) { |
|
|
|
|
96
|
|
|
if (!isset($structure[$key])) { |
97
|
|
|
return null; |
98
|
|
|
} |
99
|
|
|
if (!is_array($structure[$key])) { |
100
|
|
|
return $structure[$key]; |
101
|
|
|
} |
102
|
|
|
$structure = $structure[$key]; |
103
|
|
|
} |
104
|
|
|
return $structure; |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* Assign a value to the key-path, replacing / merging existing data with the same endpoint. |
109
|
|
|
* |
110
|
|
|
* Traverses, in reverse, each node in the key-path from the endpoint. |
111
|
|
|
* |
112
|
|
|
* @param string $key The key-path to assign $value to. |
113
|
|
|
* @param mixed $value The data value to assign to $key. |
114
|
|
|
* @return void |
115
|
|
|
*/ |
116
|
|
|
final protected function setWithSeparator($key, $value) |
117
|
|
|
{ |
118
|
|
|
$structure = $value; |
119
|
|
|
$splitKeys = array_reverse(explode($this->separator, $key)); |
120
|
|
|
foreach ($splitKeys as $key) { |
121
|
|
|
$structure = [ |
122
|
|
|
$key => $structure |
123
|
|
|
]; |
124
|
|
|
} |
125
|
|
|
|
126
|
|
View Code Duplication |
if (isset($this[$key])) { |
|
|
|
|
127
|
|
|
$data = $this[$key]; |
128
|
|
|
if (is_array($data)) { |
129
|
|
|
$structure[$key] = array_replace_recursive($data, $structure[$key]); |
130
|
|
|
} |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
$this[$key] = $structure[$key]; |
134
|
|
|
} |
135
|
|
|
} |
136
|
|
|
|
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.