2007-07-19 12:40:28 +02:00
|
|
|
<?php
|
2013-05-10 14:00:31 +02:00
|
|
|
|
2008-02-25 03:10:37 +01:00
|
|
|
/**
|
|
|
|
* Library of static methods for manipulating arrays.
|
2013-05-10 14:00:31 +02:00
|
|
|
*
|
2012-04-12 08:02:46 +02:00
|
|
|
* @package framework
|
2008-02-25 03:10:37 +01:00
|
|
|
* @subpackage misc
|
|
|
|
*/
|
2010-05-25 06:19:23 +02:00
|
|
|
class ArrayLib {
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2009-07-17 02:01:06 +02:00
|
|
|
/**
|
|
|
|
* Inverses the first and second level keys of an associative
|
|
|
|
* array, keying the result by the second level, and combines
|
|
|
|
* all first level entries within them.
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2009-07-17 02:01:06 +02:00
|
|
|
* Before:
|
|
|
|
* <example>
|
|
|
|
* array(
|
|
|
|
* 'row1' => array(
|
|
|
|
* 'col1' =>'val1',
|
|
|
|
* 'col2' => 'val2'
|
|
|
|
* ),
|
|
|
|
* 'row2' => array(
|
|
|
|
* 'col1' => 'val3',
|
|
|
|
* 'col2' => 'val4'
|
|
|
|
* )
|
|
|
|
* )
|
|
|
|
* </example>
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2009-07-17 02:01:06 +02:00
|
|
|
* After:
|
|
|
|
* <example>
|
|
|
|
* array(
|
|
|
|
* 'col1' => array(
|
|
|
|
* 'row1' => 'val1',
|
|
|
|
* 'row2' => 'val3',
|
|
|
|
* ),
|
|
|
|
* 'col2' => array(
|
|
|
|
* 'row1' => 'val2',
|
|
|
|
* 'row2' => 'val4',
|
|
|
|
* ),
|
|
|
|
* )
|
|
|
|
* </example>
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2009-07-17 02:01:06 +02:00
|
|
|
* @param array $arr
|
|
|
|
* @return array
|
|
|
|
*/
|
2012-09-19 12:07:39 +02:00
|
|
|
public static function invert($arr) {
|
2013-05-10 14:00:31 +02:00
|
|
|
if(!$arr) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-07-17 02:01:06 +02:00
|
|
|
$result = array();
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2007-07-19 12:40:28 +02:00
|
|
|
foreach($arr as $columnName => $column) {
|
|
|
|
foreach($column as $rowName => $cell) {
|
2009-07-17 02:01:06 +02:00
|
|
|
$result[$rowName][$columnName] = $cell;
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2009-07-17 02:01:06 +02:00
|
|
|
return $result;
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2007-07-19 12:40:28 +02:00
|
|
|
/**
|
2013-05-10 14:00:31 +02:00
|
|
|
* Return an array where the keys are all equal to the values.
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2007-07-19 12:40:28 +02:00
|
|
|
* @param $arr array
|
|
|
|
* @return array
|
|
|
|
*/
|
2012-09-19 12:07:39 +02:00
|
|
|
public static function valuekey($arr) {
|
2010-10-15 05:24:32 +02:00
|
|
|
return array_combine($arr, $arr);
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2008-03-03 00:24:10 +01:00
|
|
|
/**
|
|
|
|
* @todo Improve documentation
|
|
|
|
*/
|
2012-09-19 12:07:39 +02:00
|
|
|
public static function array_values_recursive($arr) {
|
2012-12-08 12:20:20 +01:00
|
|
|
$lst = array();
|
2013-05-10 14:00:31 +02:00
|
|
|
|
|
|
|
foreach(array_keys($arr) as $k) {
|
2012-12-08 12:20:20 +01:00
|
|
|
$v = $arr[$k];
|
|
|
|
if (is_scalar($v)) {
|
|
|
|
$lst[] = $v;
|
|
|
|
} elseif (is_array($v)) {
|
|
|
|
$lst = array_merge( $lst,
|
|
|
|
self::array_values_recursive($v)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2013-05-10 14:00:31 +02:00
|
|
|
|
2012-12-08 12:20:20 +01:00
|
|
|
return $lst;
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2007-07-19 12:40:28 +02:00
|
|
|
/**
|
2014-08-15 08:53:05 +02:00
|
|
|
* Filter an array by keys (useful for only allowing certain form-input to
|
2013-05-10 14:00:31 +02:00
|
|
|
* be saved).
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2007-07-19 12:40:28 +02:00
|
|
|
* @param $arr array
|
|
|
|
* @param $keys array
|
2013-05-10 14:00:31 +02:00
|
|
|
*
|
2007-07-19 12:40:28 +02:00
|
|
|
* @return array
|
|
|
|
*/
|
2013-05-10 14:00:31 +02:00
|
|
|
public static function filter_keys($arr, $keys) {
|
|
|
|
foreach($arr as $key => $v) {
|
|
|
|
if(!in_array($key, $keys)) {
|
2007-07-19 12:40:28 +02:00
|
|
|
unset($arr[$key]);
|
|
|
|
}
|
|
|
|
}
|
2013-05-10 14:00:31 +02:00
|
|
|
|
2007-07-19 12:40:28 +02:00
|
|
|
return $arr;
|
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2008-02-25 03:10:37 +01:00
|
|
|
/**
|
2014-08-15 08:53:05 +02:00
|
|
|
* Determines if an array is associative by checking for existing keys via
|
2013-05-10 14:00:31 +02:00
|
|
|
* array_key_exists().
|
|
|
|
*
|
2008-02-25 03:10:37 +01:00
|
|
|
* @see http://nz.php.net/manual/en/function.is-array.php#76188
|
|
|
|
*
|
|
|
|
* @param array $arr
|
2013-05-10 14:00:31 +02:00
|
|
|
*
|
2008-02-25 03:10:37 +01:00
|
|
|
* @return boolean
|
|
|
|
*/
|
2012-09-19 12:07:39 +02:00
|
|
|
public static function is_associative($arr) {
|
2008-02-25 03:10:37 +01:00
|
|
|
if(is_array($arr) && ! empty($arr)) {
|
2012-12-08 12:20:20 +01:00
|
|
|
for($iterator = count($arr) - 1; $iterator; $iterator--) {
|
2013-05-10 14:00:31 +02:00
|
|
|
if (!array_key_exists($iterator, $arr)) {
|
|
|
|
return true;
|
|
|
|
}
|
2012-12-08 12:20:20 +01:00
|
|
|
}
|
2013-05-10 14:00:31 +02:00
|
|
|
|
2012-12-08 12:20:20 +01:00
|
|
|
return !array_key_exists(0, $arr);
|
|
|
|
}
|
2013-05-10 14:00:31 +02:00
|
|
|
|
2012-12-08 12:20:20 +01:00
|
|
|
return false;
|
2008-02-25 03:10:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Recursively searches an array $haystack for the value(s) $needle.
|
2013-05-10 14:00:31 +02:00
|
|
|
*
|
2014-08-15 08:53:05 +02:00
|
|
|
* Assumes that all values in $needle (if $needle is an array) are at
|
2008-02-25 03:10:37 +01:00
|
|
|
* the SAME level, not spread across multiple dimensions of the $haystack.
|
|
|
|
*
|
|
|
|
* @param mixed $needle
|
|
|
|
* @param array $haystack
|
|
|
|
* @param boolean $strict
|
2013-05-10 14:00:31 +02:00
|
|
|
*
|
2008-02-25 03:10:37 +01:00
|
|
|
* @return boolean
|
|
|
|
*/
|
2012-09-19 12:07:39 +02:00
|
|
|
public static function in_array_recursive($needle, $haystack, $strict = false) {
|
2013-05-10 14:00:31 +02:00
|
|
|
if(!is_array($haystack)) {
|
2014-08-15 08:53:05 +02:00
|
|
|
return false;
|
2013-05-10 14:00:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if(in_array($needle, $haystack, $strict)) {
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
foreach($haystack as $obj) {
|
|
|
|
if(self::in_array_recursive($needle, $obj, $strict)) {
|
2014-08-15 08:53:05 +02:00
|
|
|
return true;
|
2013-05-10 14:00:31 +02:00
|
|
|
}
|
2008-02-25 03:10:37 +01:00
|
|
|
}
|
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
|
|
|
return false;
|
2008-02-25 03:10:37 +01:00
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2015-09-21 14:30:12 +02:00
|
|
|
/**
|
|
|
|
* Similar to array_map, but recurses when arrays are encountered.
|
|
|
|
*
|
|
|
|
* Actually only one array argument is supported.
|
|
|
|
*
|
|
|
|
* @param $f callback to apply
|
|
|
|
* @param $array array
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public static function array_map_recursive($f, $array) {
|
|
|
|
$applyOrRecurse = function($v) use($f) {
|
|
|
|
return is_array($v) ? ArrayLib::array_map_recursive($f, $v) : call_user_func($f, $v);
|
|
|
|
};
|
|
|
|
|
|
|
|
return array_map($applyOrRecurse, $array);
|
|
|
|
}
|
|
|
|
|
2011-12-22 23:04:44 +01:00
|
|
|
/**
|
|
|
|
* Recursively merges two or more arrays.
|
|
|
|
*
|
2014-08-15 08:53:05 +02:00
|
|
|
* Behaves similar to array_merge_recursive(), however it only merges
|
|
|
|
* values when both are arrays rather than creating a new array with
|
|
|
|
* both values, as the PHP version does. The same behaviour also occurs
|
2013-05-10 14:00:31 +02:00
|
|
|
* with numeric keys, to match that of what PHP does to generate $_REQUEST.
|
|
|
|
*
|
|
|
|
* @param array $array
|
2011-12-22 23:04:44 +01:00
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
2012-09-19 12:07:39 +02:00
|
|
|
public static function array_merge_recursive($array) {
|
2011-12-22 23:04:44 +01:00
|
|
|
$arrays = func_get_args();
|
|
|
|
$merged = array();
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2011-12-22 23:04:44 +01:00
|
|
|
if(count($arrays) == 1) {
|
|
|
|
return $array;
|
|
|
|
}
|
2013-05-10 14:00:31 +02:00
|
|
|
|
2011-12-22 23:04:44 +01:00
|
|
|
while ($arrays) {
|
|
|
|
$array = array_shift($arrays);
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2011-12-22 23:04:44 +01:00
|
|
|
if (!is_array($array)) {
|
|
|
|
trigger_error('ArrayLib::array_merge_recursive() encountered a non array argument', E_USER_WARNING);
|
|
|
|
return;
|
|
|
|
}
|
2013-05-10 14:00:31 +02:00
|
|
|
|
2011-12-22 23:04:44 +01:00
|
|
|
if (!$array) {
|
|
|
|
continue;
|
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2011-12-22 23:04:44 +01:00
|
|
|
foreach ($array as $key => $value) {
|
|
|
|
if (is_array($value) && array_key_exists($key, $merged) && is_array($merged[$key])) {
|
|
|
|
$merged[$key] = ArrayLib::array_merge_recursive($merged[$key], $value);
|
|
|
|
} else {
|
|
|
|
$merged[$key] = $value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-05-10 14:00:31 +02:00
|
|
|
|
2011-12-22 23:04:44 +01:00
|
|
|
return $merged;
|
|
|
|
}
|
2013-05-10 14:00:31 +02:00
|
|
|
|
2014-08-15 08:53:05 +02:00
|
|
|
/**
|
2013-05-10 14:00:31 +02:00
|
|
|
* Takes an multi dimension array and returns the flattened version.
|
|
|
|
*
|
|
|
|
* @param array $array
|
|
|
|
* @param boolean $preserveKeys
|
|
|
|
*
|
|
|
|
* @return array
|
2014-08-15 08:53:05 +02:00
|
|
|
*/
|
|
|
|
public static function flatten($array, $preserveKeys = true, &$out = array()) {
|
2013-05-10 14:00:31 +02:00
|
|
|
foreach($array as $key => $child) {
|
|
|
|
if(is_array($child)) {
|
|
|
|
$out = self::flatten($child, $preserveKeys, $out);
|
|
|
|
} else if($preserveKeys) {
|
|
|
|
$out[$key] = $child;
|
|
|
|
} else {
|
|
|
|
$out[] = $child;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $out;
|
|
|
|
}
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|