1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Framy Framework |
4
|
|
|
* |
5
|
|
|
* @copyright Copyright Framy |
6
|
|
|
* @Author Marco Bier <[email protected]> |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
namespace app\framework\Component\StdLib\StdObject\ArrayObject; |
10
|
|
|
|
11
|
|
|
use app\framework\Component\StdLib\StdObject\StdObjectWrapper; |
12
|
|
|
use app\framework\Component\StdLib\StdObject\StringObject\StringObject; |
13
|
|
|
use ErrorException; |
14
|
|
|
|
15
|
|
|
trait ManipulationTrait |
16
|
|
|
{ |
17
|
|
|
/** |
18
|
|
|
* Return, or update, current standard objects value. |
19
|
|
|
* |
20
|
|
|
* @param null $value If $value is set, value is updated and ArrayObject is returned. |
|
|
|
|
21
|
|
|
* @return mixed |
22
|
|
|
*/ |
23
|
|
|
abstract public function val($value = null); |
24
|
|
|
|
25
|
|
|
abstract public function keyExists($key); |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* (PHP 5 >= 5.1.0)<br/> |
29
|
|
|
* Count elements of an object |
30
|
|
|
* |
31
|
|
|
* @link http://php.net/manual/en/countable.count.php |
32
|
|
|
* @return int The custom count as an integer. |
33
|
|
|
* </p> |
34
|
|
|
* <p> |
35
|
|
|
* The return value is cast to an integer. |
36
|
|
|
*/ |
37
|
|
|
abstract public function count(); |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* Checks if given value is null. |
41
|
|
|
* |
42
|
|
|
* @param mixed $var Value to check |
43
|
|
|
* |
44
|
|
|
* @return bool |
45
|
|
|
*/ |
46
|
|
|
abstract protected static function isNull($var); |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* Check if $instance is of $type. |
50
|
|
|
* |
51
|
|
|
* @param mixed $instance |
52
|
|
|
* @param string $type |
53
|
|
|
* |
54
|
|
|
* @return bool |
55
|
|
|
*/ |
56
|
|
|
abstract protected static function isInstanceOf($instance, $type); |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* Checks if given value is an array. |
60
|
|
|
* |
61
|
|
|
* @param $var |
62
|
|
|
* |
63
|
|
|
* @return bool |
64
|
|
|
*/ |
65
|
|
|
abstract protected static function isArray($var); |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* Returns the difference between $attributes and $original |
69
|
|
|
* If an value is different the element from $arr1 will be returned |
70
|
|
|
* |
71
|
|
|
* @param $arr |
72
|
|
|
* @return array |
73
|
|
|
*/ |
74
|
|
|
public function difference($arr) |
75
|
|
|
{ |
76
|
|
|
$attributes = []; |
77
|
|
|
foreach ($this->val() as $attKey => $attribute) { |
78
|
|
|
foreach ($arr as $oriKey => $original) { |
79
|
|
|
if ($attKey == $oriKey) { |
80
|
|
|
if ($attribute !== $original) { |
81
|
|
|
$attributes[$attKey] = $attribute; |
82
|
|
|
} |
83
|
|
|
} |
84
|
|
|
} |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
return $attributes; |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* Convert the array into a query string. |
92
|
|
|
* |
93
|
|
|
* @return string |
94
|
|
|
*/ |
95
|
|
|
public function query() |
96
|
|
|
{ |
97
|
|
|
return http_build_query($this->val(), null, '&', PHP_QUERY_RFC3986); |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* Flatten a multi-dimensional associative array with dots. |
102
|
|
|
* |
103
|
|
|
* @param array $array |
104
|
|
|
* @param string $prepend |
105
|
|
|
* @return array |
106
|
|
|
*/ |
107
|
|
|
public function dot($array = null, $prepend = '') |
108
|
|
|
{ |
109
|
|
|
|
110
|
|
|
if (is_null($array)) { |
111
|
|
|
$array = $this->val(); |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
$results = []; |
115
|
|
|
foreach ($array as $key => $value) { |
116
|
|
|
if (is_array($value) && ! empty($value)) { |
117
|
|
|
$results = array_merge($results, $this->dot($value, $prepend.$key.'.')); |
118
|
|
|
} else { |
119
|
|
|
$results[$prepend.$key] = $value; |
120
|
|
|
} |
121
|
|
|
} |
122
|
|
|
return $results; |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* Divide an array into two arrays. One with keys and the other with values. |
127
|
|
|
* |
128
|
|
|
* @return array |
129
|
|
|
*/ |
130
|
|
|
public function divide() |
131
|
|
|
{ |
132
|
|
|
return [$this->getKeys(), $this->getOnlyValues()]; |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
/** |
136
|
|
|
* Returns a array of only the keys |
137
|
|
|
* |
138
|
|
|
* @return array |
139
|
|
|
*/ |
140
|
|
|
public function getKeys() |
141
|
|
|
{ |
142
|
|
|
return array_keys($this->val()); |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
/** |
146
|
|
|
* Returns a array of only the values |
147
|
|
|
* |
148
|
|
|
* @return array |
149
|
|
|
*/ |
150
|
|
|
public function getOnlyValues() |
151
|
|
|
{ |
152
|
|
|
return array_values($this->val()); |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
/** |
156
|
|
|
* remove first element of given array |
157
|
|
|
* |
158
|
|
|
* @return $this |
159
|
|
|
*/ |
160
|
|
|
public function removeFirst() |
161
|
|
|
{ |
162
|
|
|
$array = $this->val(); |
163
|
|
|
|
164
|
|
|
array_shift($array); |
165
|
|
|
|
166
|
|
|
$this->val($array); |
167
|
|
|
|
168
|
|
|
return $this; |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
/** |
172
|
|
|
* remove last element of given array |
173
|
|
|
* |
174
|
|
|
* @return $this |
175
|
|
|
*/ |
176
|
|
|
public function removeLast() |
177
|
|
|
{ |
178
|
|
|
$array = $this->val(); |
179
|
|
|
|
180
|
|
|
array_pop($array); |
181
|
|
|
|
182
|
|
|
$this->val($array); |
183
|
|
|
|
184
|
|
|
return $this; |
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
/** |
188
|
|
|
* Go thru all the entries and remove all with given value |
189
|
|
|
* |
190
|
|
|
* @param $_value |
191
|
|
|
* @return $this |
192
|
|
|
*/ |
193
|
|
|
public function removeIfValue($_value) |
194
|
|
|
{ |
195
|
|
|
$values = $this->val(); |
196
|
|
|
|
197
|
|
|
foreach ($values as $key => $value) { |
198
|
|
|
if ($value === $_value) { |
199
|
|
|
$this->removeKey($key); |
200
|
|
|
} |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
return $this; |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
/** |
207
|
|
|
* The method joins the items in a collection. |
208
|
|
|
* |
209
|
|
|
* @param string $glue The string you wish to place between the values. |
210
|
|
|
* @param string $key If the value contains arrays or objects, you should pass the key of the attributes you wish to join |
211
|
|
|
* @return string |
212
|
|
|
*/ |
213
|
|
|
public function implode(string $glue, string $key = null) |
214
|
|
|
{ |
215
|
|
|
if (! function_exists(__NAMESPACE__.'\useGlue')) { |
216
|
|
|
// done this function to avoid writing redundant code |
217
|
|
|
function useGlue(&$i, &$length, &$glue) { |
218
|
|
|
// don't use glue if is last element |
219
|
|
|
if($i < $length) |
220
|
|
|
return $glue; |
221
|
|
|
else |
222
|
|
|
return ""; |
223
|
|
|
} |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
$val = $this->val(); |
227
|
|
|
$length = $this->count(); |
228
|
|
|
$result = ""; |
229
|
|
|
|
230
|
|
|
// check if val is key or obj |
231
|
|
|
$i = 1; |
232
|
|
|
foreach ($val as $item) { |
233
|
|
|
if(is_object($item)) { |
234
|
|
|
$item = get_object_vars($this); |
|
|
|
|
235
|
|
|
//TODO finnish this case |
236
|
|
|
} elseif(is_array($item)) { |
237
|
|
|
if(!isset($key)) |
238
|
|
|
handle(new \Exception("\$key must be set!")); |
239
|
|
|
|
240
|
|
|
$result .= $item[$key].useGlue($i, $length, $glue); |
241
|
|
|
} else { |
242
|
|
|
$result .= $item.useGlue($i, $length, $glue); |
243
|
|
|
} |
244
|
|
|
$i++; |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
return $result; |
248
|
|
|
} |
249
|
|
|
|
250
|
|
|
/** |
251
|
|
|
* Get or update the given key inside current array. |
252
|
|
|
* |
253
|
|
|
* @param string|int|StringObject $key Array key |
254
|
|
|
* @param null|mixed $value If set, the value under current $key will be updated and not returned. |
255
|
|
|
* @param bool $setOnlyIfDoesntExist Set the $value only in case if the $key doesn't exist. |
256
|
|
|
* |
257
|
|
|
* @return $this|mixed|StringObject The value of the given key. |
258
|
|
|
*/ |
259
|
|
|
public function key($key, $value = null, $setOnlyIfDoesntExist = false) |
260
|
|
|
{ |
261
|
|
|
$key = StdObjectWrapper::toString($key); |
262
|
|
|
$array = $this->val(); |
263
|
|
|
|
264
|
|
|
if ($setOnlyIfDoesntExist && !$this->keyExists($key)) { |
265
|
|
|
$array[$key] = $value; |
266
|
|
|
$this->val($array); |
267
|
|
|
|
268
|
|
|
return $value; |
269
|
|
|
} else { |
270
|
|
|
if (!$setOnlyIfDoesntExist && !$this->isNull($value)) { |
271
|
|
|
$array[$key] = $value; |
272
|
|
|
$this->val($array); |
273
|
|
|
|
274
|
|
|
return $this; |
275
|
|
|
} |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
if (!isset($array[$key])) { |
279
|
|
|
return $value; |
280
|
|
|
} |
281
|
|
|
|
282
|
|
|
return $array[$key]; |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
/** |
286
|
|
|
* Inserts an element to the end of the array. |
287
|
|
|
* If you set both params, that first param is the key, and second is the value, |
288
|
|
|
* else first param is the value, and the second is ignored. |
289
|
|
|
* |
290
|
|
|
* @param mixed $k |
291
|
|
|
* @param mixed $v |
292
|
|
|
* |
293
|
|
|
* @return $this |
294
|
|
|
*/ |
295
|
|
|
public function append($k, $v = null) |
296
|
|
|
{ |
297
|
|
|
$array = $this->val(); |
298
|
|
|
|
299
|
|
|
if (!$this->isNull($v)) { |
300
|
|
|
$array[$k] = $v; |
301
|
|
|
} else { |
302
|
|
|
$array[] = $k; |
303
|
|
|
} |
304
|
|
|
|
305
|
|
|
$this->val($array); |
306
|
|
|
|
307
|
|
|
return $this; |
308
|
|
|
} |
309
|
|
|
|
310
|
|
|
/** |
311
|
|
|
* Inserts an element at the beginning of the array. |
312
|
|
|
* If you set both params, that first param is the key, and second is the value, |
313
|
|
|
* else first param is the value, and the second is ignored. |
314
|
|
|
* |
315
|
|
|
* @param mixed $k |
316
|
|
|
* @param mixed $v |
317
|
|
|
* |
318
|
|
|
* @return $this |
319
|
|
|
*/ |
320
|
|
|
public function prepend($k, $v = null) |
321
|
|
|
{ |
322
|
|
|
$array = $this->val(); |
323
|
|
|
|
324
|
|
|
if (!$this->isNull($v)) { |
325
|
|
|
$array = array_reverse($array, true); |
326
|
|
|
$array[$k] = $v; |
327
|
|
|
$array = array_reverse($array, true); |
328
|
|
|
} else { |
329
|
|
|
array_unshift($array, $k); |
330
|
|
|
} |
331
|
|
|
|
332
|
|
|
$this->val($array); |
333
|
|
|
|
334
|
|
|
return $this; |
335
|
|
|
} |
336
|
|
|
|
337
|
|
|
/** |
338
|
|
|
* remove key in current array |
339
|
|
|
* |
340
|
|
|
* @param $key |
341
|
|
|
*/ |
342
|
|
|
public function removeKey($key) |
343
|
|
|
{ |
344
|
|
|
if ($this->keyExists($key)) { |
345
|
|
|
$array = $this->val(); |
346
|
|
|
unset($array[$key]); |
347
|
|
|
|
348
|
|
|
$this->val($array); |
349
|
|
|
} |
350
|
|
|
} |
351
|
|
|
|
352
|
|
|
/** |
353
|
|
|
* The method iterates through the array and passes each value to |
354
|
|
|
* the given callback. The callback is free to modify the item and return it, |
355
|
|
|
* thus forming a new ArrayObject of modified items |
356
|
|
|
* |
357
|
|
|
* @param callable $call |
358
|
|
|
* @return ArrayObject |
359
|
|
|
*/ |
360
|
|
|
public function map(callable $call) |
361
|
|
|
{ |
362
|
|
|
$array = $this->val(); |
363
|
|
|
$result = []; |
364
|
|
|
|
365
|
|
|
foreach ($array as $key => $item) |
366
|
|
|
$result[] = call_user_func($call, $item, $key); |
367
|
|
|
|
368
|
|
|
return new ArrayObject($result); |
369
|
|
|
} |
370
|
|
|
|
371
|
|
|
/** |
372
|
|
|
* Merge given $array with current array. |
373
|
|
|
* |
374
|
|
|
* @param array|ArrayObject $array |
375
|
|
|
* |
376
|
|
|
* @return $this |
377
|
|
|
*/ |
378
|
|
|
public function merge($array) |
379
|
|
|
{ |
380
|
|
|
if($this->isInstanceOf($array, $this)){ |
|
|
|
|
381
|
|
|
$array = $array->val(); |
382
|
|
|
} |
383
|
|
|
|
384
|
|
|
$this->val(array_merge($this->val(), $array)); |
|
|
|
|
385
|
|
|
|
386
|
|
|
return $this; |
387
|
|
|
} |
388
|
|
|
|
389
|
|
|
/** |
390
|
|
|
* Merge given $array with current array. |
391
|
|
|
* |
392
|
|
|
* @param array|ArrayObject $array |
393
|
|
|
* |
394
|
|
|
* @return $this |
395
|
|
|
*/ |
396
|
|
|
public function mergeRecursive($array) |
397
|
|
|
{ |
398
|
|
|
if($this->isInstanceOf($array, $this)){ |
|
|
|
|
399
|
|
|
$array = $array->val(); |
400
|
|
|
} |
401
|
|
|
|
402
|
|
|
$this->val(array_merge_recursive($this->val(), $array)); |
|
|
|
|
403
|
|
|
|
404
|
|
|
return $this; |
405
|
|
|
} |
406
|
|
|
|
407
|
|
|
/** |
408
|
|
|
* @param int $num |
409
|
|
|
* |
410
|
|
|
* @return ArrayObject |
411
|
|
|
* @throws ArrayObjectException |
412
|
|
|
*/ |
413
|
|
|
public function rand($num = 1) |
414
|
|
|
{ |
415
|
|
|
try { |
416
|
|
|
$arr = array_rand($this->val(), $num); |
417
|
|
|
} catch (ErrorException $e) { |
418
|
|
|
throw new ArrayObjectException($e->getMessage()); |
419
|
|
|
} |
420
|
|
|
|
421
|
|
|
if (!$this->isArray($arr)) { |
422
|
|
|
$arr = [$arr]; |
423
|
|
|
} |
424
|
|
|
|
425
|
|
|
return new ArrayObject($arr); |
426
|
|
|
} |
427
|
|
|
|
428
|
|
|
/** |
429
|
|
|
* reverse elements order |
430
|
|
|
* |
431
|
|
|
* @param bool $preserve |
432
|
|
|
* |
433
|
|
|
* @return $this |
434
|
|
|
*/ |
435
|
|
|
public function reverse($preserve = false) |
436
|
|
|
{ |
437
|
|
|
$this->val(array_reverse($this->val(), $preserve)); |
438
|
|
|
|
439
|
|
|
return $this; |
440
|
|
|
} |
441
|
|
|
|
442
|
|
|
/** |
443
|
|
|
* Shuffle elements in the array. |
444
|
|
|
* |
445
|
|
|
* @return $this |
446
|
|
|
*/ |
447
|
|
|
public function shuffle() |
448
|
|
|
{ |
449
|
|
|
$val = $this->val(); |
450
|
|
|
shuffle($val); |
451
|
|
|
$this->val($val); |
452
|
|
|
return $this; |
453
|
|
|
} |
454
|
|
|
|
455
|
|
|
/** |
456
|
|
|
* Removes duplicate values from an array |
457
|
|
|
* |
458
|
|
|
* @param int $sortFlag Sorting type flags:<br> |
459
|
|
|
* SORT_REGULAR - compare items normally (don't change types)<br> |
460
|
|
|
* SORT_NUMERIC - compare items numerically<br> |
461
|
|
|
* SORT_STRING - compare items as strings<br> |
462
|
|
|
* SORT_LOCALE_STRING - compare items as strings, based on the current locale.<br> |
463
|
|
|
* |
464
|
|
|
* @return $this |
465
|
|
|
*/ |
466
|
|
|
public function unique($sortFlag = SORT_REGULAR) |
467
|
|
|
{ |
468
|
|
|
$this->val(array_unique($this->val(), $sortFlag)); |
469
|
|
|
|
470
|
|
|
return $this; |
471
|
|
|
} |
472
|
|
|
|
473
|
|
|
/** |
474
|
|
|
* Sort an array by values using a user-defined comparison function<br /> |
475
|
|
|
* This function assigns new keys to the elements in array. It will remove any existing keys that may have been assigned, rather than just reordering the keys.<br /> |
476
|
|
|
* The comparison function must return an integer less than, equal to, or greater than zero if the first argument is considered to be respectively less than, equal to, or greater than the second. |
477
|
|
|
* |
478
|
|
|
* @param callable $comparisonFunction |
479
|
|
|
* |
480
|
|
|
* @throws ArrayObjectException |
481
|
|
|
* |
482
|
|
|
* @return $this |
483
|
|
|
*/ |
484
|
|
|
public function sortUsingFunction($comparisonFunction) |
485
|
|
|
{ |
486
|
|
|
if (!is_callable($comparisonFunction)) { |
487
|
|
|
throw new ArrayObjectException(ArrayObjectException::MSG_INVALID_ARG, [ |
488
|
|
|
'$comparisonFunction', |
489
|
|
|
'callable' |
490
|
|
|
]); |
491
|
|
|
} |
492
|
|
|
|
493
|
|
|
$val = $this->val(); |
494
|
|
|
usort($val, $comparisonFunction); |
495
|
|
|
$this->val($val); |
496
|
|
|
|
497
|
|
|
return $this; |
498
|
|
|
} |
499
|
|
|
|
500
|
|
|
/** |
501
|
|
|
* Flatten a multi-dimensional array into a single level. |
502
|
|
|
* |
503
|
|
|
* @param array $array |
504
|
|
|
* @param int $depth |
505
|
|
|
* @return array |
506
|
|
|
*/ |
507
|
|
|
public function flatten(array $array = null, $depth = INF) |
508
|
|
|
{ |
509
|
|
|
$result = []; |
510
|
|
|
$val = $array ?: $this->val(); |
511
|
|
|
|
512
|
|
|
foreach ($val as $item) { |
513
|
|
|
$item = $item instanceof ArrayObject ? $item->val() : $item; |
514
|
|
|
|
515
|
|
|
if (! is_array($item) or $item === []) { |
516
|
|
|
if ($item !== []) { |
517
|
|
|
$result[] = $item; |
518
|
|
|
} |
519
|
|
|
} elseif ($depth === 1) { |
520
|
|
|
$result = array_merge($result, array_values($item)); |
521
|
|
|
} else { |
522
|
|
|
$result = array_merge($result, $this->flatten($item, $depth - 1)); |
|
|
|
|
523
|
|
|
} |
524
|
|
|
} |
525
|
|
|
|
526
|
|
|
return $result; |
527
|
|
|
} |
528
|
|
|
} |
529
|
|
|
|