/app/support/Arr.php

https://github.com/overtrue/yaf-skeleton · PHP · 482 lines · 212 code · 73 blank · 197 comment · 29 complexity · ad6c9b594c32e0b58f8ce68b20d8ad01 MD5 · raw file

  1. <?php
  2. /*
  3. * This file is part of the overtrue/yaf-skeleton.
  4. *
  5. * (c) overtrue <i@overtrue.me>
  6. *
  7. * This source file is subject to the MIT license that is bundled
  8. * with this source code in the file LICENSE.
  9. */
  10. namespace App\Support;
  11. class Arr
  12. {
  13. /**
  14. * Add an element to an array using "dot" notation if it doesn't exist.
  15. *
  16. * @param array $array
  17. * @param string $key
  18. * @param mixed $value
  19. *
  20. * @return array
  21. */
  22. public static function add($array, $key, $value)
  23. {
  24. if (is_null(static::get($array, $key))) {
  25. static::set($array, $key, $value);
  26. }
  27. return $array;
  28. }
  29. /**
  30. * Build a new array using a callback.
  31. *
  32. * @param array $array
  33. * @param callable $callback
  34. *
  35. * @return array
  36. */
  37. public static function build($array, callable $callback)
  38. {
  39. $results = [];
  40. foreach ($array as $key => $value) {
  41. list($innerKey, $innerValue) = call_user_func($callback, $key, $value);
  42. $results[$innerKey] = $innerValue;
  43. }
  44. return $results;
  45. }
  46. /**
  47. * Collapse an array of arrays into a single array.
  48. *
  49. * @param array|\ArrayAccess $array
  50. *
  51. * @return array
  52. */
  53. public static function collapse($array)
  54. {
  55. $results = [];
  56. foreach ($array as $values) {
  57. if ($values instanceof Collection) {
  58. $values = $values->all();
  59. }
  60. $results = array_merge($results, $values);
  61. }
  62. return $results;
  63. }
  64. /**
  65. * Divide an array into two arrays. One with keys and the other with values.
  66. *
  67. * @param array $array
  68. *
  69. * @return array
  70. */
  71. public static function divide($array)
  72. {
  73. return [array_keys($array), array_values($array)];
  74. }
  75. /**
  76. * Flatten a multi-dimensional associative array with dots.
  77. *
  78. * @param array $array
  79. * @param string $prepend
  80. *
  81. * @return array
  82. */
  83. public static function dot($array, $prepend = '')
  84. {
  85. $results = [];
  86. foreach ($array as $key => $value) {
  87. if (is_array($value)) {
  88. $results = array_merge($results, static::dot($value, $prepend.$key.'.'));
  89. } else {
  90. $results[$prepend.$key] = $value;
  91. }
  92. }
  93. return $results;
  94. }
  95. /**
  96. * Get all of the given array except for a specified array of items.
  97. *
  98. * @param array $array
  99. * @param array|string $keys
  100. *
  101. * @return array
  102. */
  103. public static function except($array, $keys)
  104. {
  105. static::forget($array, $keys);
  106. return $array;
  107. }
  108. /**
  109. * Fetch a flattened array of a nested array element.
  110. *
  111. * @param array $array
  112. * @param string $key
  113. *
  114. * @return array
  115. *
  116. * @deprecated since version 5.1. Use pluck instead.
  117. */
  118. public static function fetch($array, $key)
  119. {
  120. foreach (explode('.', $key) as $segment) {
  121. $results = [];
  122. foreach ($array as $value) {
  123. if (array_key_exists($segment, $value = (array) $value)) {
  124. $results[] = $value[$segment];
  125. }
  126. }
  127. $array = array_values($results);
  128. }
  129. return array_values($results);
  130. }
  131. /**
  132. * Return the first element in an array passing a given truth test.
  133. *
  134. * @param array $array
  135. * @param callable $callback
  136. * @param mixed $default
  137. *
  138. * @return mixed
  139. */
  140. public static function first($array, callable $callback, $default = null)
  141. {
  142. foreach ($array as $key => $value) {
  143. if (call_user_func($callback, $key, $value)) {
  144. return $value;
  145. }
  146. }
  147. return value($default);
  148. }
  149. /**
  150. * Return the last element in an array passing a given truth test.
  151. *
  152. * @param array $array
  153. * @param callable $callback
  154. * @param mixed $default
  155. *
  156. * @return mixed
  157. */
  158. public static function last($array, callable $callback, $default = null)
  159. {
  160. return static::first(array_reverse($array), $callback, $default);
  161. }
  162. /**
  163. * Flatten a multi-dimensional array into a single level.
  164. *
  165. * @param array $array
  166. *
  167. * @return array
  168. */
  169. public static function flatten($array)
  170. {
  171. $return = [];
  172. array_walk_recursive($array, function ($x) use (&$return) { $return[] = $x; });
  173. return $return;
  174. }
  175. /**
  176. * Remove one or many array items from a given array using "dot" notation.
  177. *
  178. * @param array $array
  179. * @param array|string $keys
  180. */
  181. public static function forget(&$array, $keys)
  182. {
  183. $original = &$array;
  184. foreach ((array) $keys as $key) {
  185. $parts = explode('.', $key);
  186. while (count($parts) > 1) {
  187. $part = array_shift($parts);
  188. if (isset($array[$part]) && is_array($array[$part])) {
  189. $array = &$array[$part];
  190. }
  191. }
  192. unset($array[array_shift($parts)]);
  193. // clean up after each pass
  194. $array = &$original;
  195. }
  196. }
  197. /**
  198. * Get an item from an array using "dot" notation.
  199. *
  200. * @param array $array
  201. * @param string $key
  202. * @param mixed $default
  203. *
  204. * @return mixed
  205. */
  206. public static function get($array, $key, $default = null)
  207. {
  208. if (is_null($key)) {
  209. return $array;
  210. }
  211. if (isset($array[$key])) {
  212. return $array[$key];
  213. }
  214. foreach (explode('.', $key) as $segment) {
  215. if (!is_array($array) || !array_key_exists($segment, $array)) {
  216. return value($default);
  217. }
  218. $array = $array[$segment];
  219. }
  220. return $array;
  221. }
  222. /**
  223. * Check if an item exists in an array using "dot" notation.
  224. *
  225. * @param array $array
  226. * @param string $key
  227. *
  228. * @return bool
  229. */
  230. public static function has($array, $key)
  231. {
  232. if (empty($array) || is_null($key)) {
  233. return false;
  234. }
  235. if (array_key_exists($key, $array)) {
  236. return true;
  237. }
  238. foreach (explode('.', $key) as $segment) {
  239. if (!is_array($array) || !array_key_exists($segment, $array)) {
  240. return false;
  241. }
  242. $array = $array[$segment];
  243. }
  244. return true;
  245. }
  246. /**
  247. * Determines if an array is associative.
  248. *
  249. * An array is "associative" if it doesn't have sequential numerical keys beginning with zero.
  250. *
  251. * @param array $array
  252. *
  253. * @return bool
  254. */
  255. public static function isAssoc(array $array)
  256. {
  257. $keys = array_keys($array);
  258. return array_keys($keys) !== $keys;
  259. }
  260. /**
  261. * Get a subset of the items from the given array.
  262. *
  263. * @param array $array
  264. * @param array|string $keys
  265. *
  266. * @return array
  267. */
  268. public static function only($array, $keys)
  269. {
  270. return array_intersect_key($array, array_flip((array) $keys));
  271. }
  272. /**
  273. * Pluck an array of values from an array.
  274. *
  275. * @param array $array
  276. * @param string|array $value
  277. * @param string|array|null $key
  278. *
  279. * @return array
  280. */
  281. public static function pluck($array, $value, $key = null)
  282. {
  283. $results = [];
  284. list($value, $key) = static::explodePluckParameters($value, $key);
  285. foreach ($array as $item) {
  286. $itemValue = data_get($item, $value);
  287. // If the key is "null", we will just append the value to the array and keep
  288. // looping. Otherwise we will key the array using the value of the key we
  289. // received from the developer. Then we'll return the final array form.
  290. if (is_null($key)) {
  291. $results[] = $itemValue;
  292. } else {
  293. $itemKey = data_get($item, $key);
  294. $results[$itemKey] = $itemValue;
  295. }
  296. }
  297. return $results;
  298. }
  299. /**
  300. * Explode the "value" and "key" arguments passed to "pluck".
  301. *
  302. * @param string|array $value
  303. * @param string|array|null $key
  304. *
  305. * @return array
  306. */
  307. protected static function explodePluckParameters($value, $key)
  308. {
  309. $value = is_array($value) ? $value : explode('.', $value);
  310. $key = is_null($key) || is_array($key) ? $key : explode('.', $key);
  311. return [$value, $key];
  312. }
  313. /**
  314. * Get a value from the array, and remove it.
  315. *
  316. * @param array $array
  317. * @param string $key
  318. * @param mixed $default
  319. *
  320. * @return mixed
  321. */
  322. public static function pull(&$array, $key, $default = null)
  323. {
  324. $value = static::get($array, $key, $default);
  325. static::forget($array, $key);
  326. return $value;
  327. }
  328. /**
  329. * Set an array item to a given value using "dot" notation.
  330. *
  331. * If no key is given to the method, the entire array will be replaced.
  332. *
  333. * @param array $array
  334. * @param string $key
  335. * @param mixed $value
  336. *
  337. * @return array
  338. */
  339. public static function set(&$array, $key, $value)
  340. {
  341. if (is_null($key)) {
  342. return $array = $value;
  343. }
  344. $keys = explode('.', $key);
  345. while (count($keys) > 1) {
  346. $key = array_shift($keys);
  347. // If the key doesn't exist at this depth, we will just create an empty array
  348. // to hold the next value, allowing us to create the arrays to hold final
  349. // values at the correct depth. Then we'll keep digging into the array.
  350. if (!isset($array[$key]) || !is_array($array[$key])) {
  351. $array[$key] = [];
  352. }
  353. $array = &$array[$key];
  354. }
  355. $array[array_shift($keys)] = $value;
  356. return $array;
  357. }
  358. /**
  359. * Sort the array using the given callback.
  360. *
  361. * @param array $array
  362. * @param callable $callback
  363. *
  364. * @return array
  365. */
  366. public static function sort($array, callable $callback)
  367. {
  368. return Collection::make($array)->sortBy($callback)->all();
  369. }
  370. /**
  371. * Recursively sort an array by keys and values.
  372. *
  373. * @param array $array
  374. *
  375. * @return array
  376. */
  377. public static function sortRecursive($array)
  378. {
  379. foreach ($array as &$value) {
  380. if (is_array($value)) {
  381. $value = self::sortRecursive($value);
  382. }
  383. }
  384. if (self::isAssoc($array)) {
  385. ksort($array);
  386. } else {
  387. sort($array);
  388. }
  389. return $array;
  390. }
  391. /**
  392. * Filter the array using the given callback.
  393. *
  394. * @param array $array
  395. * @param callable $callback
  396. *
  397. * @return array
  398. */
  399. public static function where($array, callable $callback)
  400. {
  401. $filtered = [];
  402. foreach ($array as $key => $value) {
  403. if (call_user_func($callback, $key, $value)) {
  404. $filtered[$key] = $value;
  405. }
  406. }
  407. return $filtered;
  408. }
  409. }