/src/Arr.php

https://gitlab.com/kakirigi/support · PHP · 521 lines · 255 code · 82 blank · 184 comment · 41 complexity · 232e501e50b4aae4b7049a2a9ef06866 MD5 · raw file

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