Last active
August 29, 2015 14:11
-
-
Save gmazzap/48c5f80ad63bbb8d373b to your computer and use it in GitHub Desktop.
Optimum: a class to filter arrays with callbacks.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php namespace GM; | |
use SplObjectStorage; | |
class Optimum | |
{ | |
private $data; | |
private $raw; | |
private $map; | |
private $storage; | |
/** | |
* @param array $data Raw array to be transformed | |
* @param array $keys_map A map where keys are raw data keys, values transformed data keys | |
*/ | |
public function __construct(array $data = array(), array $keys_map = array()) | |
{ | |
$this->data = $data; | |
$this->raw = $data; | |
$this->map = $keys_map; | |
$this->storage = new SplObjectStorage(); | |
} | |
/** | |
* Returns data how it was before transformation | |
* | |
* @return array | |
*/ | |
public function raw() | |
{ | |
return $this->raw; | |
} | |
/** | |
* Returns data after transformation (if it happen) | |
* | |
* @return array | |
*/ | |
public function data() | |
{ | |
return $this->data; | |
} | |
/** | |
* Return all or a subset of transformed data. Subset may be set with | |
* - an array of keys | |
* - a string with a key | |
* - passing a number of elements in $what param | |
* - using $what and $len as $offset and $length params of array_slice | |
* | |
* @param mixed $what | |
* @param int $len | |
* @return array | |
* @see http://php.net/manual/en/function.array-slice.php | |
*/ | |
public function take($what = true, $len = null) | |
{ | |
if (is_int($what)) { | |
$slice = is_int($len) ? [$what, $len] : [ 0, $what]; | |
return array_slice($this->data, $slice[0], $slice[1]); | |
} elseif (is_array($what) || is_string($what)) { | |
return array_flip(array_intersect(array_flip($this->data), (array) $what)); | |
} | |
return ! empty($what) ? $this->data : array(); | |
} | |
/** | |
* Add a callback to the transformer. | |
* First argument callback will reveice is current array item value. | |
* Second is the current array item key. | |
* Additional arguments can be passed as well in a callback-specific manner using $args param. | |
* Is possible modify args usinbg $slice param: a 2 item array with args for array_slice. | |
* | |
* @param \GM\callable $callback callable to add | |
* @param array $args additional arguments for the callable | |
* @param array $slice array slice arguments to transform args | |
* @return \GM\Optimum | |
*/ | |
public function with(callable $callback, array $args = [], array $slice = []) | |
{ | |
$closure = function () use ($callback) { | |
return call_user_func_array($callback, func_get_args()); | |
}; | |
$this->storage[$closure] = ['args' => $args, 'slice' => $slice]; | |
return $this; | |
} | |
/** | |
* Add a callback to the transformer that run only on items with specifick keys. | |
* First argument callback will reveice is current array item value. | |
* Second is the current array item key. | |
* Additional arguments can be passed as well in a callback-specific manner using $args param. | |
* Is possible modify args usinbg $slice param: a 2 item array with args for array_slice. | |
* | |
* @param array $keys a set of key to run callback on related values | |
* @param \GM\callable $callback callable to add | |
* @param array $args additional arguments for the callable | |
* @param array $slice array slice arguments to transform args | |
* @return \GM\Optimum | |
*/ | |
public function withFor(array $keys, callable $callback, array $args = [], array $slice = []) | |
{ | |
$closure = function () use ($callback) { | |
return call_user_func_array($callback, func_get_args()); | |
}; | |
$this->storage[$closure] = ['args' => $args, 'slice' => $slice, 'keys' => $keys]; | |
return $this; | |
} | |
/** | |
* Call recursevely all the registered callbacks to all items of original array. | |
* | |
* @return \GM\Optimum | |
*/ | |
public function transform() | |
{ | |
array_walk($this->data, [$this, 'run']); | |
$this->data = array_combine( | |
array_map([$this, 'map'], array_keys($this->data)), array_values($this->data) | |
); | |
return $this; | |
} | |
private function run(&$item, $key) | |
{ | |
$this->storage->rewind(); | |
while ($this->storage->valid()) { | |
$i = $this->storage->getInfo(); | |
if (! isset($i['keys']) || in_array($key, $i['keys'], true)) { | |
$all_args = array_merge([$item, $key], $i['args']); | |
$args = ! empty($i['slice']) ? $this->args($all_args, $i['slice']) : $all_args; | |
$item = call_user_func_array($this->storage->current(), $args); | |
} | |
$this->storage->next(); | |
} | |
} | |
private function map($key) | |
{ | |
return isset($this->map[$key]) && is_string($this->map[$key]) ? $this->map[$key] : $key; | |
} | |
private function args(array $args, array $slice) | |
{ | |
$i = array_shift($slice); | |
return empty($slice) ? array_slice($args, $i) : array_slice($args, $i, array_shift($slice)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Assuming this code:
Will output: