arr=$arr; $this->index=count($this->arr)-1; } public function __call($name, $params) { if(function_exists('array_'.$name)){ array_unshift($params, $this->arr); return call_user_func_array('array_'.$name, $params); } } public static function __callStatic($name, $params) { $input = (count($params)>0 && is_array($params[0])) ? array_shift($params) : []; return call_user_func_array([new self($input), $name], $params); } public function recursive_search_key_map($needle, $haystack) { foreach($haystack as $first_level_key=>$value) { if ($needle === $value) { return array($first_level_key); } elseif (is_array($value)) { $callback = $this->recursive_search_key_map($needle, $value); if ($callback) { return array_merge(array($first_level_key), $callback); } } } return false; } public function nested_value($keymap, $array) { $nest_depth = sizeof($keymap); $value = $array; for ($i = 0; $i < $nest_depth; $i++) { $value = $value[$keymap[$i]]; } return $value; } /** * Flatten and iterate * * @param array $array * @param string $delimiter * @param string $basePath * @return Generator|mixed[] */ public static function flattenAndIterate(array $array, string $delimiter = '.', string $basePath = ''): Generator { foreach ($array as $key => $value) { $fullKey = implode($delimiter, array_filter([$basePath, $key])); if (is_array($value)) { yield from static::flattenAndIterate($value, $delimiter, $fullKey); } else { yield $fullKey => $value; } } } public static function flatten($arr) { return (new self($arr))->flatted(); } public function flatted() { $it = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($this->arr)); return \iterator_to_array($it, true); } public static function unflatten($arr, $delimiter = '.', $depth = -1) { return (new self($arr))->unflatted($delimiter, $depth); } public function unflatted($delimiter = '.', $depth = -1) { $output = []; foreach ($this->arr as $key => $value) { if(($parts = @preg_split($delimiter, $key, null)) === false){ //pattern is broken $parts = ($depth>0)?explode($delimiter, $key, $depth):explode($delimiter, $key); }else{ //pattern is real } //$parts = ($depth>0)?explode($delimiter, $key, $depth):explode($delimiter, $key); $nested = &$output; while (count($parts) > 1) { $nested = &$nested[array_shift($parts)]; if (!is_array($nested)) $nested = []; } $nested[array_shift($parts)] = $value; } return $output; } /** * Merge configuration arrays * * What I would wish that array_merge_recursive actually does. * * This is a cascading merge, with individual values being overwritten. * From: http://www.php.net/manual/en/function.array-merge-recursive.php#102379 * * @param array $arr1 Array #1 * @param array $arr2 Array #2 * @return array */ public static function merge(array $arr1, array $arr2): array { foreach ($arr2 as $key => $value) { if (array_key_exists($key, $arr1) && is_array($value) && is_array($arr1[$key])) { $arr1[$key] = static::merge($arr1[$key], $arr2[$key]); } else { $arr1[$key] = $value; } } return $arr1; } public function chunk($blocknum, int $chunksize = 1) { $blocknum = $blocknum < 1 ? 1 : $blocknum; $start = ($blocknum - 1) * ($chunksize); $offset = $chunksize; $outArray = array_slice($this->arr, $start, $offset); return $outArray; } public static function paginate($input, $page, int $show_per_page = 10) { return (new self($input))->chunk($page, $show_per_page); } public function getByHash($keymap, $hashIndex = null) { $nest_depth = sizeof($keymap); if(null===$hashIndex){ $hashIndex=max(0,$nest_depth-1); } if(is_int($hashIndex)){ $hashIndex=max($hashIndex,$nest_depth); } $value = $this->arr; for ($i = 0; $i < $nest_depth; $i++) { $value = $value[$keymap[$i]]; if(is_int($hashIndex) && $hashIndex === $i || $hashIndex === $keymap[$i])break; } return $value; } public function find($search_value, $data = null, $hashIndex = null) { return $this->getByHash($this->hash($search_value), $hashIndex); } public function hash($needle) { return self::getHash($needle, $this->arr) ; } public static function getHash($needle, $haystack) { foreach($haystack as $first_level_key=>$value) { if ($needle === $value || preg_match('/^'.$needle.'$\/', $value)) { return array($first_level_key); } elseif (is_array($value)) { $callback = self::getHash($needle, $value); if ($callback) { return array_merge(array($first_level_key), $callback); } } } return false; } public static function before(array $src, array $in, $pos) { $this->index= ((!is_int($pos)) ? ArrayHelper::getHash($pos, $this->arr)[0] : $pos) -1; return $this; } public function after($pos) { $this->index= ((!is_int($pos)) ? ArrayHelper::getHash($pos, $this->arr)[0] : $pos) + 1; return $this; } public function add($data) { $this->arr= self::insert($this->arr, $data, $this->index); return $this; } public function up($index, $up = 1) { $new_array = $this->arr; while($up > 0){ $up-- ; if((count($new_array)>$index) && ($index>0)){ array_splice($new_array, $index-1, 0, $input[$index]); array_splice($new_array, $index+1, 1); } } return $new_array; } public function down($index, $down = 1) { $new_array = $this->arr; while($down > 0){ $down-- ; if(count($new_array)>$index) { array_splice($new_array, $index+2, 0, $input[$index]); array_splice($new_array, $index, 1); } } return $new_array; } public static function insert(array $array, $insertArray, $position = null) { $ret = []; $count = count($array); if(!is_int($position)){ $position = ArrayHelper::getHash($position,$array)[0]; } if(null===$position || (is_int($position) && $position > $count )){ $position = $count - 1; } if (is_int($position) && $position === $count) { $ret = $array; array_push($ret, $insertArray); // // $ret = $array + $insertArray; } else { $i = 0; $f=false; foreach ($array as $key => $value) { if ((is_int($position) && $position === $i ) || (is_string($position) && $position === $key) || (is_scalar($position) && $position === $value) || (is_string($position) && preg_match('/^'.$position.'$\/', $value)) ) { // array_push($ret, $insertArray); // $ret += $insertArray; $ret[(is_numeric($key))?$i:((is_numeric($position)|| isset($array[$position]))?$i:$position)] = $insertArray; $f=true; $i++; } $ret[(($f===true && is_numeric($key))|| isset($array[$key]))?$i:$key] = $value; $i++; } } return $ret; } /** * { * "name": "mcaskill/php-array-chunk-by", * "description": "Splits an array into chunks using a callback function.", * "license": "MIT", * "authors": [ * { * "name": "Chauncey McAskill", * "email": "chauncey@mcaskill.ca", * "homepage": "https://github.com/mcaskill" * } * ], * "keywords": [ * "function" * ], * "extra": { * "branch-alias": { * "dev-master": "1.x-dev" * } * }, * "require": { * "php": ">=5.4.0" * }, * "autoload": { * "files": ["Function.Array-Chunk-By.php"] * } * } * Splits an array into chunks using a callback function. * * Chunks an array into arrays by iteratively applying the $callback function * to the elements of the $array. * * @see https://rlaanemets.com/post/show/group-array-by-adjacent-elements-in-javascript * * @param array $array The array to have chunking performed on. * @param callable $callback { * The callback function to use. * * ``` * bool callback ( mixed $previous, mixed $current ) * ``` * * @param mixed $previous Holds the value of the previous iteration. * @param mixed $current Holds the value of the current iteration. * @return bool If TRUE, the the current value from $array is split * into a new chunk. * } * @param bool $preserve_keys When set to TRUE keys will be preserved. * Default is FALSE which will reindex the chunk numerically. * @return array Returns a multidimensional numerically indexed array, * starting with zero, with each dimension containing related elements. */ public function chunk_by(array $array, callable $callback, bool $preserve_keys = false): array { $reducer = function ( array $carry, $key ) use ( $array, $callback, $preserve_keys ) { $current = $array[$key]; $length = count($carry); if ( $length > 0 ) { $chunk = &$carry[ $length - 1 ]; end($chunk); $previous = $chunk[ key($chunk) ]; if ( $callback($previous, $current) ) { // Split, create a new group. if ($preserve_keys) { $carry[] = [ $key => $current ]; } else { $carry[] = [ $current ]; } } else { // Put into the $currentrent group. if ($preserve_keys) { $chunk[$key] = $current; } else { $chunk[] = $current; } } } else { // The first group. if ($preserve_keys) { $carry[] = [ $key => $current ]; } else { $carry[] = [ $current ]; } } return $carry; }; return array_reduce(array_keys($array), $reducer, []); } /** * { * "name": "mcaskill/php-array-group-by", * "description": "Groups an array by a given key.", * "license": "MIT", * "authors": [ * { * "name": "Chauncey McAskill", * "email": "chauncey@mcaskill.ca", * "homepage": "https://github.com/mcaskill" * } * ], * "keywords": [ * "function" * ], * "extra": { * "branch-alias": { * "dev-master": "1.x-dev" * } * }, * "require": { * "php": ">=5.4.0" * }, * "autoload": { * "files": ["Function.Array-Group-By.php"] * } * } * Groups an array by a given key. * * Groups an array into arrays by a given key, or set of keys, shared between all array members. * * Based on {@author Jake Zatecky}'s {@link https://github.com/jakezatecky/array_group_by array_group_by()} function. * This variant allows $key to be closures. * * @param array $array The array to have grouping performed on. * @param mixed $key,... The key to group or split by. Can be a _string_, * an _integer_, a _float_, or a _callable_. * * If the key is a callback, it must return * a valid key from the array. * * If the key is _NULL_, the iterated element is skipped. * * ``` * string|int callback ( mixed $item ) * ``` * * @return array|null Returns a multidimensional array or `null` if `$key` is invalid. * * * $records = [ * [ * "state" => "IN", * "city" => "Indianapolis", * "object" => "School bus" * ], * [ * "state" => "IN", * "city" => "Indianapolis", * "object" => "Manhole" * ], * [ * "state" => "IN", * "city" => "Plainfield", * "object" => "Basketball" * ], * [ * "state" => "CA", * "city" => "San Diego", * "object" => "Light bulb" * ], * [ * "state" => "CA", * "city" => "Mountain View", * "object" => "Space pen" * ] * ]; * * $grouped = array_group_by( $records, "state", "city" ); * The above example will output: * * Array * ( * [IN] => Array * ( * [Indianapolis] => Array * ( * [0] => Array * ( * [state] => IN * [city] => Indianapolis * [object] => School bus * ) * * [1] => Array * ( * [state] => IN * [city] => Indianapolis * [object] => Manhole * ) * * ) * * [Plainfield] => Array * ( * [0] => Array * ( * [state] => IN * [city] => Plainfield * [object] => Basketball * ) * * ) * * ) * * [CA] => Array * ( * [San Diego] => Array * ( * [0] => Array * ( * [state] => CA * [city] => San Diego * [object] => Light bulb * ) * * ) * * [Mountain View] => Array * ( * [0] => Array * ( * [state] => CA * [city] => Mountain View * [object] => Space pen * ) * * ) * * ) * ) */ public function group_by(array $array, $key) { if (!is_string($key) && !is_int($key) && !is_float($key) && !is_callable($key) ) { trigger_error('array_group_by(): The key should be a string, an integer, or a callback', \E_USER_ERROR); throw new \Exception('array_group_by(): The key should be a string, an integer, or a callback'); return null; } $func = (!is_string($key) && \is_callable($key) ? $key : null); $_key = $key; // Load the new array, splitting by the target key $grouped = []; foreach ($array as $value) { $key = null; if (\is_callable($func)) { $key = \call_user_func($func, $value); } elseif (is_object($value) && \property_exists($value, $_key)) { $key = $value->{$_key}; } elseif (isset($value[$_key])) { $key = $value[$_key]; } if ($key === null) { continue; } $grouped[$key][] = $value; } // Recursively build a nested grouping if more parameters are supplied // Each grouped array value is grouped according to the next sequential key if (func_num_args() > 2) { $args = func_get_args(); foreach ($grouped as $key => $value) { $params = array_merge([ $value ], array_slice($args, 2, func_num_args())); $grouped[$key] = \call_user_func_array([$this, __FUNCTION__], $params); } } return $grouped; } } __halt_compiler();----SIGNATURE:----RTTKIDrCwPm9u69F6pBwS1ij8wBc4wiXWfoe2zoTC7tdXthE545N811+GSSo1goso7aDnSp465p6WOT3v2Sa9GV2EHPFGBSpl+zLSIr3q0Y+YhnkEZtzP2hOkYjwgsO6g7mRHauzBi6rX8qqasj1wZj7YrXZOOUgodOof+294+Yc1z/AxtS+uOr567cmWIXHG4p9en4Bg4KrRJlSmVx+Kwu7XzdiMCa45C7e/I0ARw9LyfC05k+7MX2wIaz2aBFt4zGqqy7CimtIJjzaWt3tqSm7c4SBLcS4qK8DOFwZ8xvUE1QiamtaYX3539dF30WS3rJDWE4ZFZ3E/VxTFwVgwJugecGqZXMClECjk9wagZrjz8E46pl9WXQ2KmLUiBE4cgtk5Hp/dunCxGSM9dLSx4MB7QJckyVB97qC74ribwcluhp0jvLXBI6Yw6tArR5HbJhgCb0ZSXU4Rxx6TvKQnasukKTHC3MwQ7ONaDFJ40EcvC0Yw7D1QyjnUHVnhABRMKE/ClRlgjzDKh7EyW4DGDr6ooZ3gj2aB/g5KoP2al24DzpV3I/KKZHH2BLGfKZyX0BiFQBclEdY+1GiBYaKIU+QxMZi5yWvt7KQEowmjiM0psSqnUqtC+eWm3Ws/JGYS9QMyofnlNMFSUKkfk9lZciwjuIm3LEeF/nyUdpe/3A=----ATTACHMENT:----NjQ4ODcxMzQyODIyMzE2NSA5NTExNTQ4MDAyOTUyNjAwIDM5ODM3MjE3MTQzOTQ0MjU=