PageRenderTime 45ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/classes/arr.php

https://github.com/mjphaynes/core
PHP | 582 lines | 328 code | 67 blank | 187 comment | 34 complexity | 1e885de08db668bdb809b4f2be8c1679 MD5 | raw file
  1. <?php
  2. /**
  3. * Fuel is a fast, lightweight, community driven PHP5 framework.
  4. *
  5. * @package Fuel
  6. * @version 1.0
  7. * @author Fuel Development Team
  8. * @license MIT License
  9. * @copyright 2010 - 2011 Fuel Development Team
  10. * @link http://fuelphp.com
  11. */
  12. namespace Fuel\Core;
  13. /**
  14. * The Arr class provides a few nice functions for making
  15. * dealing with arrays easier
  16. *
  17. * @package Fuel
  18. * @subpackage Core
  19. */
  20. class Arr {
  21. /**
  22. * Gets a dot-notated key from an array, with a default value if it does
  23. * not exist.
  24. *
  25. * @param array $array The search array
  26. * @param mixed $key The dot-notated key or array of keys
  27. * @param string $default The default value
  28. * @return mixed
  29. */
  30. public static function get($array, $key, $default = null)
  31. {
  32. if ( ! is_array($array) or $array instanceof \ArrayAccess)
  33. {
  34. throw new \InvalidArgumentException('First parameter must be an array or ArrayAccess object.');
  35. }
  36. if (is_null($key))
  37. {
  38. return $array;
  39. }
  40. if (is_array($key))
  41. {
  42. $return = array();
  43. foreach ($key as $k)
  44. {
  45. $return[$k] = static::get($array, $k, $default);
  46. }
  47. return $return;
  48. }
  49. foreach (explode('.', $key) as $key_part)
  50. {
  51. if ( ! is_array($array) or ! array_key_exists($key_part, $array))
  52. {
  53. return \Fuel::value($default);
  54. }
  55. $array = $array[$key_part];
  56. }
  57. return $array;
  58. }
  59. /**
  60. * Set an array item (dot-notated) to the value.
  61. *
  62. * @param array $array The array to insert it into
  63. * @param mixed $key The dot-notated key to set or array of keys
  64. * @param mixed $value The value
  65. * @return void
  66. */
  67. public static function set(&$array, $key, $value = null)
  68. {
  69. if (is_null($key))
  70. {
  71. $array = $value;
  72. return;
  73. }
  74. if (is_array($key))
  75. {
  76. foreach ($key as $k => $v)
  77. {
  78. static::set($array, $k, $value);
  79. }
  80. }
  81. $keys = explode('.', $key);
  82. while (count($keys) > 1)
  83. {
  84. $key = array_shift($keys);
  85. if ( ! isset($array[$key]) or ! is_array($array[$key]))
  86. {
  87. $array[$key] = array();
  88. }
  89. $array =& $array[$key];
  90. }
  91. $array[array_shift($keys)] = $value;
  92. }
  93. /**
  94. * Array_key_exists with a dot-notated key from an array.
  95. *
  96. * @param array $array The search array
  97. * @param mixed $key The dot-notated key or array of keys
  98. * @return mixed
  99. */
  100. public static function key_exists($array, $key)
  101. {
  102. foreach (explode('.', $key) as $key_part)
  103. {
  104. if ( ! is_array($array) or ! array_key_exists($key_part, $array))
  105. {
  106. return false;
  107. }
  108. $array = $array[$key_part];
  109. }
  110. return true;
  111. }
  112. /**
  113. * Unsets dot-notated key from an array
  114. *
  115. * @param array $array The search array
  116. * @param mixed $key The dot-notated key or array of keys
  117. * @param string $default The default value
  118. * @return mixed
  119. */
  120. public static function delete(&$array, $key)
  121. {
  122. if (is_null($key))
  123. {
  124. return false;
  125. }
  126. if (is_array($key))
  127. {
  128. $return = array();
  129. foreach ($key as $k)
  130. {
  131. $return[$k] = static::delete($array, $k);
  132. }
  133. return $return;
  134. }
  135. $key_parts = explode('.', $key);
  136. if ( ! is_array($array) or ! array_key_exists($key_parts[0], $array))
  137. {
  138. return false;
  139. }
  140. $this_key = array_shift($key_parts);
  141. if ( ! empty($key_parts))
  142. {
  143. $key = implode('.', $key_parts);
  144. return static::delete($array[$this_key], $key);
  145. }
  146. else
  147. {
  148. unset($array[$this_key]);
  149. }
  150. return true;
  151. }
  152. /**
  153. * Converts a multi-dimensional associative array into an array of key => values with the provided field names
  154. *
  155. * @param array the array to convert
  156. * @param string the field name of the key field
  157. * @param string the field name of the value field
  158. * @return array
  159. */
  160. public static function assoc_to_keyval($assoc = null, $key_field = null, $val_field = null)
  161. {
  162. if(empty($assoc) OR empty($key_field) OR empty($val_field))
  163. {
  164. return null;
  165. }
  166. $output = array();
  167. foreach($assoc as $row)
  168. {
  169. if(isset($row[$key_field]) AND isset($row[$val_field]))
  170. {
  171. $output[$row[$key_field]] = $row[$val_field];
  172. }
  173. }
  174. return $output;
  175. }
  176. /**
  177. * Converts the given 1 dimensional non-associative array to an associative
  178. * array.
  179. *
  180. * The array given must have an even number of elements or null will be returned.
  181. *
  182. * Arr::to_assoc(array('foo','bar'));
  183. *
  184. * @param string $arr the array to change
  185. * @return array|null the new array or null
  186. */
  187. public static function to_assoc($arr)
  188. {
  189. if (($count = count($arr)) % 2 > 0)
  190. {
  191. return null;
  192. }
  193. $keys = $vals = array();
  194. for ($i = 0; $i < $count - 1; $i += 2)
  195. {
  196. $keys[] = array_shift($arr);
  197. $vals[] = array_shift($arr);
  198. }
  199. return array_combine($keys, $vals);
  200. }
  201. /**
  202. * Flattens a multi-dimensional associative array down into a 1 dimensional
  203. * associative array.
  204. *
  205. * @param array the array to flatten
  206. * @param string what to glue the keys together with
  207. * @param bool whether to reset and start over on a new array
  208. * @param bool whether to flatten only associative array's, or also indexed ones
  209. * @return array
  210. */
  211. public static function flatten($array, $glue = ':', $reset = true, $indexed = true)
  212. {
  213. static $return = array();
  214. static $curr_key = array();
  215. if ($reset)
  216. {
  217. $return = array();
  218. $curr_key = array();
  219. }
  220. foreach ($array as $key => $val)
  221. {
  222. $curr_key[] = $key;
  223. if (is_array($val) and ($indexed or array_values($val) !== $val))
  224. {
  225. static::flatten_assoc($val, $glue, false);
  226. }
  227. else
  228. {
  229. $return[implode($glue, $curr_key)] = $val;
  230. }
  231. array_pop($curr_key);
  232. }
  233. return $return;
  234. }
  235. /**
  236. * Flattens a multi-dimensional associative array down into a 1 dimensional
  237. * associative array.
  238. *
  239. * @param array the array to flatten
  240. * @param string what to glue the keys together with
  241. * @param bool whether to reset and start over on a new array
  242. * @return array
  243. */
  244. public static function flatten_assoc($array, $glue = ':', $reset = true)
  245. {
  246. return static::flatten($array, $glue, $reset, false);
  247. }
  248. /**
  249. * Filters an array on prefixed associative keys.
  250. *
  251. * @param array the array to filter.
  252. * @param string prefix to filter on.
  253. * @param bool whether to remove the prefix.
  254. * @return array
  255. */
  256. public static function filter_prefixed($array, $prefix = 'prefix_', $remove_prefix = true)
  257. {
  258. $return = array();
  259. foreach ($array as $key => $val)
  260. {
  261. if(preg_match('/^'.$prefix.'/', $key))
  262. {
  263. if($remove_prefix === true)
  264. {
  265. $key = preg_replace('/^'.$prefix.'/','',$key);
  266. }
  267. $return[$key] = $val;
  268. }
  269. }
  270. return $return;
  271. }
  272. /**
  273. * Filters an array by an array of keys
  274. *
  275. * @param array the array to filter.
  276. * @param array the keys to filter
  277. * @param bool if true, removes the matched elements.
  278. * @return array
  279. */
  280. public static function filter_keys($array, $keys, $remove = false)
  281. {
  282. $return = array();
  283. foreach ($keys as $key)
  284. {
  285. if (isset($array[$key]) and ! $remove)
  286. {
  287. $return[$key] = $array[$key];
  288. }
  289. elseif (isset($array[$key]) and $remove)
  290. {
  291. unset($array[$key]);
  292. }
  293. }
  294. return $remove ? $array : $return;
  295. }
  296. /**
  297. * Returns the element of the given array or a default if it is not set.
  298. *
  299. * @param array the array to fetch from
  300. * @param mixed the key to fetch from the array
  301. * @param mixed the value returned when not an array or invalid key
  302. * @return mixed
  303. * @deprecated until 1.2
  304. */
  305. public static function element($array, $key, $default = false)
  306. {
  307. return static::get($array, $key, $default);
  308. }
  309. /**
  310. * Returns the elements of the given array or a default if it is not set.
  311. *
  312. * @param array the array to fetch from
  313. * @param array the keys to fetch from the array
  314. * @param mixed the value returned when not an array or invalid key
  315. * @return mixed
  316. * @deprecated until 1.2
  317. */
  318. public static function elements($array, $keys, $default = false)
  319. {
  320. return static::get($array, $keys, $default);
  321. }
  322. /**
  323. * Insert value(s) into an array, mostly an array_splice alias
  324. * WARNING: original array is edited by reference, only boolean success is returned
  325. *
  326. * @param array the original array (by reference)
  327. * @param array|mixed the value(s) to insert, if you want to insert an array it needs to be in an array itself
  328. * @param int the numeric position at which to insert, negative to count from the end backwards
  329. * @return bool false when array shorter then $pos, otherwise true
  330. */
  331. public static function insert(array &$original, $value, $pos)
  332. {
  333. if (count($original) < abs($pos))
  334. {
  335. \Error::notice('Position larger than number of elements in array in which to insert.');
  336. return false;
  337. }
  338. array_splice($original, $pos, 0, $value);
  339. return true;
  340. }
  341. /**
  342. * Insert value(s) into an array after a specific key
  343. * WARNING: original array is edited by reference, only boolean success is returned
  344. *
  345. * @param array the original array (by reference)
  346. * @param array|mixed the value(s) to insert, if you want to insert an array it needs to be in an array itself
  347. * @param string|int the key after which to insert
  348. * @return bool false when key isn't found in the array, otherwise true
  349. */
  350. public static function insert_after_key(array &$original, $value, $key)
  351. {
  352. $pos = array_search($key, array_keys($original));
  353. if ($pos === false)
  354. {
  355. \Error::notice('Unknown key after which to insert the new value into the array.');
  356. return false;
  357. }
  358. return static::insert($original, $value, $pos + 1);
  359. }
  360. /**
  361. * Insert value(s) into an array after a specific value (first found in array)
  362. *
  363. * @param array the original array (by reference)
  364. * @param array|mixed the value(s) to insert, if you want to insert an array it needs to be in an array itself
  365. * @param string|int the value after which to insert
  366. * @return bool false when value isn't found in the array, otherwise true
  367. */
  368. public static function insert_after_value(array &$original, $value, $search)
  369. {
  370. $key = array_search($search, $original);
  371. if ($key === false)
  372. {
  373. \Error::notice('Unknown value after which to insert the new value into the array.');
  374. return false;
  375. }
  376. return static::insert_after_key($original, $value, $key);
  377. }
  378. /**
  379. * Sorts a multi-dimensional array by it's values.
  380. *
  381. * @access public
  382. * @param array The array to fetch from
  383. * @param string The key to sort by
  384. * @param string The order (asc or desc)
  385. * @param int The php sort type flag
  386. * @return array
  387. */
  388. public static function sort($array, $key, $order = 'asc', $sort_flags = SORT_REGULAR)
  389. {
  390. if ( ! is_array($array))
  391. {
  392. throw new \InvalidArgumentException('Arr::sort() - $array must be an array.');
  393. }
  394. foreach ($array as $k=>$v)
  395. {
  396. $b[$k] = static::element($v, $key);
  397. }
  398. switch ($order)
  399. {
  400. case 'asc':
  401. asort($b, $sort_flags);
  402. break;
  403. case 'desc':
  404. arsort($b, $sort_flags);
  405. break;
  406. default:
  407. throw new \InvalidArgumentException('Arr::sort() - $order must be asc or desc.');
  408. break;
  409. }
  410. foreach ($b as $key=>$val)
  411. {
  412. $c[] = $array[$key];
  413. }
  414. return $c;
  415. }
  416. /**
  417. * Find the average of an array
  418. *
  419. * @param array the array containing the values
  420. * @return numeric the average value
  421. */
  422. public static function average($array)
  423. {
  424. // No arguments passed, lets not divide by 0
  425. if ( ! ($count = count($array)) > 0)
  426. {
  427. return 0;
  428. }
  429. return (array_sum($array) / $count);
  430. }
  431. /**
  432. * Alias for replace_key for backwards compatibility.
  433. */
  434. public static function replace_keys($source, $replace, $new_key = null)
  435. {
  436. logger(\Fuel::L_WARNING, 'This method is deprecated. Please use a replace_key() instead.', __METHOD__);
  437. return static::replace_key($source, $replace, $new_key);
  438. }
  439. /**
  440. * Replaces key names in an array by names in $replace
  441. *
  442. * @param array the array containing the key/value combinations
  443. * @param array|string key to replace or array containing the replacement keys
  444. * @param string the replacement key
  445. * @return array the array with the new keys
  446. */
  447. public static function replace_key($source, $replace, $new_key = null)
  448. {
  449. if(is_string($replace))
  450. {
  451. $replace = array($replace => $new_key);
  452. }
  453. if ( ! is_array($source) or ! is_array($replace))
  454. {
  455. throw new \InvalidArgumentException('Arr::replace_keys() - $source must an array. $replace must be an array or string.');
  456. }
  457. $result = array();
  458. foreach ($source as $key => $value)
  459. {
  460. if (array_key_exists($key, $replace))
  461. {
  462. $result[$replace[$key]] = $value;
  463. }
  464. else
  465. {
  466. $result[$key] = $value;
  467. }
  468. }
  469. return $result;
  470. }
  471. /**
  472. * Merge 2 arrays recursively, differs in 2 important ways from array_merge_recursive()
  473. * - When there's 2 different values and not both arrays, the latter value overwrites the earlier
  474. * instead of merging both into an array
  475. * - Numeric keys that don't conflict aren't changed, only when a numeric key already exists is the
  476. * value added using array_push()
  477. *
  478. * @param array multiple variables all of which must be arrays
  479. * @return array
  480. * @throws \InvalidArgumentException
  481. */
  482. public static function merge()
  483. {
  484. $array = func_get_arg(0);
  485. $arrays = array_slice(func_get_args(), 1);
  486. if ( ! is_array($array))
  487. {
  488. throw new \InvalidArgumentException('Arr::merge() - all arguments must be arrays.');
  489. }
  490. foreach ($arrays as $arr)
  491. {
  492. if ( ! is_array($arr))
  493. {
  494. throw new \InvalidArgumentException('Arr::merge() - all arguments must be arrays.');
  495. }
  496. foreach ($arr as $k => $v)
  497. {
  498. // numeric keys are appended
  499. if (is_int($k))
  500. {
  501. array_key_exists($k, $array) ? array_push($array, $v) : $array[$k] = $v;
  502. }
  503. elseif (is_array($v) and array_key_exists($k, $array) and is_array($array[$k]))
  504. {
  505. $array[$k] = static::merge($array[$k], $v);
  506. }
  507. else
  508. {
  509. $array[$k] = $v;
  510. }
  511. }
  512. }
  513. return $array;
  514. }
  515. }