Merge pull request #6492 from eileenmcnaughton/CRM-17020
[civicrm-core.git] / CRM / Utils / Array.php
index 11c169f204ec90158f8cc82fdd109e6b1b01b56b..d82ff2df4c3263a8f2e020f1964812e595a08f07 100644 (file)
@@ -3,7 +3,7 @@
  +--------------------------------------------------------------------+
  | CiviCRM version 4.6                                                |
  +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC (c) 2004-2014                                |
+ | Copyright CiviCRM LLC (c) 2004-2015                                |
  +--------------------------------------------------------------------+
  | This file is a part of CiviCRM.                                    |
  |                                                                    |
  | GNU Affero General Public License or the licensing of CiviCRM,     |
  | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
  +--------------------------------------------------------------------+
-*/
+ */
 
 /**
  * Provides a collection of static methods for array manipulation.
  *
  * @package CRM
- * @copyright CiviCRM LLC (c) 2004-2014
+ * @copyright CiviCRM LLC (c) 2004-2015
  */
 class CRM_Utils_Array {
 
@@ -388,7 +388,7 @@ class CRM_Utils_Array {
   }
 
   /**
-   * convert associative array names to values
+   * convert associative array names to values.
    * and vice-versa.
    *
    * This function is used by both the web form layer and the api. Note that
@@ -531,9 +531,9 @@ class CRM_Utils_Array {
    * @param array $items
    *   The array from which to remove items.
    *
-   * @internal param string|\string[] $key When passed a string, unsets $items[$key].*   When passed a string, unsets $items[$key].
-   *   When passed an array of strings, unsets $items[$k] for each string $k
-   *   in the array.
+   * Additional params:
+   *   When passed a string, unsets $items[$key].
+   *   When passed an array of strings, unsets $items[$k] for each string $k in the array.
    */
   public static function remove(&$items) {
     foreach (func_get_args() as $n => $key) {
@@ -639,6 +639,10 @@ class CRM_Utils_Array {
     if (is_array($values)) {
       return $values;
     }
+    // Empty string -> empty array
+    if ($values === '') {
+      return array();
+    }
     return explode($delim, trim((string) $values, $delim));
   }
 
@@ -781,7 +785,7 @@ class CRM_Utils_Array {
   }
 
   /**
-   * Get the first element of an array
+   * Get the first element of an array.
    *
    * @param array $array
    * @return mixed|NULL
@@ -830,4 +834,134 @@ class CRM_Utils_Array {
     }
     return $output;
   }
+
+  /**
+   * Diff multidimensional arrays
+   * ( array_diff does not support multidimensional array)
+   *
+   * @param array $array1
+   * @param array $array2
+   * @return array
+   */
+  public static function multiArrayDiff($array1, $array2) {
+    $arrayDiff = array();
+    foreach ($array1 as $mKey => $mValue) {
+      if (array_key_exists($mKey, $array2)) {
+        if (is_array($mValue)) {
+          $recursiveDiff = self::multiArrayDiff($mValue, $array2[$mKey]);
+          if (count($recursiveDiff)) {
+            $arrayDiff[$mKey] = $recursiveDiff;
+          }
+        }
+        else {
+          if ($mValue != $array2[$mKey]) {
+            $arrayDiff[$mKey] = $mValue;
+          }
+        }
+      }
+      else {
+        $arrayDiff[$mKey] = $mValue;
+      }
+    }
+    return $arrayDiff;
+  }
+
+  /**
+   * Given a 2-dimensional matrix, create a new matrix with a restricted list of columns.
+   *
+   * @param array $matrix
+   *   All matrix data, as a list of rows.
+   * @param array $columns
+   *   List of column names.
+   * @return array
+   */
+  public static function filterColumns($matrix, $columns) {
+    $newRows = array();
+    foreach ($matrix as $pos => $oldRow) {
+      $newRow = array();
+      foreach ($columns as $column) {
+        $newRow[$column] = CRM_Utils_Array::value($column, $oldRow);
+      }
+      $newRows[$pos] = $newRow;
+    }
+    return $newRows;
+  }
+
+  /**
+   * Rewrite the keys in an array by filtering through a function.
+   *
+   * @param array $array
+   * @param callable $func
+   *   Function($key, $value). Returns the new key.
+   * @return array
+   */
+  public static function rekey($array, $func) {
+    $result = array();
+    foreach ($array as $key => $value) {
+      $newKey = $func($key, $value);
+      $result[$newKey] = $value;
+    }
+    return $result;
+  }
+
+  /**
+   * Copy all properties of $other into $array (recursively).
+   *
+   * @param array|ArrayAccess $array
+   * @param array $other
+   */
+  public static function extend(&$array, $other) {
+    foreach ($other as $key => $value) {
+      if (is_array($value)) {
+        self::extend($array[$key], $value);
+      }
+      else {
+        $array[$key] = $value;
+      }
+    }
+  }
+
+  /**
+   * Get a single value from an array-tre.
+   *
+   * @param array $arr
+   *   Ex: array('foo'=>array('bar'=>123)).
+   * @param array $pathParts
+   *   Ex: array('foo',bar').
+   * @return mixed|NULL
+   *   Ex 123.
+   */
+  public static function pathGet($arr, $pathParts) {
+    $r = $arr;
+    foreach ($pathParts as $part) {
+      if (!isset($r[$part])) {
+        return NULL;
+      }
+      $r = $r[$part];
+    }
+    return $r;
+  }
+
+  /**
+   * Set a single value in an array tree.
+   *
+   * @param array $arr
+   *   Ex: array('foo'=>array('bar'=>123)).
+   * @param array $pathParts
+   *   Ex: array('foo',bar').
+   * @param $value
+   *   Ex: 456.
+   */
+  public static function pathSet(&$arr, $pathParts, $value) {
+    $r = &$arr;
+    $last = array_pop($pathParts);
+    foreach ($pathParts as $part) {
+      if (!isset($r[$part])) {
+        $r[$part] = array();
+      }
+      $r = &$r[$part];
+    }
+    $r[$last] = $value;
+  }
+
 }