PluginProbe
Packeta / 1.6.1
Packeta v1.6.1
2.3.2 2.3.1 trunk 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.3.0 1.3.1 1.3.2 1.4 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 All 56 releases
packeta / deps / nette / utils / src / Utils / Arrays.php

Arrays.php in Packeta 1.6.1, at deps/nette/utils/src/Utils/Arrays.php

353 lines 12.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * This file is part of the Nette Framework (https://nette.org)
5 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6 */
7 declare (strict_types=1);
8 namespace Packetery\Nette\Utils;
9
10 use Packetery\Nette;
11 use function is_array, is_int, is_object, count;
12 /**
13 * Array tools library.
14 */
15 class Arrays
16 {
17 use \Packetery\Nette\StaticClass;
18 /**
19 * Returns item from array. If it does not exist, it throws an exception, unless a default value is set.
20 * @param string|int|array $key one or more keys
21 * @param mixed $default
22 * @return mixed
23 * @throws \Packetery\Nette\InvalidArgumentException if item does not exist and default value is not provided
24 */
25 public static function get(array $array, $key, $default = null)
26 {
27 foreach (is_array($key) ? $key : [$key] as $k) {
28 if (is_array($array) && \array_key_exists($k, $array)) {
29 $array = $array[$k];
30 } else {
31 if (\func_num_args() < 3) {
32 throw new \Packetery\Nette\InvalidArgumentException("Missing item '{$k}'.");
33 }
34 return $default;
35 }
36 }
37 return $array;
38 }
39 /**
40 * Returns reference to array item. If the index does not exist, new one is created with value null.
41 * @param string|int|array $key one or more keys
42 * @return mixed
43 * @throws \Packetery\Nette\InvalidArgumentException if traversed item is not an array
44 */
45 public static function &getRef(array &$array, $key)
46 {
47 foreach (is_array($key) ? $key : [$key] as $k) {
48 if (is_array($array) || $array === null) {
49 $array =& $array[$k];
50 } else {
51 throw new \Packetery\Nette\InvalidArgumentException('Traversed item is not an array.');
52 }
53 }
54 return $array;
55 }
56 /**
57 * Recursively merges two fields. It is useful, for example, for merging tree structures. It behaves as
58 * the + operator for array, ie. it adds a key/value pair from the second array to the first one and retains
59 * the value from the first array in the case of a key collision.
60 */
61 public static function mergeTree(array $array1, array $array2) : array
62 {
63 $res = $array1 + $array2;
64 foreach (\array_intersect_key($array1, $array2) as $k => $v) {
65 if (is_array($v) && is_array($array2[$k])) {
66 $res[$k] = self::mergeTree($v, $array2[$k]);
67 }
68 }
69 return $res;
70 }
71 /**
72 * Returns zero-indexed position of given array key. Returns null if key is not found.
73 * @param string|int $key
74 * @return int|null offset if it is found, null otherwise
75 */
76 public static function getKeyOffset(array $array, $key) : ?int
77 {
78 return Helpers::falseToNull(\array_search(self::toKey($key), \array_keys($array), \true));
79 }
80 /**
81 * @deprecated use getKeyOffset()
82 */
83 public static function searchKey(array $array, $key) : ?int
84 {
85 return self::getKeyOffset($array, $key);
86 }
87 /**
88 * Tests an array for the presence of value.
89 * @param mixed $value
90 */
91 public static function contains(array $array, $value) : bool
92 {
93 return \in_array($value, $array, \true);
94 }
95 /**
96 * Returns the first item from the array or null if array is empty.
97 * @return mixed
98 */
99 public static function first(array $array)
100 {
101 return count($array) ? \reset($array) : null;
102 }
103 /**
104 * Returns the last item from the array or null if array is empty.
105 * @return mixed
106 */
107 public static function last(array $array)
108 {
109 return count($array) ? \end($array) : null;
110 }
111 /**
112 * Inserts the contents of the $inserted array into the $array immediately after the $key.
113 * If $key is null (or does not exist), it is inserted at the beginning.
114 * @param string|int|null $key
115 */
116 public static function insertBefore(array &$array, $key, array $inserted) : void
117 {
118 $offset = $key === null ? 0 : (int) self::getKeyOffset($array, $key);
119 $array = \array_slice($array, 0, $offset, \true) + $inserted + \array_slice($array, $offset, count($array), \true);
120 }
121 /**
122 * Inserts the contents of the $inserted array into the $array before the $key.
123 * If $key is null (or does not exist), it is inserted at the end.
124 * @param string|int|null $key
125 */
126 public static function insertAfter(array &$array, $key, array $inserted) : void
127 {
128 if ($key === null || ($offset = self::getKeyOffset($array, $key)) === null) {
129 $offset = count($array) - 1;
130 }
131 $array = \array_slice($array, 0, $offset + 1, \true) + $inserted + \array_slice($array, $offset + 1, count($array), \true);
132 }
133 /**
134 * Renames key in array.
135 * @param string|int $oldKey
136 * @param string|int $newKey
137 */
138 public static function renameKey(array &$array, $oldKey, $newKey) : bool
139 {
140 $offset = self::getKeyOffset($array, $oldKey);
141 if ($offset === null) {
142 return \false;
143 }
144 $val =& $array[$oldKey];
145 $keys = \array_keys($array);
146 $keys[$offset] = $newKey;
147 $array = \array_combine($keys, $array);
148 $array[$newKey] =& $val;
149 return \true;
150 }
151 /**
152 * Returns only those array items, which matches a regular expression $pattern.
153 * @throws \Packetery\Nette\RegexpException on compilation or runtime error
154 */
155 public static function grep(array $array, string $pattern, int $flags = 0) : array
156 {
157 return Strings::pcre('preg_grep', [$pattern, $array, $flags]);
158 }
159 /**
160 * Transforms multidimensional array to flat array.
161 */
162 public static function flatten(array $array, bool $preserveKeys = \false) : array
163 {
164 $res = [];
165 $cb = $preserveKeys ? function ($v, $k) use(&$res) : void {
166 $res[$k] = $v;
167 } : function ($v) use(&$res) : void {
168 $res[] = $v;
169 };
170 \array_walk_recursive($array, $cb);
171 return $res;
172 }
173 /**
174 * Checks if the array is indexed in ascending order of numeric keys from zero, a.k.a list.
175 * @param mixed $value
176 */
177 public static function isList($value) : bool
178 {
179 return is_array($value) && (!$value || \array_keys($value) === \range(0, count($value) - 1));
180 }
181 /**
182 * Reformats table to associative tree. Path looks like 'field|field[]field->field=field'.
183 * @param string|string[] $path
184 * @return array|\stdClass
185 */
186 public static function associate(array $array, $path)
187 {
188 $parts = is_array($path) ? $path : \preg_split('#(\\[\\]|->|=|\\|)#', $path, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY);
189 if (!$parts || $parts === ['->'] || $parts[0] === '=' || $parts[0] === '|') {
190 throw new \Packetery\Nette\InvalidArgumentException("Invalid path '{$path}'.");
191 }
192 $res = $parts[0] === '->' ? new \stdClass() : [];
193 foreach ($array as $rowOrig) {
194 $row = (array) $rowOrig;
195 $x =& $res;
196 for ($i = 0; $i < count($parts); $i++) {
197 $part = $parts[$i];
198 if ($part === '[]') {
199 $x =& $x[];
200 } elseif ($part === '=') {
201 if (isset($parts[++$i])) {
202 $x = $row[$parts[$i]];
203 $row = null;
204 }
205 } elseif ($part === '->') {
206 if (isset($parts[++$i])) {
207 if ($x === null) {
208 $x = new \stdClass();
209 }
210 $x =& $x->{$row[$parts[$i]]};
211 } else {
212 $row = is_object($rowOrig) ? $rowOrig : (object) $row;
213 }
214 } elseif ($part !== '|') {
215 $x =& $x[(string) $row[$part]];
216 }
217 }
218 if ($x === null) {
219 $x = $row;
220 }
221 }
222 return $res;
223 }
224 /**
225 * Normalizes array to associative array. Replace numeric keys with their values, the new value will be $filling.
226 * @param mixed $filling
227 */
228 public static function normalize(array $array, $filling = null) : array
229 {
230 $res = [];
231 foreach ($array as $k => $v) {
232 $res[is_int($k) ? $v : $k] = is_int($k) ? $filling : $v;
233 }
234 return $res;
235 }
236 /**
237 * Returns and removes the value of an item from an array. If it does not exist, it throws an exception,
238 * or returns $default, if provided.
239 * @param string|int $key
240 * @param mixed $default
241 * @return mixed
242 * @throws \Packetery\Nette\InvalidArgumentException if item does not exist and default value is not provided
243 */
244 public static function pick(array &$array, $key, $default = null)
245 {
246 if (\array_key_exists($key, $array)) {
247 $value = $array[$key];
248 unset($array[$key]);
249 return $value;
250 } elseif (\func_num_args() < 3) {
251 throw new \Packetery\Nette\InvalidArgumentException("Missing item '{$key}'.");
252 } else {
253 return $default;
254 }
255 }
256 /**
257 * Tests whether at least one element in the array passes the test implemented by the
258 * provided callback with signature `function ($value, $key, array $array): bool`.
259 */
260 public static function some(iterable $array, callable $callback) : bool
261 {
262 foreach ($array as $k => $v) {
263 if ($callback($v, $k, $array)) {
264 return \true;
265 }
266 }
267 return \false;
268 }
269 /**
270 * Tests whether all elements in the array pass the test implemented by the provided function,
271 * which has the signature `function ($value, $key, array $array): bool`.
272 */
273 public static function every(iterable $array, callable $callback) : bool
274 {
275 foreach ($array as $k => $v) {
276 if (!$callback($v, $k, $array)) {
277 return \false;
278 }
279 }
280 return \true;
281 }
282 /**
283 * Calls $callback on all elements in the array and returns the array of return values.
284 * The callback has the signature `function ($value, $key, array $array): bool`.
285 */
286 public static function map(iterable $array, callable $callback) : array
287 {
288 $res = [];
289 foreach ($array as $k => $v) {
290 $res[$k] = $callback($v, $k, $array);
291 }
292 return $res;
293 }
294 /**
295 * Invokes all callbacks and returns array of results.
296 * @param callable[] $callbacks
297 */
298 public static function invoke(iterable $callbacks, ...$args) : array
299 {
300 $res = [];
301 foreach ($callbacks as $k => $cb) {
302 $res[$k] = $cb(...$args);
303 }
304 return $res;
305 }
306 /**
307 * Invokes method on every object in an array and returns array of results.
308 * @param object[] $objects
309 */
310 public static function invokeMethod(iterable $objects, string $method, ...$args) : array
311 {
312 $res = [];
313 foreach ($objects as $k => $obj) {
314 $res[$k] = $obj->{$method}(...$args);
315 }
316 return $res;
317 }
318 /**
319 * Copies the elements of the $array array to the $object object and then returns it.
320 * @param object $object
321 * @return object
322 */
323 public static function toObject(iterable $array, $object)
324 {
325 foreach ($array as $k => $v) {
326 $object->{$k} = $v;
327 }
328 return $object;
329 }
330 /**
331 * Converts value to array key.
332 * @param mixed $value
333 * @return int|string
334 */
335 public static function toKey($value)
336 {
337 return \key([$value => null]);
338 }
339 /**
340 * Returns copy of the $array where every item is converted to string
341 * and prefixed by $prefix and suffixed by $suffix.
342 * @return string[]
343 */
344 public static function wrap(array $array, string $prefix = '', string $suffix = '') : array
345 {
346 $res = [];
347 foreach ($array as $k => $v) {
348 $res[$k] = $prefix . $v . $suffix;
349 }
350 return $res;
351 }
352 }
353