/fulcrum/src/support/helpers/class-arr.php

https://gitlab.com/knowthecode/ktc-must-use · PHP · 545 lines · 200 code · 70 blank · 275 comment · 32 complexity · 0ab02745acefdcde711c60a69083cb9e MD5 · raw file

  1. <?php namespace Fulcrum\Support\Helpers;
  2. /**
  3. * Array Helpers - Static Collection of Helpers for Data Type Array
  4. *
  5. * @package Fulcrum\Support\Helpers
  6. * @since 1.0.0
  7. * @author hellofromTonya
  8. * @link https://UpTechLabs.io
  9. * @license GNU General Public License 2.0+ and MIT License (MIT)
  10. */
  11. /**
  12. * This class has been adapted from the Laravel Illuminate framework, which
  13. * is copyrighted to Taylor Otwell and carries a MIT Licence (MIT).
  14. * Changes reflect WordPress coding standard, compliance with PHP 5.3, +
  15. * additional functionality.
  16. */
  17. use Closure;
  18. class Arr {
  19. /**
  20. * Add an element to an array using "dot" notation if it does not exist.
  21. *
  22. * @since 1.0.0
  23. *
  24. * @param array $array
  25. * @param string $key
  26. * @param mixed $value
  27. *
  28. * @return array
  29. */
  30. public static function add( $array, $key, $value ) {
  31. if ( is_null( static::get( $array, $key ) ) ) {
  32. static::set( $array, $key, $value );
  33. }
  34. return $array;
  35. }
  36. /**
  37. * Flatten a multi-dimensional associative array with dots.
  38. *
  39. * @since 1.0.0
  40. *
  41. * @param array $array
  42. * @param string $prepend
  43. *
  44. * @return array
  45. */
  46. public static function dot( $array, $prepend = '' ) {
  47. $results = array();
  48. foreach ( $array as $key => $value ) {
  49. if ( is_array( $value ) ) {
  50. $results = array_merge( $results, static::dot( $value, $prepend . $key . '.' ) );
  51. } else {
  52. $results[ $prepend . $key ] = $value;
  53. }
  54. }
  55. return $results;
  56. }
  57. /**
  58. * Get all of the given array except for a specified array of items.
  59. *
  60. * @since 1.0.0
  61. *
  62. * @param array $array
  63. * @param array|string $keys
  64. *
  65. * @return array
  66. */
  67. public static function except( $array, $keys ) {
  68. return array_diff_key( $array, array_flip( (array) $keys ) );
  69. }
  70. /**
  71. * Fetch a flattened array of a nested array element.
  72. *
  73. * @since 1.0.0
  74. *
  75. * @param array $array
  76. * @param string $key
  77. *
  78. * @return array
  79. */
  80. public static function fetch( $array, $key ) {
  81. $results = self::dot_notation_walk( $array, $key, 'callback_fetch' );
  82. return array_values( $results );
  83. }
  84. /**
  85. * Return the first element in an array passing a given truth test.
  86. *
  87. * @since 1.0.0
  88. *
  89. * @param array $array
  90. * @param \Closure $callback
  91. * @param mixed $default
  92. *
  93. * @return mixed
  94. */
  95. public static function first( $array, $callback, $default = null ) {
  96. foreach ( $array as $key => $value ) {
  97. if ( call_user_func( $callback, $key, $value ) ) {
  98. return $value;
  99. }
  100. }
  101. return fulcrum_value( $default );
  102. }
  103. /**
  104. * Flatten a multi-dimensional array into a single level
  105. *
  106. * @since 1.0.0
  107. *
  108. * @param array $array
  109. *
  110. * @return array
  111. */
  112. public static function flatten( $array ) {
  113. $return = array();
  114. array_walk_recursive( $array, function ( $x ) use ( &$return ) {
  115. $return[] = $x;
  116. } );
  117. return $return;
  118. }
  119. /**
  120. * Remove one or many array items from a given array using "dot" notation.
  121. *
  122. * @param array $array
  123. * @param array|string $keys
  124. *
  125. * @return void
  126. */
  127. public static function forget( array &$array, $keys ) {
  128. $original =& $array;
  129. foreach ( (array) $keys as $key ) {
  130. self::forget_segments( $array, $key );
  131. $array =& $original;
  132. }
  133. }
  134. /**
  135. * Drop keys from the array
  136. *
  137. * @since 1.0.0
  138. *
  139. * @param $array
  140. * @param $keys
  141. *
  142. * @return null
  143. */
  144. public static function drop( array &$array, $keys ) {
  145. self::forget( $array, $keys );
  146. }
  147. /**
  148. * Get an item from an array using "dot" notation.
  149. *
  150. * @param array $array
  151. * @param string $key
  152. * @param mixed $default
  153. *
  154. * @return mixed
  155. */
  156. public static function get( $array, $key, $default = null ) {
  157. if ( is_null( $key ) ) {
  158. return $array;
  159. }
  160. if ( isset( $array[ $key ] ) ) {
  161. return $array[ $key ];
  162. }
  163. return self::dot_notation_walk( $array, $key, 'callback_get', compact( 'default' ) );
  164. }
  165. /**
  166. * Check if an item exists in an array using "dot" notation.
  167. *
  168. * @since 1.0.0
  169. *
  170. * @param array $array
  171. * @param string $key
  172. *
  173. * @return bool
  174. */
  175. public static function has( array $array, $key ) {
  176. if ( empty( $array ) || is_null( $key ) ) {
  177. return false;
  178. }
  179. if ( array_key_exists( $key, $array ) ) {
  180. return true;
  181. }
  182. return false === self::dot_notation_walk( $array, $key, 'callback_has' ) ? false : true;
  183. }
  184. /**
  185. * Checks if the element within the array is a valid array - uses key dot notation.
  186. *
  187. * @since 1.0.0
  188. *
  189. * @param array|mixed $array
  190. * @param string $key
  191. * @param bool|true $valid_if_not_empty
  192. *
  193. * @return bool
  194. */
  195. public static function is_array( $array, $key = '', $valid_if_not_empty = true ) {
  196. if ( empty( $array ) || empty( $key ) ) {
  197. return false;
  198. }
  199. if ( array_key_exists( $key, $array ) ) {
  200. return self::is_array_element_valid_array( $array, $key, $valid_if_not_empty );
  201. }
  202. return self::dot_notation_walk( $array, $key, 'callback_is_array', compact( 'valid_if_not_empty' ) );
  203. }
  204. /**
  205. * Return the last element in an array passing a given truth test.
  206. *
  207. * @param array $array
  208. * @param \Closure $callback
  209. * @param mixed $default
  210. *
  211. * @return mixed
  212. */
  213. public static function last( $array, $callback, $default = null ) {
  214. return static::first( array_reverse( $array ), $callback, $default );
  215. }
  216. /**
  217. * Get a subset of the items from the given array.
  218. *
  219. * @since 1.0.0
  220. *
  221. * @param array $array
  222. * @param array|string $keys
  223. *
  224. * @return array
  225. */
  226. public static function only( $array, $keys ) {
  227. return array_intersect_key( $array, array_flip( (array) $keys ) );
  228. }
  229. /**
  230. * Pluck an array of values from an array.
  231. *
  232. * @since 1.0.0
  233. *
  234. * @param array $array
  235. * @param string $value
  236. * @param string $key
  237. *
  238. * @return array
  239. */
  240. public static function pluck( $array, $value, $key = null ) {
  241. $results = array();
  242. foreach ( $array as $item ) {
  243. $item_value = fulcrum_data_get( $item, $value );
  244. if ( is_null( $item_value ) ) {
  245. continue;
  246. }
  247. if ( is_null( $key ) ) {
  248. $results[] = $item_value;
  249. } else {
  250. $item_key = fulcrum_data_get( $item, $key );
  251. $results[ $item_key ] = $item_value;
  252. }
  253. }
  254. return $results;
  255. }
  256. /**
  257. * Get a value from the array, and remove it.
  258. *
  259. * @since 1.0.0
  260. *
  261. * @param array $array
  262. * @param string $key
  263. * @param mixed $default
  264. *
  265. * @return mixed
  266. */
  267. public static function pull( &$array, $key, $default = null ) {
  268. $value = static::get( $array, $key, $default );
  269. static::forget( $array, $key );
  270. return $value;
  271. }
  272. /**
  273. * Set an array item to a given value using "dot" notation.
  274. *
  275. * If no key is given to the method, the entire array will be replaced.
  276. *
  277. * @since 1.0.0
  278. *
  279. * @param array $array
  280. * @param string $key
  281. * @param mixed $value
  282. * @param bool $append When true, appends the value to the current value
  283. *
  284. * @return array
  285. */
  286. public static function set( &$array, $key, $value, $append = false ) {
  287. if ( is_null( $key ) ) {
  288. return $array = $value;
  289. }
  290. $keys = explode( '.', $key );
  291. while ( count( $keys ) > 1 ) {
  292. $key = array_shift( $keys );
  293. self::init_empty_array_when_key_does_not_exists( $array, $key );
  294. $array =& $array[ $key ];
  295. }
  296. $key = array_shift( $keys );
  297. if ( $append ) {
  298. $value = $array[ $key ] . $value;
  299. }
  300. $array[ $key ] = $value;
  301. return $array;
  302. }
  303. /**
  304. * Filter the array using the given Closure.
  305. *
  306. * @param array $array
  307. * @param \Closure $callback
  308. *
  309. * @return array
  310. */
  311. public static function where( $array, Closure $callback ) {
  312. $filtered = array();
  313. foreach ( $array as $key => $value ) {
  314. if ( call_user_func( $callback, $key, $value ) ) {
  315. $filtered[ $key ] = $value;
  316. }
  317. }
  318. return $filtered;
  319. }
  320. /*****************
  321. * Helpers
  322. ***************/
  323. /**
  324. * Init an empty array at the key index when the key does not currently exists in the array
  325. *
  326. * @since 1.0.0
  327. *
  328. * @param array $array
  329. * @param string $key
  330. */
  331. protected static function init_empty_array_when_key_does_not_exists( array &$array, $key ) {
  332. if ( ! array_key_exists( $key, $array ) || ! is_array( $array[ $key ] ) ) {
  333. $array[ $key ] = array();
  334. }
  335. }
  336. /**
  337. * Dot notation array walker - this function dissembles the dot notation keys and then
  338. * iterates through each of them and applies the callback to each.
  339. *
  340. * @since 1.0.0
  341. *
  342. * @param array $array
  343. * @param string $dot_notation_keys
  344. * @param string $callback
  345. * @param array $args
  346. *
  347. * @return mixed
  348. */
  349. protected static function dot_notation_walk( array &$array, $dot_notation_keys, $callback, $args = array() ) {
  350. $value = null;
  351. $break = false;
  352. $dot_notation_keys = explode( '.', $dot_notation_keys );
  353. foreach ( $dot_notation_keys as $key ) {
  354. $value = self::$callback( $array, $key, $break, $args );
  355. if ( $break ) {
  356. return $value;
  357. };
  358. }
  359. return $value;
  360. }
  361. /**
  362. * Fetch() function callback for key dot notation walker
  363. *
  364. * @since 1.0.0
  365. *
  366. * @param array $array
  367. * @param string $key Key to evaluate within the "array"
  368. *
  369. * @return bool
  370. */
  371. protected static function callback_fetch( array &$array, $key ) {
  372. $results = array();
  373. foreach ( $array as $value ) {
  374. if ( array_key_exists( $key, $value = (array) $value ) ) {
  375. $results[] = $value[ $key ];
  376. }
  377. }
  378. $array = array_values( $results );
  379. return $results;
  380. }
  381. /**
  382. * Forget segments within the array
  383. *
  384. * @since 1.0.0
  385. *
  386. * @param array $array
  387. * @param string $key
  388. */
  389. protected static function forget_segments( array &$array, $key ) {
  390. $parts = explode( '.', $key );
  391. while ( count( $parts ) > 1 ) {
  392. $part = array_shift( $parts );
  393. if ( isset( $array[ $part ] ) && is_array( $array[ $part ] ) ) {
  394. $array =& $array[ $part ];
  395. }
  396. }
  397. unset( $array[ array_shift( $parts ) ] );
  398. }
  399. /**
  400. * Get() function callback for key dot notation walker
  401. *
  402. * @since 1.0.0
  403. *
  404. * @param array $array
  405. * @param string $key
  406. * @param bool $break
  407. * @param array $args
  408. *
  409. * @return bool
  410. */
  411. protected static function callback_get( array &$array, $key, &$break = false, $args = array() ) {
  412. if ( ! is_array( $array ) || ! array_key_exists( $key, $array ) ) {
  413. $break = true;
  414. return fulcrum_value( $args['default'] );
  415. }
  416. $array = $array[ $key ];
  417. return $array;
  418. }
  419. /**
  420. * Has() function callback for key dot notation walker
  421. *
  422. * @since 1.0.0
  423. *
  424. * @param array $array
  425. * @param string $key_segment
  426. * @param bool $break
  427. *
  428. * @return bool
  429. */
  430. protected static function callback_has( array &$array, $key_segment, &$break = false ) {
  431. if ( ! array_key_exists( $key_segment, $array ) ) {
  432. $break = true;
  433. return false;
  434. }
  435. $array = $array[ $key_segment ];
  436. return true;
  437. }
  438. /**
  439. * Is Valid Array() function callback for key dot notation walker
  440. *
  441. * @since 1.0.0
  442. *
  443. * @param array $array
  444. * @param string $key
  445. * @param bool $break
  446. * @param array $args
  447. *
  448. * @return bool
  449. */
  450. protected static function callback_is_array( array &$array, $key, &$break = false, $args ) {
  451. $is_valid = array_key_exists( $key, $array )
  452. ? self::is_array_element_valid_array( $array, $key, $args['valid_if_not_empty'] )
  453. : false;
  454. if ( true === $is_valid ) {
  455. $array = $array[ $key ];
  456. return true;
  457. }
  458. $break = true;
  459. return false;
  460. }
  461. /**
  462. * Checks if the array element, indicated by the key, is a valid array.
  463. *
  464. * @since 1.0.0
  465. *
  466. * @param array $array
  467. * @param string $key
  468. * @param bool $valid_if_not_empty
  469. *
  470. * @return bool
  471. */
  472. protected static function is_array_element_valid_array( array $array, $key, $valid_if_not_empty = true ) {
  473. return is_array( $array[ $key ] ) && ( ! $valid_if_not_empty || ! empty( $array[ $key ] ) );
  474. }
  475. }