@@ -19,250 +19,250 @@ |
||
19 | 19 | abstract class JsonDataNode implements JsonDataNodeInterface |
20 | 20 | { |
21 | 21 | |
22 | - /** |
|
23 | - * @var JsonDataNodeValidator |
|
24 | - */ |
|
25 | - protected $validator; |
|
26 | - |
|
27 | - /** |
|
28 | - * @var array |
|
29 | - */ |
|
30 | - private $data = []; |
|
31 | - |
|
32 | - /** |
|
33 | - * @var string |
|
34 | - */ |
|
35 | - private $domain = ''; |
|
36 | - |
|
37 | - /** |
|
38 | - * @var boolean |
|
39 | - */ |
|
40 | - private $initialized = false; |
|
41 | - |
|
42 | - /** |
|
43 | - * @var string |
|
44 | - */ |
|
45 | - private $node_name = ''; |
|
46 | - |
|
47 | - /** |
|
48 | - * @var int |
|
49 | - */ |
|
50 | - private $order = 50; |
|
51 | - |
|
52 | - |
|
53 | - /** |
|
54 | - * @param JsonDataNodeValidator $validator |
|
55 | - * @throws DomainException |
|
56 | - */ |
|
57 | - public function __construct(JsonDataNodeValidator $validator) |
|
58 | - { |
|
59 | - $this->validator = $validator; |
|
60 | - } |
|
61 | - |
|
62 | - |
|
63 | - /** |
|
64 | - * for adding primitive data like arrays, integers, or strings |
|
65 | - * |
|
66 | - * @param string $key |
|
67 | - * @param mixed $data |
|
68 | - * @throws DomainException |
|
69 | - */ |
|
70 | - protected function addData(string $key, $data) |
|
71 | - { |
|
72 | - if ($this->validator->propertyNotSet($this->data, $key)) { |
|
73 | - $this->data[ $key ] = $data; |
|
74 | - } |
|
75 | - } |
|
76 | - |
|
77 | - |
|
78 | - /** |
|
79 | - * for setting value of the entire data array for the node |
|
80 | - * |
|
81 | - * @param array $data |
|
82 | - * @throws DomainException |
|
83 | - */ |
|
84 | - protected function setDataArray(array $data) |
|
85 | - { |
|
86 | - if ($this->validator->dataArrayEmpty($this)) { |
|
87 | - $this->data = $data; |
|
88 | - } |
|
89 | - } |
|
90 | - |
|
91 | - |
|
92 | - /** |
|
93 | - * for embedding other JsonDataNode objects within this one |
|
94 | - * |
|
95 | - * @param JsonDataNode $data_node |
|
96 | - * @throws DomainException |
|
97 | - */ |
|
98 | - public function addDataNode(JsonDataNode $data_node) |
|
99 | - { |
|
100 | - if ($data_node->isNotInitialized()) { |
|
101 | - // $data_node->initialize(); |
|
102 | - $key = $data_node->nodeName(); |
|
103 | - $this->addData($key, $data_node); |
|
104 | - // if the node being added specifies a domain (use case) |
|
105 | - // and this is the primary data node, then set the domain |
|
106 | - if ($this instanceof PrimaryJsonDataNode && $data_node->domain()) { |
|
107 | - $this->setDomain($data_node->domain()); |
|
108 | - } |
|
109 | - } |
|
110 | - } |
|
111 | - |
|
112 | - |
|
113 | - /** |
|
114 | - * sets the domain (use case) that this data node provides data for |
|
115 | - * |
|
116 | - * @param string $domain |
|
117 | - * @throws DomainException |
|
118 | - */ |
|
119 | - protected function setDomain(string $domain) |
|
120 | - { |
|
121 | - if ($this->domain !== '') { |
|
122 | - $this->validator->overwriteError($domain, 'domain route'); |
|
123 | - } |
|
124 | - $this->domain = $domain; |
|
125 | - } |
|
126 | - |
|
127 | - |
|
128 | - /** |
|
129 | - * used to mark the data node as having been processed |
|
130 | - * |
|
131 | - * @param bool $initialized |
|
132 | - */ |
|
133 | - protected function setInitialized(bool $initialized) |
|
134 | - { |
|
135 | - $this->initialized = filter_var($initialized, FILTER_VALIDATE_BOOLEAN); |
|
136 | - } |
|
137 | - |
|
138 | - |
|
139 | - /** |
|
140 | - * self explanatory (i hope) |
|
141 | - * |
|
142 | - * @param string $node_name |
|
143 | - * @throws DomainException |
|
144 | - */ |
|
145 | - protected function setNodeName(string $node_name) |
|
146 | - { |
|
147 | - $this->validator->validateCriticalProperty($node_name, 'node name'); |
|
148 | - $this->node_name = $node_name; |
|
149 | - // by default set the data node order property by the alphabetical position of the first letter of its name |
|
150 | - // we do this by passing the node name (in UPPERCASE) to ord() to get its ASCII position |
|
151 | - // then we subtract 64 (cuz A has a position of 65) then multiply by 10 just to space things out a bit. |
|
152 | - // this allows a data node to set its order upon construction to some other value |
|
153 | - // so that it can squeak into whatever position it needs to be in, like 55 |
|
154 | - $this->setOrder((ord(strtoupper($this->node_name)) - 64) * 10); |
|
155 | - } |
|
156 | - |
|
157 | - |
|
158 | - /** |
|
159 | - * the actual data in key value array format |
|
160 | - * |
|
161 | - * @param bool $sort |
|
162 | - * @return array |
|
163 | - */ |
|
164 | - public function data(bool $sort = false): array |
|
165 | - { |
|
166 | - if ($sort) { |
|
167 | - // check if data array has non-numerical keys and use a custom sort algorithm, else sort by keys |
|
168 | - EEH_Array::is_associative_array($this->data) |
|
169 | - ? uasort( |
|
170 | - $this->data, |
|
171 | - function ($a, $b) { |
|
172 | - // check if each incoming argument is a node and if they have an order set |
|
173 | - // if so, then use that for our sorting comparison. otherwise use the node's name... |
|
174 | - // unless it's NOT a node, in which case use the arg value if it is scalar, or 0 if not. |
|
175 | - if ($a instanceof JsonDataNode) { |
|
176 | - $a_ord = $a->order() ?: $a->nodeName(); |
|
177 | - } else { |
|
178 | - $a_ord = is_scalar($a) ?: 0; |
|
179 | - } |
|
180 | - if ($b instanceof JsonDataNode) { |
|
181 | - $b_ord = $b->order() ?: $b->nodeName(); |
|
182 | - } else { |
|
183 | - $b_ord = is_scalar($b) ?: 0; |
|
184 | - } |
|
185 | - return $a_ord <=> $b_ord; |
|
186 | - } |
|
187 | - ) |
|
188 | - // sort numerically indexed arrays by their keys |
|
189 | - : ksort($this->data); |
|
190 | - } |
|
191 | - return $this->data; |
|
192 | - } |
|
193 | - |
|
194 | - |
|
195 | - /** |
|
196 | - * the domain (use case) that this data node provides data for |
|
197 | - * |
|
198 | - * @return string |
|
199 | - */ |
|
200 | - public function domain(): string |
|
201 | - { |
|
202 | - return $this->domain; |
|
203 | - } |
|
204 | - |
|
205 | - |
|
206 | - /** |
|
207 | - * true if the data node has been initialized, |
|
208 | - * which entails retrieving the required data and adding it to the data node data array |
|
209 | - * |
|
210 | - * @return bool |
|
211 | - */ |
|
212 | - public function isInitialized(): bool |
|
213 | - { |
|
214 | - return $this->initialized; |
|
215 | - } |
|
216 | - |
|
217 | - |
|
218 | - /** |
|
219 | - * true if the data node has NOT been initialized |
|
220 | - * |
|
221 | - * @return bool |
|
222 | - */ |
|
223 | - public function isNotInitialized(): bool |
|
224 | - { |
|
225 | - return ! $this->initialized; |
|
226 | - } |
|
227 | - |
|
228 | - |
|
229 | - /** |
|
230 | - * Specify data which should be serialized to JSON |
|
231 | - * |
|
232 | - * @link https://php.net/manual/en/jsonserializable.jsonserialize.php |
|
233 | - * @return array data which can be serialized by json_encode |
|
234 | - */ |
|
235 | - public function jsonSerialize(): array |
|
236 | - { |
|
237 | - return $this->data; |
|
238 | - } |
|
239 | - |
|
240 | - |
|
241 | - /** |
|
242 | - * self explanatory (i hope) |
|
243 | - * |
|
244 | - * @return string |
|
245 | - */ |
|
246 | - public function nodeName(): string |
|
247 | - { |
|
248 | - return $this->node_name; |
|
249 | - } |
|
250 | - |
|
251 | - |
|
252 | - /** |
|
253 | - * @return int |
|
254 | - */ |
|
255 | - public function order(): ?int |
|
256 | - { |
|
257 | - return $this->order; |
|
258 | - } |
|
259 | - |
|
260 | - |
|
261 | - /** |
|
262 | - * @param int $order |
|
263 | - */ |
|
264 | - protected function setOrder(int $order): void |
|
265 | - { |
|
266 | - $this->order = absint($order); |
|
267 | - } |
|
22 | + /** |
|
23 | + * @var JsonDataNodeValidator |
|
24 | + */ |
|
25 | + protected $validator; |
|
26 | + |
|
27 | + /** |
|
28 | + * @var array |
|
29 | + */ |
|
30 | + private $data = []; |
|
31 | + |
|
32 | + /** |
|
33 | + * @var string |
|
34 | + */ |
|
35 | + private $domain = ''; |
|
36 | + |
|
37 | + /** |
|
38 | + * @var boolean |
|
39 | + */ |
|
40 | + private $initialized = false; |
|
41 | + |
|
42 | + /** |
|
43 | + * @var string |
|
44 | + */ |
|
45 | + private $node_name = ''; |
|
46 | + |
|
47 | + /** |
|
48 | + * @var int |
|
49 | + */ |
|
50 | + private $order = 50; |
|
51 | + |
|
52 | + |
|
53 | + /** |
|
54 | + * @param JsonDataNodeValidator $validator |
|
55 | + * @throws DomainException |
|
56 | + */ |
|
57 | + public function __construct(JsonDataNodeValidator $validator) |
|
58 | + { |
|
59 | + $this->validator = $validator; |
|
60 | + } |
|
61 | + |
|
62 | + |
|
63 | + /** |
|
64 | + * for adding primitive data like arrays, integers, or strings |
|
65 | + * |
|
66 | + * @param string $key |
|
67 | + * @param mixed $data |
|
68 | + * @throws DomainException |
|
69 | + */ |
|
70 | + protected function addData(string $key, $data) |
|
71 | + { |
|
72 | + if ($this->validator->propertyNotSet($this->data, $key)) { |
|
73 | + $this->data[ $key ] = $data; |
|
74 | + } |
|
75 | + } |
|
76 | + |
|
77 | + |
|
78 | + /** |
|
79 | + * for setting value of the entire data array for the node |
|
80 | + * |
|
81 | + * @param array $data |
|
82 | + * @throws DomainException |
|
83 | + */ |
|
84 | + protected function setDataArray(array $data) |
|
85 | + { |
|
86 | + if ($this->validator->dataArrayEmpty($this)) { |
|
87 | + $this->data = $data; |
|
88 | + } |
|
89 | + } |
|
90 | + |
|
91 | + |
|
92 | + /** |
|
93 | + * for embedding other JsonDataNode objects within this one |
|
94 | + * |
|
95 | + * @param JsonDataNode $data_node |
|
96 | + * @throws DomainException |
|
97 | + */ |
|
98 | + public function addDataNode(JsonDataNode $data_node) |
|
99 | + { |
|
100 | + if ($data_node->isNotInitialized()) { |
|
101 | + // $data_node->initialize(); |
|
102 | + $key = $data_node->nodeName(); |
|
103 | + $this->addData($key, $data_node); |
|
104 | + // if the node being added specifies a domain (use case) |
|
105 | + // and this is the primary data node, then set the domain |
|
106 | + if ($this instanceof PrimaryJsonDataNode && $data_node->domain()) { |
|
107 | + $this->setDomain($data_node->domain()); |
|
108 | + } |
|
109 | + } |
|
110 | + } |
|
111 | + |
|
112 | + |
|
113 | + /** |
|
114 | + * sets the domain (use case) that this data node provides data for |
|
115 | + * |
|
116 | + * @param string $domain |
|
117 | + * @throws DomainException |
|
118 | + */ |
|
119 | + protected function setDomain(string $domain) |
|
120 | + { |
|
121 | + if ($this->domain !== '') { |
|
122 | + $this->validator->overwriteError($domain, 'domain route'); |
|
123 | + } |
|
124 | + $this->domain = $domain; |
|
125 | + } |
|
126 | + |
|
127 | + |
|
128 | + /** |
|
129 | + * used to mark the data node as having been processed |
|
130 | + * |
|
131 | + * @param bool $initialized |
|
132 | + */ |
|
133 | + protected function setInitialized(bool $initialized) |
|
134 | + { |
|
135 | + $this->initialized = filter_var($initialized, FILTER_VALIDATE_BOOLEAN); |
|
136 | + } |
|
137 | + |
|
138 | + |
|
139 | + /** |
|
140 | + * self explanatory (i hope) |
|
141 | + * |
|
142 | + * @param string $node_name |
|
143 | + * @throws DomainException |
|
144 | + */ |
|
145 | + protected function setNodeName(string $node_name) |
|
146 | + { |
|
147 | + $this->validator->validateCriticalProperty($node_name, 'node name'); |
|
148 | + $this->node_name = $node_name; |
|
149 | + // by default set the data node order property by the alphabetical position of the first letter of its name |
|
150 | + // we do this by passing the node name (in UPPERCASE) to ord() to get its ASCII position |
|
151 | + // then we subtract 64 (cuz A has a position of 65) then multiply by 10 just to space things out a bit. |
|
152 | + // this allows a data node to set its order upon construction to some other value |
|
153 | + // so that it can squeak into whatever position it needs to be in, like 55 |
|
154 | + $this->setOrder((ord(strtoupper($this->node_name)) - 64) * 10); |
|
155 | + } |
|
156 | + |
|
157 | + |
|
158 | + /** |
|
159 | + * the actual data in key value array format |
|
160 | + * |
|
161 | + * @param bool $sort |
|
162 | + * @return array |
|
163 | + */ |
|
164 | + public function data(bool $sort = false): array |
|
165 | + { |
|
166 | + if ($sort) { |
|
167 | + // check if data array has non-numerical keys and use a custom sort algorithm, else sort by keys |
|
168 | + EEH_Array::is_associative_array($this->data) |
|
169 | + ? uasort( |
|
170 | + $this->data, |
|
171 | + function ($a, $b) { |
|
172 | + // check if each incoming argument is a node and if they have an order set |
|
173 | + // if so, then use that for our sorting comparison. otherwise use the node's name... |
|
174 | + // unless it's NOT a node, in which case use the arg value if it is scalar, or 0 if not. |
|
175 | + if ($a instanceof JsonDataNode) { |
|
176 | + $a_ord = $a->order() ?: $a->nodeName(); |
|
177 | + } else { |
|
178 | + $a_ord = is_scalar($a) ?: 0; |
|
179 | + } |
|
180 | + if ($b instanceof JsonDataNode) { |
|
181 | + $b_ord = $b->order() ?: $b->nodeName(); |
|
182 | + } else { |
|
183 | + $b_ord = is_scalar($b) ?: 0; |
|
184 | + } |
|
185 | + return $a_ord <=> $b_ord; |
|
186 | + } |
|
187 | + ) |
|
188 | + // sort numerically indexed arrays by their keys |
|
189 | + : ksort($this->data); |
|
190 | + } |
|
191 | + return $this->data; |
|
192 | + } |
|
193 | + |
|
194 | + |
|
195 | + /** |
|
196 | + * the domain (use case) that this data node provides data for |
|
197 | + * |
|
198 | + * @return string |
|
199 | + */ |
|
200 | + public function domain(): string |
|
201 | + { |
|
202 | + return $this->domain; |
|
203 | + } |
|
204 | + |
|
205 | + |
|
206 | + /** |
|
207 | + * true if the data node has been initialized, |
|
208 | + * which entails retrieving the required data and adding it to the data node data array |
|
209 | + * |
|
210 | + * @return bool |
|
211 | + */ |
|
212 | + public function isInitialized(): bool |
|
213 | + { |
|
214 | + return $this->initialized; |
|
215 | + } |
|
216 | + |
|
217 | + |
|
218 | + /** |
|
219 | + * true if the data node has NOT been initialized |
|
220 | + * |
|
221 | + * @return bool |
|
222 | + */ |
|
223 | + public function isNotInitialized(): bool |
|
224 | + { |
|
225 | + return ! $this->initialized; |
|
226 | + } |
|
227 | + |
|
228 | + |
|
229 | + /** |
|
230 | + * Specify data which should be serialized to JSON |
|
231 | + * |
|
232 | + * @link https://php.net/manual/en/jsonserializable.jsonserialize.php |
|
233 | + * @return array data which can be serialized by json_encode |
|
234 | + */ |
|
235 | + public function jsonSerialize(): array |
|
236 | + { |
|
237 | + return $this->data; |
|
238 | + } |
|
239 | + |
|
240 | + |
|
241 | + /** |
|
242 | + * self explanatory (i hope) |
|
243 | + * |
|
244 | + * @return string |
|
245 | + */ |
|
246 | + public function nodeName(): string |
|
247 | + { |
|
248 | + return $this->node_name; |
|
249 | + } |
|
250 | + |
|
251 | + |
|
252 | + /** |
|
253 | + * @return int |
|
254 | + */ |
|
255 | + public function order(): ?int |
|
256 | + { |
|
257 | + return $this->order; |
|
258 | + } |
|
259 | + |
|
260 | + |
|
261 | + /** |
|
262 | + * @param int $order |
|
263 | + */ |
|
264 | + protected function setOrder(int $order): void |
|
265 | + { |
|
266 | + $this->order = absint($order); |
|
267 | + } |
|
268 | 268 | } |
@@ -70,7 +70,7 @@ discard block |
||
70 | 70 | protected function addData(string $key, $data) |
71 | 71 | { |
72 | 72 | if ($this->validator->propertyNotSet($this->data, $key)) { |
73 | - $this->data[ $key ] = $data; |
|
73 | + $this->data[$key] = $data; |
|
74 | 74 | } |
75 | 75 | } |
76 | 76 | |
@@ -168,7 +168,7 @@ discard block |
||
168 | 168 | EEH_Array::is_associative_array($this->data) |
169 | 169 | ? uasort( |
170 | 170 | $this->data, |
171 | - function ($a, $b) { |
|
171 | + function($a, $b) { |
|
172 | 172 | // check if each incoming argument is a node and if they have an order set |
173 | 173 | // if so, then use that for our sorting comparison. otherwise use the node's name... |
174 | 174 | // unless it's NOT a node, in which case use the arg value if it is scalar, or 0 if not. |
@@ -18,127 +18,127 @@ |
||
18 | 18 | class JsonDataNodeHandler |
19 | 19 | { |
20 | 20 | |
21 | - /** |
|
22 | - * @var PrimaryJsonDataNode $primary_data_node |
|
23 | - */ |
|
24 | - private $primary_data_node; |
|
25 | - |
|
26 | - /** |
|
27 | - * @var JsonDataNodeValidator $validator |
|
28 | - */ |
|
29 | - private $validator; |
|
30 | - |
|
31 | - |
|
32 | - /** |
|
33 | - * @param JsonDataNodeValidator $validator |
|
34 | - */ |
|
35 | - public function __construct(JsonDataNodeValidator $validator) |
|
36 | - { |
|
37 | - $this->validator = $validator; |
|
38 | - } |
|
39 | - |
|
40 | - |
|
41 | - /** |
|
42 | - * @param JsonDataNode $data_node |
|
43 | - * @throws DomainException |
|
44 | - */ |
|
45 | - public function addDataNode(JsonDataNode $data_node) |
|
46 | - { |
|
47 | - if ($data_node->isNotInitialized()) { |
|
48 | - $this->validatePrimaryDataNode($data_node); |
|
49 | - $this->primary_data_node->addDataNode($data_node); |
|
50 | - } |
|
51 | - } |
|
52 | - |
|
53 | - |
|
54 | - /** |
|
55 | - * @param PrimaryJsonDataNode $primary_data_node |
|
56 | - */ |
|
57 | - public function setPrimaryDataNode(PrimaryJsonDataNode $primary_data_node) |
|
58 | - { |
|
59 | - $this->primary_data_node = $primary_data_node; |
|
60 | - } |
|
61 | - |
|
62 | - |
|
63 | - /** |
|
64 | - * @param JsonDataNode $data_node |
|
65 | - * @param int $depth |
|
66 | - * @return array |
|
67 | - */ |
|
68 | - private function initializeDataNodes(JsonDataNode $data_node, int $depth = 0): array |
|
69 | - { |
|
70 | - $depth++; |
|
71 | - $data = []; |
|
72 | - // initialize the data node if not done already |
|
73 | - if ($data_node->isNotInitialized()) { |
|
74 | - $data_node->initialize(); |
|
75 | - // loop thru the data node's data array |
|
76 | - foreach ($data_node->data(true) as $child_node_name => $child_node) { |
|
77 | - // don't parse node if it's the primary, OR if depth has exceeded wp_json_encode() limit |
|
78 | - if ($child_node instanceof PrimaryJsonDataNode || $depth > 512) { |
|
79 | - continue; |
|
80 | - } |
|
81 | - $data[ $child_node_name ] = $child_node instanceof JsonDataNode |
|
82 | - // feed data node back into this function |
|
83 | - ? $this->initializeDataNodes($child_node, $depth) |
|
84 | - // or assign data directly |
|
85 | - : $child_node; |
|
86 | - } |
|
87 | - } |
|
88 | - return $data; |
|
89 | - } |
|
90 | - |
|
91 | - |
|
92 | - /** |
|
93 | - * @throws DomainException |
|
94 | - */ |
|
95 | - public function printDataNode() |
|
96 | - { |
|
97 | - if (!$this->primary_data_node instanceof PrimaryJsonDataNode) { |
|
98 | - return; |
|
99 | - } |
|
100 | - // validate that the domain, node name, and target script are set |
|
101 | - $domain = $this->primary_data_node->domain(); |
|
102 | - $node_name = $this->primary_data_node->nodeName(); |
|
103 | - $data_valid = $this->validator->validateCriticalProperty($domain, 'domain route', false) |
|
104 | - && $this->validator->validateCriticalProperty($node_name, 'node name', false); |
|
105 | - if (! $data_valid) { |
|
106 | - return; |
|
107 | - } |
|
108 | - // initialize and parse data from primary data node |
|
109 | - $data = $this->initializeDataNodes($this->primary_data_node); |
|
110 | - // this prepends the current domain "use case" to the front of the array |
|
111 | - $data = ['domain' => $domain] + $data; |
|
112 | - // add legacy i18n strings |
|
113 | - $data['eei18n'] = EE_Registry::$i18n_js_strings; |
|
114 | - // and finally, print the JSON encoded data to the DOM |
|
115 | - printf( |
|
116 | - "<script type='text/javascript' id='%s'>\nvar %s = %s\n</script>\n", |
|
117 | - $node_name, |
|
118 | - $node_name, |
|
119 | - json_encode($data) |
|
120 | - ); |
|
121 | - } |
|
122 | - |
|
123 | - |
|
124 | - /** |
|
125 | - * @param JsonDataNode $data_node |
|
126 | - * @throws DomainException |
|
127 | - */ |
|
128 | - private function validatePrimaryDataNode(JsonDataNode $data_node) |
|
129 | - { |
|
130 | - // set primary data node if that's what the incoming node is |
|
131 | - if ($data_node instanceof PrimaryJsonDataNode) { |
|
132 | - $this->setPrimaryDataNode($data_node); |
|
133 | - } |
|
134 | - // and don't allow other nodes to be set until a primary is set |
|
135 | - if (! $this->primary_data_node instanceof PrimaryJsonDataNode) { |
|
136 | - throw new DomainException( |
|
137 | - esc_html__( |
|
138 | - 'A PrimaryJsonDataNode needs to be set before data nodes can be added.', |
|
139 | - 'event_espresso' |
|
140 | - ) |
|
141 | - ); |
|
142 | - } |
|
143 | - } |
|
21 | + /** |
|
22 | + * @var PrimaryJsonDataNode $primary_data_node |
|
23 | + */ |
|
24 | + private $primary_data_node; |
|
25 | + |
|
26 | + /** |
|
27 | + * @var JsonDataNodeValidator $validator |
|
28 | + */ |
|
29 | + private $validator; |
|
30 | + |
|
31 | + |
|
32 | + /** |
|
33 | + * @param JsonDataNodeValidator $validator |
|
34 | + */ |
|
35 | + public function __construct(JsonDataNodeValidator $validator) |
|
36 | + { |
|
37 | + $this->validator = $validator; |
|
38 | + } |
|
39 | + |
|
40 | + |
|
41 | + /** |
|
42 | + * @param JsonDataNode $data_node |
|
43 | + * @throws DomainException |
|
44 | + */ |
|
45 | + public function addDataNode(JsonDataNode $data_node) |
|
46 | + { |
|
47 | + if ($data_node->isNotInitialized()) { |
|
48 | + $this->validatePrimaryDataNode($data_node); |
|
49 | + $this->primary_data_node->addDataNode($data_node); |
|
50 | + } |
|
51 | + } |
|
52 | + |
|
53 | + |
|
54 | + /** |
|
55 | + * @param PrimaryJsonDataNode $primary_data_node |
|
56 | + */ |
|
57 | + public function setPrimaryDataNode(PrimaryJsonDataNode $primary_data_node) |
|
58 | + { |
|
59 | + $this->primary_data_node = $primary_data_node; |
|
60 | + } |
|
61 | + |
|
62 | + |
|
63 | + /** |
|
64 | + * @param JsonDataNode $data_node |
|
65 | + * @param int $depth |
|
66 | + * @return array |
|
67 | + */ |
|
68 | + private function initializeDataNodes(JsonDataNode $data_node, int $depth = 0): array |
|
69 | + { |
|
70 | + $depth++; |
|
71 | + $data = []; |
|
72 | + // initialize the data node if not done already |
|
73 | + if ($data_node->isNotInitialized()) { |
|
74 | + $data_node->initialize(); |
|
75 | + // loop thru the data node's data array |
|
76 | + foreach ($data_node->data(true) as $child_node_name => $child_node) { |
|
77 | + // don't parse node if it's the primary, OR if depth has exceeded wp_json_encode() limit |
|
78 | + if ($child_node instanceof PrimaryJsonDataNode || $depth > 512) { |
|
79 | + continue; |
|
80 | + } |
|
81 | + $data[ $child_node_name ] = $child_node instanceof JsonDataNode |
|
82 | + // feed data node back into this function |
|
83 | + ? $this->initializeDataNodes($child_node, $depth) |
|
84 | + // or assign data directly |
|
85 | + : $child_node; |
|
86 | + } |
|
87 | + } |
|
88 | + return $data; |
|
89 | + } |
|
90 | + |
|
91 | + |
|
92 | + /** |
|
93 | + * @throws DomainException |
|
94 | + */ |
|
95 | + public function printDataNode() |
|
96 | + { |
|
97 | + if (!$this->primary_data_node instanceof PrimaryJsonDataNode) { |
|
98 | + return; |
|
99 | + } |
|
100 | + // validate that the domain, node name, and target script are set |
|
101 | + $domain = $this->primary_data_node->domain(); |
|
102 | + $node_name = $this->primary_data_node->nodeName(); |
|
103 | + $data_valid = $this->validator->validateCriticalProperty($domain, 'domain route', false) |
|
104 | + && $this->validator->validateCriticalProperty($node_name, 'node name', false); |
|
105 | + if (! $data_valid) { |
|
106 | + return; |
|
107 | + } |
|
108 | + // initialize and parse data from primary data node |
|
109 | + $data = $this->initializeDataNodes($this->primary_data_node); |
|
110 | + // this prepends the current domain "use case" to the front of the array |
|
111 | + $data = ['domain' => $domain] + $data; |
|
112 | + // add legacy i18n strings |
|
113 | + $data['eei18n'] = EE_Registry::$i18n_js_strings; |
|
114 | + // and finally, print the JSON encoded data to the DOM |
|
115 | + printf( |
|
116 | + "<script type='text/javascript' id='%s'>\nvar %s = %s\n</script>\n", |
|
117 | + $node_name, |
|
118 | + $node_name, |
|
119 | + json_encode($data) |
|
120 | + ); |
|
121 | + } |
|
122 | + |
|
123 | + |
|
124 | + /** |
|
125 | + * @param JsonDataNode $data_node |
|
126 | + * @throws DomainException |
|
127 | + */ |
|
128 | + private function validatePrimaryDataNode(JsonDataNode $data_node) |
|
129 | + { |
|
130 | + // set primary data node if that's what the incoming node is |
|
131 | + if ($data_node instanceof PrimaryJsonDataNode) { |
|
132 | + $this->setPrimaryDataNode($data_node); |
|
133 | + } |
|
134 | + // and don't allow other nodes to be set until a primary is set |
|
135 | + if (! $this->primary_data_node instanceof PrimaryJsonDataNode) { |
|
136 | + throw new DomainException( |
|
137 | + esc_html__( |
|
138 | + 'A PrimaryJsonDataNode needs to be set before data nodes can be added.', |
|
139 | + 'event_espresso' |
|
140 | + ) |
|
141 | + ); |
|
142 | + } |
|
143 | + } |
|
144 | 144 | } |
@@ -78,7 +78,7 @@ discard block |
||
78 | 78 | if ($child_node instanceof PrimaryJsonDataNode || $depth > 512) { |
79 | 79 | continue; |
80 | 80 | } |
81 | - $data[ $child_node_name ] = $child_node instanceof JsonDataNode |
|
81 | + $data[$child_node_name] = $child_node instanceof JsonDataNode |
|
82 | 82 | // feed data node back into this function |
83 | 83 | ? $this->initializeDataNodes($child_node, $depth) |
84 | 84 | // or assign data directly |
@@ -94,15 +94,15 @@ discard block |
||
94 | 94 | */ |
95 | 95 | public function printDataNode() |
96 | 96 | { |
97 | - if (!$this->primary_data_node instanceof PrimaryJsonDataNode) { |
|
97 | + if ( ! $this->primary_data_node instanceof PrimaryJsonDataNode) { |
|
98 | 98 | return; |
99 | 99 | } |
100 | 100 | // validate that the domain, node name, and target script are set |
101 | 101 | $domain = $this->primary_data_node->domain(); |
102 | 102 | $node_name = $this->primary_data_node->nodeName(); |
103 | - $data_valid = $this->validator->validateCriticalProperty($domain, 'domain route', false) |
|
103 | + $data_valid = $this->validator->validateCriticalProperty($domain, 'domain route', false) |
|
104 | 104 | && $this->validator->validateCriticalProperty($node_name, 'node name', false); |
105 | - if (! $data_valid) { |
|
105 | + if ( ! $data_valid) { |
|
106 | 106 | return; |
107 | 107 | } |
108 | 108 | // initialize and parse data from primary data node |
@@ -132,7 +132,7 @@ discard block |
||
132 | 132 | $this->setPrimaryDataNode($data_node); |
133 | 133 | } |
134 | 134 | // and don't allow other nodes to be set until a primary is set |
135 | - if (! $this->primary_data_node instanceof PrimaryJsonDataNode) { |
|
135 | + if ( ! $this->primary_data_node instanceof PrimaryJsonDataNode) { |
|
136 | 136 | throw new DomainException( |
137 | 137 | esc_html__( |
138 | 138 | 'A PrimaryJsonDataNode needs to be set before data nodes can be added.', |
@@ -13,203 +13,203 @@ |
||
13 | 13 | { |
14 | 14 | |
15 | 15 | |
16 | - /** |
|
17 | - * This method basically works the same as the PHP core function array_diff except it allows you to compare arrays |
|
18 | - * of EE_Base_Class objects NOTE: This will ONLY work on an array of EE_Base_Class objects |
|
19 | - * |
|
20 | - * @uses array_udiff core php function for setting up our own array comparison |
|
21 | - * @uses self::_compare_objects as the custom method for array_udiff |
|
22 | - * @param array $array1 an array of objects |
|
23 | - * @param array $array2 an array of objects |
|
24 | - * @return array an array of objects found in array 1 that aren't found in array 2. |
|
25 | - */ |
|
26 | - public static function object_array_diff($array1, $array2) |
|
27 | - { |
|
28 | - return array_udiff($array1, $array2, array('self', '_compare_objects')); |
|
29 | - } |
|
30 | - |
|
31 | - /** |
|
32 | - * Given that $arr is an array, determines if it's associative or numerically AND sequentially indexed |
|
33 | - * |
|
34 | - * @param array $array |
|
35 | - * @return boolean |
|
36 | - */ |
|
37 | - public static function is_associative_array(array $array): bool |
|
38 | - { |
|
39 | - return ! empty($array) && array_keys($array) !== range(0, count($array) - 1); |
|
40 | - } |
|
41 | - |
|
42 | - /** |
|
43 | - * Gets an item from the array and leave the array intact. Use in place of end() |
|
44 | - * when you don't want to change the array |
|
45 | - * |
|
46 | - * @param array $arr |
|
47 | - * @return mixed what ever is in the array |
|
48 | - */ |
|
49 | - public static function get_one_item_from_array($arr) |
|
50 | - { |
|
51 | - $item = end($arr); |
|
52 | - reset($arr); |
|
53 | - return $item; |
|
54 | - } |
|
55 | - |
|
56 | - /** |
|
57 | - * Detects if this is a multi-dimensional array (meaning that the top-level |
|
58 | - * values are themselves array. Eg array(array(...),...) |
|
59 | - * |
|
60 | - * @param mixed $arr |
|
61 | - * @return boolean |
|
62 | - */ |
|
63 | - public static function is_multi_dimensional_array($arr) |
|
64 | - { |
|
65 | - if (is_array($arr)) { |
|
66 | - $first_item = reset($arr); |
|
67 | - if (is_array($first_item)) { |
|
68 | - return true;// yep, there's at least 2 levels to this array |
|
69 | - } else { |
|
70 | - return false;// nope, only 1 level |
|
71 | - } |
|
72 | - } else { |
|
73 | - return false;// its not an array at all! |
|
74 | - } |
|
75 | - } |
|
76 | - |
|
77 | - /** |
|
78 | - * Shorthand for isset( $arr[ $index ] ) ? $arr[ $index ] : $default |
|
79 | - * |
|
80 | - * @param array $arr |
|
81 | - * @param mixed $index |
|
82 | - * @param mixed $default |
|
83 | - * @return mixed |
|
84 | - */ |
|
85 | - public static function is_set($arr, $index, $default) |
|
86 | - { |
|
87 | - return isset($arr[ $index ]) ? $arr[ $index ] : $default; |
|
88 | - } |
|
89 | - |
|
90 | - /** |
|
91 | - * Exactly like `maybe_unserialize`, but also accounts for a WP bug: http://core.trac.wordpress.org/ticket/26118 |
|
92 | - * |
|
93 | - * @param mixed $value usually a string, but could be an array or object |
|
94 | - * @return mixed the UN-serialized data |
|
95 | - */ |
|
96 | - public static function maybe_unserialize($value) |
|
97 | - { |
|
98 | - $data = maybe_unserialize($value); |
|
99 | - // it's possible that this still has serialized data if its the session. WP has a bug, http://core.trac.wordpress.org/ticket/26118 that doesnt' unserialize this automatically. |
|
100 | - $token = 'C'; |
|
101 | - $data = is_string($data) ? trim($data) : $data; |
|
102 | - if (is_string($data) && strlen($data) > 1 && $data[0] == $token && preg_match("/^{$token}:[0-9]+:/s", $data)) { |
|
103 | - return unserialize($data); |
|
104 | - } else { |
|
105 | - return $data; |
|
106 | - } |
|
107 | - } |
|
108 | - |
|
109 | - |
|
110 | - /** |
|
111 | - * insert_into_array |
|
112 | - * |
|
113 | - * @param array $target_array the array to insert new data into |
|
114 | - * @param array $array_to_insert the new data to be inserted |
|
115 | - * @param int | string $offset a known key within $target_array where new data will be inserted |
|
116 | - * @param bool $add_before whether to add new data before or after the offset key |
|
117 | - * @param bool $preserve_keys whether or not to reset numerically indexed arrays |
|
118 | - * @return array |
|
119 | - */ |
|
120 | - public static function insert_into_array( |
|
121 | - $target_array = array(), |
|
122 | - $array_to_insert = array(), |
|
123 | - $offset = null, |
|
124 | - $add_before = true, |
|
125 | - $preserve_keys = true |
|
126 | - ) { |
|
127 | - // ensure incoming arrays are actually arrays |
|
128 | - $target_array = (array) $target_array; |
|
129 | - $array_to_insert = (array) $array_to_insert; |
|
130 | - // if no offset key was supplied |
|
131 | - if (empty($offset)) { |
|
132 | - // use start or end of $target_array based on whether we are adding before or not |
|
133 | - $offset = $add_before ? 0 : count($target_array); |
|
134 | - } |
|
135 | - // if offset key is a string, then find the corresponding numeric location for that element |
|
136 | - $offset = is_int($offset) ? $offset : array_search($offset, array_keys($target_array)); |
|
137 | - // add one to the offset if adding after |
|
138 | - $offset = $add_before ? $offset : $offset + 1; |
|
139 | - // but ensure offset does not exceed the length of the array |
|
140 | - $offset = $offset > count($target_array) ? count($target_array) : $offset; |
|
141 | - // reindex array ??? |
|
142 | - if ($preserve_keys) { |
|
143 | - // take a slice of the target array from the beginning till the offset, |
|
144 | - // then add the new data |
|
145 | - // then add another slice that starts at the offset and goes till the end |
|
146 | - return array_slice($target_array, 0, $offset, true) + $array_to_insert + array_slice( |
|
147 | - $target_array, |
|
148 | - $offset, |
|
149 | - null, |
|
150 | - true |
|
151 | - ); |
|
152 | - } else { |
|
153 | - // since we don't want to preserve keys, we can use array_splice |
|
154 | - array_splice($target_array, $offset, 0, $array_to_insert); |
|
155 | - return $target_array; |
|
156 | - } |
|
157 | - } |
|
158 | - |
|
159 | - |
|
160 | - /** |
|
161 | - * array_merge() is slow and should never be used while looping over data |
|
162 | - * if you don't need to preserve keys from all arrays, then using a foreach loop is much faster |
|
163 | - * so really this acts more like array_replace( $array1, $array2 ) |
|
164 | - * or a union with the arrays flipped ( $array2 + $array1 ) |
|
165 | - * this saves a few lines of code and improves readability |
|
166 | - * |
|
167 | - * @param array $array1 |
|
168 | - * @param array $array2 |
|
169 | - * @return array |
|
170 | - */ |
|
171 | - public static function merge_arrays_and_overwrite_keys(array $array1, array $array2) |
|
172 | - { |
|
173 | - foreach ($array2 as $key => $value) { |
|
174 | - $array1[ $key ] = $value; |
|
175 | - } |
|
176 | - return $array1; |
|
177 | - } |
|
178 | - |
|
179 | - |
|
180 | - /** |
|
181 | - * given a flat array like $array = array('A', 'B', 'C') |
|
182 | - * will convert into a multidimensional array like $array[A][B][C] |
|
183 | - * if $final_value is provided and is anything other than null, |
|
184 | - * then that will be set as the value for the innermost array key |
|
185 | - * like so: $array[A][B][C] = $final_value |
|
186 | - * |
|
187 | - * @param array $flat_array |
|
188 | - * @param mixed $final_value |
|
189 | - * @return array |
|
190 | - */ |
|
191 | - public static function convert_array_values_to_keys(array $flat_array, $final_value = null) |
|
192 | - { |
|
193 | - $multidimensional = array(); |
|
194 | - $reference = &$multidimensional; |
|
195 | - foreach ($flat_array as $key) { |
|
196 | - $reference[ $key ] = array(); |
|
197 | - $reference = &$reference[ $key ]; |
|
198 | - } |
|
199 | - if ($final_value !== null) { |
|
200 | - $reference = $final_value; |
|
201 | - } |
|
202 | - return $multidimensional; |
|
203 | - } |
|
204 | - |
|
205 | - |
|
206 | - /** |
|
207 | - * @see http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential |
|
208 | - * @param array $array |
|
209 | - * @return bool |
|
210 | - */ |
|
211 | - public static function is_array_numerically_and_sequentially_indexed(array $array) |
|
212 | - { |
|
213 | - return ! empty($array) ? array_keys($array) === range(0, count($array) - 1) : true; |
|
214 | - } |
|
16 | + /** |
|
17 | + * This method basically works the same as the PHP core function array_diff except it allows you to compare arrays |
|
18 | + * of EE_Base_Class objects NOTE: This will ONLY work on an array of EE_Base_Class objects |
|
19 | + * |
|
20 | + * @uses array_udiff core php function for setting up our own array comparison |
|
21 | + * @uses self::_compare_objects as the custom method for array_udiff |
|
22 | + * @param array $array1 an array of objects |
|
23 | + * @param array $array2 an array of objects |
|
24 | + * @return array an array of objects found in array 1 that aren't found in array 2. |
|
25 | + */ |
|
26 | + public static function object_array_diff($array1, $array2) |
|
27 | + { |
|
28 | + return array_udiff($array1, $array2, array('self', '_compare_objects')); |
|
29 | + } |
|
30 | + |
|
31 | + /** |
|
32 | + * Given that $arr is an array, determines if it's associative or numerically AND sequentially indexed |
|
33 | + * |
|
34 | + * @param array $array |
|
35 | + * @return boolean |
|
36 | + */ |
|
37 | + public static function is_associative_array(array $array): bool |
|
38 | + { |
|
39 | + return ! empty($array) && array_keys($array) !== range(0, count($array) - 1); |
|
40 | + } |
|
41 | + |
|
42 | + /** |
|
43 | + * Gets an item from the array and leave the array intact. Use in place of end() |
|
44 | + * when you don't want to change the array |
|
45 | + * |
|
46 | + * @param array $arr |
|
47 | + * @return mixed what ever is in the array |
|
48 | + */ |
|
49 | + public static function get_one_item_from_array($arr) |
|
50 | + { |
|
51 | + $item = end($arr); |
|
52 | + reset($arr); |
|
53 | + return $item; |
|
54 | + } |
|
55 | + |
|
56 | + /** |
|
57 | + * Detects if this is a multi-dimensional array (meaning that the top-level |
|
58 | + * values are themselves array. Eg array(array(...),...) |
|
59 | + * |
|
60 | + * @param mixed $arr |
|
61 | + * @return boolean |
|
62 | + */ |
|
63 | + public static function is_multi_dimensional_array($arr) |
|
64 | + { |
|
65 | + if (is_array($arr)) { |
|
66 | + $first_item = reset($arr); |
|
67 | + if (is_array($first_item)) { |
|
68 | + return true;// yep, there's at least 2 levels to this array |
|
69 | + } else { |
|
70 | + return false;// nope, only 1 level |
|
71 | + } |
|
72 | + } else { |
|
73 | + return false;// its not an array at all! |
|
74 | + } |
|
75 | + } |
|
76 | + |
|
77 | + /** |
|
78 | + * Shorthand for isset( $arr[ $index ] ) ? $arr[ $index ] : $default |
|
79 | + * |
|
80 | + * @param array $arr |
|
81 | + * @param mixed $index |
|
82 | + * @param mixed $default |
|
83 | + * @return mixed |
|
84 | + */ |
|
85 | + public static function is_set($arr, $index, $default) |
|
86 | + { |
|
87 | + return isset($arr[ $index ]) ? $arr[ $index ] : $default; |
|
88 | + } |
|
89 | + |
|
90 | + /** |
|
91 | + * Exactly like `maybe_unserialize`, but also accounts for a WP bug: http://core.trac.wordpress.org/ticket/26118 |
|
92 | + * |
|
93 | + * @param mixed $value usually a string, but could be an array or object |
|
94 | + * @return mixed the UN-serialized data |
|
95 | + */ |
|
96 | + public static function maybe_unserialize($value) |
|
97 | + { |
|
98 | + $data = maybe_unserialize($value); |
|
99 | + // it's possible that this still has serialized data if its the session. WP has a bug, http://core.trac.wordpress.org/ticket/26118 that doesnt' unserialize this automatically. |
|
100 | + $token = 'C'; |
|
101 | + $data = is_string($data) ? trim($data) : $data; |
|
102 | + if (is_string($data) && strlen($data) > 1 && $data[0] == $token && preg_match("/^{$token}:[0-9]+:/s", $data)) { |
|
103 | + return unserialize($data); |
|
104 | + } else { |
|
105 | + return $data; |
|
106 | + } |
|
107 | + } |
|
108 | + |
|
109 | + |
|
110 | + /** |
|
111 | + * insert_into_array |
|
112 | + * |
|
113 | + * @param array $target_array the array to insert new data into |
|
114 | + * @param array $array_to_insert the new data to be inserted |
|
115 | + * @param int | string $offset a known key within $target_array where new data will be inserted |
|
116 | + * @param bool $add_before whether to add new data before or after the offset key |
|
117 | + * @param bool $preserve_keys whether or not to reset numerically indexed arrays |
|
118 | + * @return array |
|
119 | + */ |
|
120 | + public static function insert_into_array( |
|
121 | + $target_array = array(), |
|
122 | + $array_to_insert = array(), |
|
123 | + $offset = null, |
|
124 | + $add_before = true, |
|
125 | + $preserve_keys = true |
|
126 | + ) { |
|
127 | + // ensure incoming arrays are actually arrays |
|
128 | + $target_array = (array) $target_array; |
|
129 | + $array_to_insert = (array) $array_to_insert; |
|
130 | + // if no offset key was supplied |
|
131 | + if (empty($offset)) { |
|
132 | + // use start or end of $target_array based on whether we are adding before or not |
|
133 | + $offset = $add_before ? 0 : count($target_array); |
|
134 | + } |
|
135 | + // if offset key is a string, then find the corresponding numeric location for that element |
|
136 | + $offset = is_int($offset) ? $offset : array_search($offset, array_keys($target_array)); |
|
137 | + // add one to the offset if adding after |
|
138 | + $offset = $add_before ? $offset : $offset + 1; |
|
139 | + // but ensure offset does not exceed the length of the array |
|
140 | + $offset = $offset > count($target_array) ? count($target_array) : $offset; |
|
141 | + // reindex array ??? |
|
142 | + if ($preserve_keys) { |
|
143 | + // take a slice of the target array from the beginning till the offset, |
|
144 | + // then add the new data |
|
145 | + // then add another slice that starts at the offset and goes till the end |
|
146 | + return array_slice($target_array, 0, $offset, true) + $array_to_insert + array_slice( |
|
147 | + $target_array, |
|
148 | + $offset, |
|
149 | + null, |
|
150 | + true |
|
151 | + ); |
|
152 | + } else { |
|
153 | + // since we don't want to preserve keys, we can use array_splice |
|
154 | + array_splice($target_array, $offset, 0, $array_to_insert); |
|
155 | + return $target_array; |
|
156 | + } |
|
157 | + } |
|
158 | + |
|
159 | + |
|
160 | + /** |
|
161 | + * array_merge() is slow and should never be used while looping over data |
|
162 | + * if you don't need to preserve keys from all arrays, then using a foreach loop is much faster |
|
163 | + * so really this acts more like array_replace( $array1, $array2 ) |
|
164 | + * or a union with the arrays flipped ( $array2 + $array1 ) |
|
165 | + * this saves a few lines of code and improves readability |
|
166 | + * |
|
167 | + * @param array $array1 |
|
168 | + * @param array $array2 |
|
169 | + * @return array |
|
170 | + */ |
|
171 | + public static function merge_arrays_and_overwrite_keys(array $array1, array $array2) |
|
172 | + { |
|
173 | + foreach ($array2 as $key => $value) { |
|
174 | + $array1[ $key ] = $value; |
|
175 | + } |
|
176 | + return $array1; |
|
177 | + } |
|
178 | + |
|
179 | + |
|
180 | + /** |
|
181 | + * given a flat array like $array = array('A', 'B', 'C') |
|
182 | + * will convert into a multidimensional array like $array[A][B][C] |
|
183 | + * if $final_value is provided and is anything other than null, |
|
184 | + * then that will be set as the value for the innermost array key |
|
185 | + * like so: $array[A][B][C] = $final_value |
|
186 | + * |
|
187 | + * @param array $flat_array |
|
188 | + * @param mixed $final_value |
|
189 | + * @return array |
|
190 | + */ |
|
191 | + public static function convert_array_values_to_keys(array $flat_array, $final_value = null) |
|
192 | + { |
|
193 | + $multidimensional = array(); |
|
194 | + $reference = &$multidimensional; |
|
195 | + foreach ($flat_array as $key) { |
|
196 | + $reference[ $key ] = array(); |
|
197 | + $reference = &$reference[ $key ]; |
|
198 | + } |
|
199 | + if ($final_value !== null) { |
|
200 | + $reference = $final_value; |
|
201 | + } |
|
202 | + return $multidimensional; |
|
203 | + } |
|
204 | + |
|
205 | + |
|
206 | + /** |
|
207 | + * @see http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential |
|
208 | + * @param array $array |
|
209 | + * @return bool |
|
210 | + */ |
|
211 | + public static function is_array_numerically_and_sequentially_indexed(array $array) |
|
212 | + { |
|
213 | + return ! empty($array) ? array_keys($array) === range(0, count($array) - 1) : true; |
|
214 | + } |
|
215 | 215 | } |