Arr::last()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 3
dl 0
loc 3
rs 10
1
<?php 
2
3
/**
4
 * Lenevor Framework
5
 *
6
 * LICENSE
7
 *
8
 * This source file is subject to the new BSD license that is bundled
9
 * with this package in the file license.md.
10
 * It is also available through the world-wide-web at this URL:
11
 * https://lenevor.com/license
12
 * If you did not receive a copy of the license and are unable to
13
 * obtain it through the world-wide-web, please send an email
14
 * to [email protected] so we can send you a copy immediately.
15
 *
16
 * @package     Lenevor
17
 * @subpackage  Base
18
 * @link        https://lenevor.com
19
 * @copyright   Copyright (c) 2019 - 2021 Alexander Campo <[email protected]>
20
 * @license     https://opensource.org/licenses/BSD-3-Clause New BSD license or see https://lenevor.com/license or see /license.md
21
 */
22
23
namespace Syscodes\Collections;
24
25
use ArrayAccess;
26
use InvalidArgumentException;
27
28
/**
29
 * Gets all a given array for return dot-notated key from an array.
30
 * 
31
 * @author Alexander Campo <[email protected]>
32
 */
33
class Arr
34
{
35
	/**
36
	 * Determine whether the value is accessible in a array.
37
	 *
38
	 * @param  mixed  $value The default value
39
	 *
40
	 * @return bool
41
	 *
42
	 * @uses   instanceof ArrayAccess
43
	 */
44
	public static function access($value) 
45
	{
46
		return is_array($value) || $value instanceof ArrayAccess;
47
	}
48
49
	/**
50
	 * Add an element to an array using "dot" notation if it doesn't exist.
51
	 *
52
	 * @param  array  $array  The search array 
53
	 * @param  string  $key  The key exist
54
	 * @param  mixed  $value  The default value
55
	 *
56
	 * @return array 
57
	 */
58
	public static function add($array, $key, $value)
59
	{
60
		if (is_null(static::get($array, $key))) {
61
			static::set($array, $key, $value);
62
		}
63
64
		return $array;
65
	}
66
67
	/**
68
     * Collapse the collection items into a single array.
69
     * 
70
     * @return static
71
     */
72
    public static function collapse($array)
73
    {
74
        $results = [];
75
76
        foreach ($array as $values) {
77
			if ($values instanceof Collection) {
78
				$values = $values->all();
79
			} elseif ( ! is_array($values)) {
80
				continue;
81
			}
82
83
			$results[] = $values;
84
        }
85
86
        return array_merge([], ...$results);
0 ignored issues
show
Bug Best Practice introduced by
The expression return array_merge(array(), $results) returns the type array which is incompatible with the documented return type Syscodes\Collections\Arr.
Loading history...
87
    }
88
89
	/**
90
	 * Divide an array into two arrays. One with keys and the other with values.
91
	 *
92
	 * @param  array  $array
93
	 *
94
	 * @return array
95
	 */
96
	public static function divide($array)
97
	{
98
		return [array_keys($array), array_values($array)];
99
	}
100
101
	/**
102
	 * Get all of the given array except for a specified array of items.
103
	 *
104
	 * @param  array  $array
105
	 * @param  string|array  $keys
106
	 *
107
	 * @return array
108
	 */
109
	public static function except($array, $keys)
110
	{
111
		static::erase($array, $keys);
112
113
		return $array;
114
	}
115
	
116
	/**
117
	 * Determine if the given key exists in the provided array.
118
	 *
119
	 * @param  ArrayAccess|array  $array  The search array
120
	 * @param  string|int  $key  The key exist
121
	 *
122
	 * @return bool
123
	 *
124
	 * @uses   instaceof ArrayAccess
125
	 */
126
	public static function exists($array, $key) 
127
	{
128
		if ($array instanceof ArrayAccess) {
129
			return $array->offsetExists($key);
130
		}
131
		
132
		return array_key_exists($key, $array);
133
	}
134
135
	/**
136
	 * Unsets dot-notated key from an array.
137
	 *
138
	 * @param  array  $array  The search array
139
	 * @param  mixed  $keys  The dot-notated key or array of keys
140
	 *
141
	 * @return mixed
142
	 */
143
	public static function erase(&$array, $keys)
144
	{
145
		$original = &$array;
146
147
		$keys = (array) $keys;
148
149
		if (count($keys) === 0) {
150
			return;
151
		}
152
153
		foreach ($keys as $key) {
154
			if (static::exists($array, $key)) {
155
				unset($array[$key]);
156
157
				continue;
158
			}
159
			
160
			$parts = explode('.', $key);
161
162
			// Clean up after each pass
163
			$array = &$original;
164
	
165
			// traverse the array into the second last key
166
			while (count($parts) > 1) {
167
				$part = array_shift($parts);
168
	
169
				if (isset($array[$part]) && is_array($array[$part])) {
170
					$array = &$array[$key];
171
				} else {
172
					continue 2;
173
				}
174
			}
175
176
			unset($array[array_shift($parts)]);
177
		}
178
	}
179
180
	/**
181
	 * Flatten a multi-dimensional array into a single level.
182
	 * 
183
	 * @param  array  $array
184
	 * 
185
	 * @return array
186
	 */
187
	public static function flatten($array)
188
	{
189
		$result = [];
190
191
		array_walk_recursive($array, function ($value) use (&$result) {
192
			$result[] = $value;
193
		});
194
195
		return $result;
196
	}
197
	
198
	/**
199
	 * Fetch a flattened array of a nested array element.
200
	 * 
201
	 * @param  array  $array
202
	 * @param  string  $key
203
	 * 
204
	 * @return array
205
	 */
206
	public static function fetch($array, $key)
207
	{
208
		foreach (explode('.', $key) as $segment) {
209
			$results = array();
210
			
211
			foreach ($array as $value) {
212
				if (array_key_exists($segment, $value = (array) $value)) {
213
					$results[] = $value[$segment];
214
				}
215
			}
216
			
217
			$array = array_values($results);
218
		}
219
		
220
		return array_values($results);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $results seems to be defined by a foreach iteration on line 208. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
221
	}
222
223
	/**
224
	 * Return the first element in an array passing a given truth test.
225
	 *
226
	 * @param  array  $array 
227
	 * @param  \Closure  $callback
228
	 * @param  mixed  $default
229
	 *
230
	 * @return mixed
231
	 */
232
	public static function first($array, callable $callback, $default = null)
233
	{
234
		foreach ($array as $key => $value) { 
235
			if (call_user_func($callback, $key, $value)) return $value;
236
		}
237
238
		return value($default);
239
	}	
240
241
	/**
242
	 * Get an item from an array using "dot" notation.
243
	 *
244
	 * @param  \ArrayAccess|array  $array  The search array
245
	 * @param  string  $key  The dot-notated key or array of keys
246
	 * @param  mixed  $default  The default value
247
	 *
248
	 * @return mixed
249
	 */
250
	public static function get($array, $key, $default = null)
251
	{
252
		if ( ! static::access($array)) {
253
			return value($default);
254
		}
255
256
		if (static::exists($array, $key)) {
257
			return $array[$key];
258
		}
259
260
		foreach (explode('.', $key) as $segm) {
261
			if (static::access($array) && static::exists($array, $segm)) {
262
				$array = $array[$segm];
263
			} else {
264
				return value($default);
265
			}
266
		}
267
268
		return $array;		
269
	}
270
271
	/**
272
	 * Return the last element in an array passing a given truth test.
273
	 *
274
	 * @param  array  $array 
275
	 * @param  \Closure  $callback
276
	 * @param  mixed  $default 
277
	 *
278
	 * @return mixed
279
	 *
280
	 * @uses   \Syscodes\Support\Arr::first
281
	 */
282
	public static function last($array, $callback, $default = null)
283
	{
284
		return static::first(array_reverse($array), $callback, $default);
285
	}
286
287
	/**
288
	 * Check if an item exists in an array using "dot" notation.
289
	 * 
290
	 * @param  array  $array
291
	 * @param  string  $key
292
	 * 
293
	 * @return bool
294
	 */
295
	public static function has($array, $key)
296
	{
297
		if (empty($array) || is_null($key)) return false;
298
		
299
		if (array_key_exists($key, $array)) return true;
300
		
301
		foreach (explode('.', $key) as $segment) {
302
			if ( ! is_array($array) || ! static::exists($array, $segment)) {
303
				return false;
304
			}
305
			
306
			$array = $array[$segment];
307
		}
308
		
309
		return true;
310
	}
311
312
	/**
313
	 * Get a subset of the items from the given array.
314
	 * 
315
	 * @param  array  $array
316
	 * @param  array|string  $keys
317
	 * 
318
	 * @return array
319
	 */
320
	public static function only($array, $keys)
321
	{
322
		return array_intersect_key($array, array_flip($array), $keys);
0 ignored issues
show
Bug introduced by
It seems like $keys can also be of type string; however, parameter $_ of array_intersect_key() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

322
		return array_intersect_key($array, array_flip($array), /** @scrutinizer ignore-type */ $keys);
Loading history...
323
	}
324
325
	/**
326
	 * Sets a value in an array using "dot" notation.
327
	 *
328
	 * @param  array  $array  The search array
329
	 * @param  string  $key  The dot-notated key or array of keys
330
	 * @param  mixed  $value  The default value
331
	 *
332
	 * @return mixed
333
	 */
334
	public static function set(& $array, $key, $value = null)
335
	{
336
		$keys = explode('.', $key);
337
338
		while (count($keys) > 1) {
339
			$key = array_shift($keys);
340
341
			if ( ! static::exists($array, $key)) {
342
				$array[$key] = [];
343
			}
344
345
			$array =& $array[$key];
346
		}
347
348
		$array[array_shift($keys)] = $value;
349
350
		return $array;
351
	}
352
353
	/**
354
	 * Push an item onto the beginning of an array.
355
	 * 
356
	 * @param  mixed  $array
357
	 * @param  mixed  $value
358
	 * @param  mixed  key
0 ignored issues
show
Bug introduced by
The type Syscodes\Collections\key was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
359
	 * 
360
	 * @return array
361
	 */
362
	public static function prepend($array, $value, $key = null)
363
	{
364
		if (func_num_args() == 2) {
365
			array_unshift($array, $value);
366
		} else {
367
			$array = [$key => $value] + $array;
368
		}
369
370
		return $array;
371
	}
372
373
	/**
374
	 * Get a value from the array, and remove it.
375
	 * 
376
	 * @param  array  $array
377
	 * @param  string  $key
378
	 * @param  mixed  $default
379
	 * 
380
	 * @return mixed
381
	 */
382
	public static function pull(&$array, $key, $default = null)
383
	{
384
		$value = static::get($array, $key, $default);
385
386
		static::erase($array, $key);
387
388
		return $value;
389
	}
390
	
391
	/**
392
	 * Pluck an array of values from an array.
393
	 * 
394
	 * @param  iterable  $array
395
	 * @param  string|array|int|null  $value
396
	 * @param  string|array|null  $key
397
	 * 
398
	 * @return array
399
	 */
400
	public static function pluck($array, $value, $key = null)
401
	{
402
		$results = [];
403
404
		foreach ($array as $item) {
405
			$itemValue = is_object($item) ? $item->{$value} : $item[$value];
406
			
407
			// If the key is "null", we will just append the value to the array and keep
408
			// looping. Otherwise we will key the array using the value of the key we
409
			// received from the developer. Then we'll return the final array form.
410
			if (is_null($key)) {
411
				$results[] = $itemValue;
412
			} else {
413
				$itemKey = is_object($item) ? $item->{$key} : $item[$key];
414
				
415
				$results[$itemKey] = $itemValue;
416
			}
417
		}
418
		
419
		return $results;
420
	}
421
422
	/**
423
	 * Convert the array into a query string.
424
	 * 
425
	 * @param  array  $array
426
	 * 
427
	 * @return array
428
	 */
429
	public static function query($array)
430
	{
431
		return http_build_query($array, null, '&', PHP_QUERY_RFC3986);
0 ignored issues
show
Bug introduced by
null of type null is incompatible with the type string expected by parameter $numeric_prefix of http_build_query(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

431
		return http_build_query($array, /** @scrutinizer ignore-type */ null, '&', PHP_QUERY_RFC3986);
Loading history...
Bug Best Practice introduced by
The expression return http_build_query(...ions\PHP_QUERY_RFC3986) returns the type string which is incompatible with the documented return type array.
Loading history...
432
	}
433
434
	/**
435
	 * Filter the array using the given callback.
436
	 * 
437
	 * @param  array  $array
438
	 * @param  \Callable  $callback
0 ignored issues
show
Bug introduced by
The type Callable was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
439
	 * 
440
	 * @return array
441
	 */
442
	public static function where($array, Callable $callback)
443
	{
444
		return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH);
445
	}
446
447
	/**
448
	 * If the given value is not an array and not null, wrap it in one.
449
	 * 
450
	 * @param  mixed  $value
451
	 * 
452
	 * @return array
453
	 */
454
	public static function wrap($value)
455
	{
456
		if (is_null($value)) {
457
			return [];
458
		}
459
460
		return is_array($value) ? $value : [$value];
461
	}
462
}