3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.3 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
31 * @copyright CiviCRM LLC (c) 2004-2013
35 class CRM_Utils_Array
{
38 * if the key exists in the list returns the associated value
42 * @param array $list the array to be searched
43 * @param string $key the key value
45 * @return value if exists else null
50 static function value($key, $list, $default = NULL) {
51 if (is_array($list)) {
52 return array_key_exists($key, $list) ?
$list[$key] : $default;
58 * Given a parameter array and a key to search for,
59 * search recursively for that key's value.
61 * @param array $values The parameter array
62 * @param string $key The key to search for
64 * @return mixed The value of the key, or null.
68 static function retrieveValueRecursive(&$params, $key) {
69 if (!is_array($params)) {
72 elseif ($value = CRM_Utils_Array
::value($key, $params)) {
76 foreach ($params as $subParam) {
77 if (is_array($subParam) &&
78 $value = self
::retrieveValueRecursive($subParam, $key)
88 * if the value exists in the list returns the associated key
92 * @param list the array to be searched
93 * @param value the search value
95 * @return key if exists else null
100 static function key($value, &$list) {
101 if (is_array($list)) {
102 $key = array_search($value, $list);
104 // array_search returns key if found, false otherwise
105 // it may return values like 0 or empty string which
106 // evaluates to false
107 // hence we must use identical comparison operator
108 return ($key === FALSE) ?
NULL : $key;
113 static function &xml(&$list, $depth = 1, $seperator = "\n") {
115 foreach ($list as $name => $value) {
116 $xml .= str_repeat(' ', $depth * 4);
117 if (is_array($value)) {
118 $xml .= "<{$name}>{$seperator}";
119 $xml .= self
::xml($value, $depth +
1, $seperator);
120 $xml .= str_repeat(' ', $depth * 4);
121 $xml .= "</{$name}>{$seperator}";
124 // make sure we escape value
125 $value = self
::escapeXML($value);
126 $xml .= "<{$name}>$value</{$name}>{$seperator}";
132 static function escapeXML($value) {
137 $src = array('&', '<', '>', '\ 1');
138 $dst = array('&', '<', '>', ',');
141 return str_replace($src, $dst, $value);
145 * Convert an array-tree to a flat array
147 * @param array $list the original, tree-shaped list
148 * @param array $flat the flat list to which items will be copied
149 * @param string $prefix
150 * @param string $seperator
152 static function flatten(&$list, &$flat, $prefix = '', $seperator = ".") {
153 foreach ($list as $name => $value) {
154 $newPrefix = ($prefix) ?
$prefix . $seperator . $name : $name;
155 if (is_array($value)) {
156 self
::flatten($value, $flat, $newPrefix, $seperator);
159 if (!empty($value)) {
160 $flat[$newPrefix] = $value;
167 * Convert an array with path-like keys into a tree of arrays
169 * @param $delim A path delimiter
170 * @param $arr A one-dimensional array indexed by string keys
172 * @return array-encoded tree
174 function unflatten($delim, &$arr) {
176 foreach ($arr as $key => $value) {
177 $path = explode($delim, $key);
179 while (count($path) > 1) {
180 $key = array_shift($path);
181 if (!isset($node[$key])) {
182 $node[$key] = array();
184 $node = &$node[$key];
187 $key = array_shift($path);
188 $node[$key] = $value;
194 * Funtion to merge to two arrays recursively
202 static function crmArrayMerge($a1, $a2) {
212 foreach ($a1 as $key => $value) {
213 if (array_key_exists($key, $a2) &&
214 is_array($a2[$key]) && is_array($a1[$key])
216 $a3[$key] = array_merge($a1[$key], $a2[$key]);
219 $a3[$key] = $a1[$key];
223 foreach ($a2 as $key => $value) {
224 if (array_key_exists($key, $a1)) {
225 // already handled in above loop
228 $a3[$key] = $a2[$key];
234 static function isHierarchical(&$list) {
235 foreach ($list as $n => $v) {
246 * @params array $array
247 * @params int $maxdepth
250 * @return array copy of the array
255 static function array_deep_copy(&$array, $maxdepth = 50, $depth = 0) {
256 if ($depth > $maxdepth) {
260 foreach ($array as $key => $value) {
261 if (is_array($value)) {
262 array_deep_copy($value, $copy[$key], $maxdepth, ++
$depth);
265 $copy[$key] = $value;
272 * In some cases, functions return an array by reference, but we really don't
273 * want to receive a reference.
278 static function breakReference($array) {
284 * Array splice function that preserves associative keys
285 * defauly php array_splice function doesnot preserve keys
286 * So specify start and end of the array that you want to remove
288 * @param array $params array to slice
289 * @param Integer $start
290 * @param Integer $end
295 static function crmArraySplice(&$params, $start, $end) {
296 // verify start and end date
300 if ($end > count($params)) {
301 $end = count($params);
306 // procees unset operation
307 foreach ($params as $key => $value) {
308 if ($i >= $start && $i < $end) {
309 unset($params[$key]);
316 * Function for case insensitive in_array search
318 * @param $value value or search string
319 * @param $params array that need to be searched
320 * @param $caseInsensitive boolean true or false
324 static function crmInArray($value, $params, $caseInsensitive = TRUE) {
325 foreach ($params as $item) {
326 if (is_array($item)) {
327 $ret = crmInArray($value, $item, $caseInsensitive);
330 $ret = ($caseInsensitive) ?
strtolower($item) == strtolower($value) : $item == $value;
340 * This function is used to convert associative array names to values
343 * This function is used by both the web form layer and the api. Note that
344 * the api needs the name => value conversion, also the view layer typically
345 * requires value => name conversion
347 static function lookupValue(&$defaults, $property, $lookup, $reverse) {
348 $id = $property . '_id';
350 $src = $reverse ?
$property : $id;
351 $dst = $reverse ?
$id : $property;
353 if (!array_key_exists(strtolower($src), array_change_key_case($defaults, CASE_LOWER
))) {
357 $look = $reverse ?
array_flip($lookup) : $lookup;
359 //trim lookup array, ignore . ( fix for CRM-1514 ), eg for prefix/suffix make sure Dr. and Dr both are valid
361 foreach ($look as $k => $v) {
362 $newLook[trim($k, ".")] = $v;
367 if (is_array($look)) {
368 if (!array_key_exists(trim(strtolower($defaults[strtolower($src)]), '.'), array_change_key_case($look, CASE_LOWER
))) {
373 $tempLook = array_change_key_case($look, CASE_LOWER
);
375 $defaults[$dst] = $tempLook[trim(strtolower($defaults[strtolower($src)]), '.')];
380 * Function to check if give array is empty
381 * @param array $array array that needs to be check for empty condition
383 * @return boolean true is array is empty else false
386 static function crmIsEmptyArray($array = array(
388 if (!is_array($array)) {
391 foreach ($array as $element) {
392 if (is_array($element)) {
393 if (!self
::crmIsEmptyArray($element)) {
397 elseif (isset($element)) {
405 * Function to determine how many levels in array for multidimensional arrays
407 * @param array $array
409 * @return integer $levels containing number of levels in array
412 static function getLevelsArray($array) {
413 if (!is_array($array)) {
416 $jsonString = json_encode($array);
417 $parts = explode("}", $jsonString);
419 foreach ($parts as $part) {
420 $countLevels = substr_count($part, "{");
421 if ($countLevels > $max) {
429 * Function to sort an associative array of arrays by an attribute using natural string compare
431 * @param array $array Array to be sorted
432 * @param string $field Name of the attribute you want to sort by
434 * @return array $array Sorted array
437 static function crmArraySortByField($array, $field) {
438 $code = "return strnatcmp(\$a['$field'], \$b['$field']);";
439 uasort($array, create_function('$a,$b', $code));
444 * Recursively removes duplicate values from an multi-dimensional array.
446 * @param array $array The input array possibly containing duplicate values.
448 * @return array $array The array with duplicate values removed.
451 static function crmArrayUnique($array) {
452 $result = array_map("unserialize", array_unique(array_map("serialize", $array)));
453 foreach ($result as $key => $value) {
454 if (is_array($value)) {
455 $result[$key] = self
::crmArrayUnique($value);
462 * Sort an array and maintain index association, use Collate from the
463 * PECL "intl" package, if available, for UTF-8 sorting (ex: list of countries).
464 * On Debian/Ubuntu: apt-get install php5-intl
466 * @param array $array array of values
468 * @return array Sorted array
471 static function asort($array = array()) {
472 $lcMessages = CRM_Utils_System
::getUFLocale();
474 if ($lcMessages && $lcMessages != 'en_US' && class_exists('Collator')) {
475 $collator = new Collator($lcMessages . '.utf8');
476 $collator->asort($array);
486 * Convenient way to unset a bunch of items from an array
488 * @param array $items (reference)
489 * @param string/int/array $itemN: other params to this function will be treated as keys (or arrays of keys) to unset
491 static function remove(&$items) {
492 foreach (func_get_args() as $n => $key) {
493 if ($n && is_array($key)) {
494 foreach($key as $k) {
505 * Build an array-tree which indexes the records in an array
507 * @param $keys array of string (properties by which to index)
508 * @param $records array of records (objects or assoc-arrays)
509 * @return array; multi-dimensional, with one layer for each key
511 static function index($keys, $records) {
512 $final_key = array_pop($keys);
515 foreach ($records as $record) {
517 foreach ($keys as $key) {
518 if (is_array($record)) {
519 $keyvalue = $record[$key];
521 $keyvalue = $record->{$key};
523 if (!is_array($node[$keyvalue])) {
524 $node[$keyvalue] = array();
526 $node = &$node[$keyvalue];
528 if (is_array($record)) {
529 $node[ $record[$final_key] ] = $record;
531 $node[ $record->{$final_key} ] = $record;
538 * Iterate through a list of records and grab the value of some property
540 * @param string $prop
541 * @param array $records a list of records (object|array)
542 * @return array keys are the original keys of $records; values are the $prop values
544 static function collect($prop, $records) {
546 foreach ($records as $key => $record) {
547 if (is_object($record)) {
548 $result[$key] = $record->{$prop};
550 $result[$key] = $record[$prop];
557 * Given a list of key-value pairs, combine thme into a single string
558 * @param array $pairs e.g. array('a' => '1', 'b' => '2')
559 * @param string $l1Delim e.g. ','
560 * @param string $l2Delim e.g. '='
561 * @return string e.g. 'a=1,b=2'
563 static function implodeKeyValue($l1Delim, $l2Delim, $pairs) {
565 foreach ($pairs as $key => $value) {
566 $exprs[] = $key . $l2Delim . $value;
568 return implode($l1Delim, $exprs);
572 * Like explode() but assumes that the $value is padded with $delim on left and right
574 * @param string|NULL $value
575 * @param string $delim
578 static function explodePadded($value, $delim = CRM_Core_DAO
::VALUE_SEPARATOR
) {
579 if ($value === NULL) {
582 return explode($delim, trim($value, $delim));
586 * Like implode() but assumes that the $value is padded with $delim on left and right
588 * @param string|NULL $value
589 * @param string $delim
592 static function implodePadded($values, $delim = CRM_Core_DAO
::VALUE_SEPARATOR
) {
593 if ($values === NULL) {
596 return $delim . implode($delim, $values) . $delim;
600 * Function to modify the key in an array without actually changing the order
601 * By default when you add an element it is added at the end
603 * @param array $elementArray associated array element
604 * @param string $oldKey old key
605 * @param string $newKey new key
609 static function crmReplaceKey(&$elementArray, $oldKey, $newKey) {
610 $keys = array_keys($elementArray);
611 if (FALSE === $index = array_search($oldKey, $keys)) {
612 throw new Exception(sprintf('key "%s" does not exit', $oldKey));
614 $keys[$index] = $newKey;
615 $elementArray = array_combine($keys, array_values($elementArray));
616 return $elementArray;