* @license http://www.gnu.org/licenses/ GPLv3 * @link http://ermshaus.org/2010/03/php-kaloa-spl-arrayobject See for * examples and additional info * @see ArrayObject * @version 2010-03-10 */ class Kaloa_Spl_ArrayObject extends ArrayObject { /** * Adds possibility to pass multi-dimensional arrays to the constructor * * All arrays found among the values of the passed array will be transformed * recursively to instances of Kaloa_Spl_ArrayObject. * * @param array $array Data array to initialize class with */ public function __construct(array $array) { foreach($array as $key => $value) { if (is_array($value)) { $array[$key] = new self($value); } } parent::__construct($array); } /** * Groups the array by one or more criteria defined via callback function * * Each element in the first dimension of the array is passed to the * specified callback function and will be reordered in regard to the * returned value. This can either be a string with the new key or an array * with a stack of new keys. For an element $e, the callback * return value array('a', 'b') translates to * $newArray['a']['b'][] = $e;. * * Callback functions may take the element argument by reference and modify * it during execution (e. g. to remove any fields that will be grouped by). * * @param callback $func Function to group by * @return Kaloa_Spl_ArrayObject Provides fluent interface */ public function groupBy($func) { $ret = array(); $it = $this->getIterator(); while ($it->valid()) { if (is_object($it->current())) { $key = call_user_func($func, $it->current()); } else { // Pass scalar values by reference, too $value = $it->current(); $key = call_user_func_array($func, array(&$value)); $it->offsetSet($it->key(), $value); unset($value); } if (is_array($key)) { $ref = &$ret; foreach ($key as $subkey) { if (!array_key_exists($subkey, $ref)) { $ref[$subkey] = array(); } $ref = &$ref[$subkey]; } $ref[] = $it->current(); } else { $ret[$key][] = $it->current(); } $it->next(); } unset($ref); $ret = new self($ret); $this->exchangeArray($ret->getArrayCopy()); return $this; } /** * Adds usort as an instance method * * @param callback $cmp_function Function to sort by * @return boolean */ public function usort($cmp_function) { $tmp = $this->getArrayCopy(); $ret = usort($tmp, $cmp_function); $tmp = new self($tmp); $this->exchangeArray($tmp->getArrayCopy()); return $ret; } /** * Recursively applies all provided sorting functions to their corresponding * dimension of the array * * @param Kaloa_Spl_ArrayObject $a Represents the current dimension * in the active array branch * @param array $sortFuncs Holds the specified sorting * function for each dimension * @param int $depth Current dimension * @param string $sortMode Possible values: 'a', 'k', '' * (= uasort, uksort, usort) */ protected function _uxsortmRec(Kaloa_Spl_ArrayObject $a, array $sortFuncs, $depth = 0, $sortMode = '') { $goOn = (count($sortFuncs) > $depth + 1); $it = $a->getIterator(); while ($it->valid()) { if (null !== $sortFuncs[$depth]) { if ($sortMode == 'a') { $it->current()->uasort($sortFuncs[$depth]); } else if ($sortMode == 'k') { $it->current()->uksort($sortFuncs[$depth]); } else { $it->current()->usort($sortFuncs[$depth]); } } if ($goOn) { $this->_uxsortmRec($it->current(), $sortFuncs, $depth + 1, $sortMode); } $it->next(); } } /** * Applies the first sorting function (if set) to the array's first * dimension and starts the recursion to apply the other functions (if set) * * A sorting function is exactly the same as an usort callback. If you don't * want to sort a specific dimension but one or more dimensions below it, * pass null for each dimension that should be skipped. * array(null, null, $func) would sort the third dimension but * leave dimensions one and two untouched. * * @param array|callback $funcs Sorting function(s) to sort one or more * dimensions of the array by * @param string $sortMode Possible values: 'a', 'k', '' (= uasort, * uksort, usort) * @return Kaloa_Spl_ArrayObject Provides fluent interface */ protected function _uxsortm($funcs, $sortMode = '') { if (!is_array($funcs)) { $funcs = array($funcs); } if (count($funcs) > 0) { if (null !== $funcs[0]) { if ($sortMode == 'a') { $this->uasort($funcs[0]); } else if ($sortMode == 'k') { $this->uksort($funcs[0]); } else { $this->usort($funcs[0]); } } if (count($funcs) > 1) { $this->_uxsortmRec($this, $funcs, 1, $sortMode); } } return $this; } /** * * @param array|callback $funcs * @return Kaloa_Spl_ArrayObject Provides fluent interface */ public function usortm($funcs) { return $this->_uxsortm($funcs); } /** * * * @param array|callback $funcs * @return Kaloa_Spl_ArrayObject Provides fluent interface */ public function uasortm($funcs) { return $this->_uxsortm($funcs, 'a'); } /** * * @param array|callback $funcs * @return Kaloa_Spl_ArrayObject Provides fluent interface */ public function uksortm($funcs) { return $this->_uxsortm($funcs, 'k'); } }