+ /**
+ * Check if a key isset which may be several layers deep.
+ *
+ * This is a helper for when the calling function does not know how many layers deep the
+ * path array is so cannot easily check.
+ *
+ * @param array $array
+ * @param array $path
+ * @return bool
+ * @throws \CRM_Core_Exception
+ */
+ public static function recursiveIsset($array, $path) {
+ foreach ($path as $key) {
+ if (!is_array($array) || !isset($array[$key])) {
+ return FALSE;
+ }
+ $array = $array[$key];
+ }
+ return TRUE;
+ }
+
+ /**
+ * Check if a key isset which may be several layers deep.
+ *
+ * This is a helper for when the calling function does not know how many layers deep the
+ * path array is so cannot easily check.
+ *
+ * @param array $array
+ * @param array $path
+ * An array of keys - e.g [0, 'bob', 8] where we want to check if $array[0]['bob'][8]
+ * @param mixed $default
+ * Value to return if not found.
+ * @return bool
+ * @throws \CRM_Core_Exception
+ */
+ public static function recursiveValue($array, $path, $default = NULL) {
+ foreach ($path as $key) {
+ if (!is_array($array) || !isset($array[$key])) {
+ return $default;
+ }
+ $array = $array[$key];
+ }
+ return $array;
+ }
+
+ /**
+ * Append the value to the array using the key provided.
+ *
+ * e.g if value is 'llama' & path is [0, 'email', 'location'] result will be
+ * [0 => ['email' => ['location' => 'llama']]
+ *
+ * @param $path
+ * @param $value
+ * @param array $source
+ *
+ * @return array
+ */
+ public static function recursiveBuild($path, $value, $source = []) {
+ $arrayKey = array_shift($path);
+ // Recurse through array keys
+ if ($path) {
+ if (!isset($source[$arrayKey])) {
+ $source[$arrayKey] = [];
+ }
+ $source[$arrayKey] = self::recursiveBuild($path, $value, $source[$arrayKey]);
+ }
+ // Final iteration
+ else {
+ $source[$arrayKey] = $value;
+ }
+ return $source;
+ }
+