PageRenderTime 43ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/fuel/core/classes/arr.php

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