Initial Commit
This commit is contained in:
319
dependencies/rpnzl/arrch/src/Arrch/Arrch.php
vendored
Normal file
319
dependencies/rpnzl/arrch/src/Arrch/Arrch.php
vendored
Normal file
@ -0,0 +1,319 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Ultimo\Dependencies\Arrch;
|
||||
|
||||
/**
|
||||
* Arrch
|
||||
*
|
||||
* @copyright 2012 - 2013
|
||||
* @author Michael Giuliana
|
||||
* @link http://rpnzl.com
|
||||
* @version 1.1.0
|
||||
* @since 2013/5
|
||||
* @license MIT License - http://opensource.org/licenses/MIT
|
||||
*
|
||||
* A small library of array search and sort methods. Perhaps most
|
||||
* useful paired with a simple, flat-file storage system, Arrch
|
||||
* allows psuedo-queries of large arrays.
|
||||
*
|
||||
*/
|
||||
class Arrch
|
||||
{
|
||||
/**
|
||||
* @var arr $defaults The find() method default values.
|
||||
*/
|
||||
public static $defaults = array('where' => array(), 'limit' => 0, 'offset' => 0, 'sort_key' => null, 'sort_order' => 'ASC');
|
||||
/**
|
||||
* @var str $key_split The string to split keys when checking a deep multidimensional array value.
|
||||
*/
|
||||
public static $key_split = '.';
|
||||
/**
|
||||
* @var arr $operators A list of valid operators for comparisons.
|
||||
*/
|
||||
public static $operators = array('==', '===', '!=', '!==', '>', '<', '>=', '<=', '~', '!~');
|
||||
/**
|
||||
* This method combines the functionality of the where() and sort() methods,
|
||||
* with additional limit and offset parameters. Returns an array of matching
|
||||
* array items. Will only sort if a sort key is set.
|
||||
*
|
||||
* @param arr $data The array of objects or associative arrays to search.
|
||||
* @param arr $options The query options, see Arrch::$defaults.
|
||||
* @param misc $key An item's key or index value.
|
||||
* @return arr The result array.
|
||||
*/
|
||||
public static function find(array $data, array $options = array(), $key = 'all')
|
||||
{
|
||||
$options = static::merge(static::$defaults, $options);
|
||||
$data = static::where($data, $options['where']);
|
||||
$data = $options['sort_key'] ? static::sort($data, $options['sort_key'], $options['sort_order']) : $data;
|
||||
$data = \array_slice($data, $options['offset'], $options['limit'] == 0 ? null : $options['limit'], \true);
|
||||
switch ($key) {
|
||||
case 'all':
|
||||
return $data;
|
||||
break;
|
||||
case 'first':
|
||||
return \array_shift($data);
|
||||
break;
|
||||
case 'last':
|
||||
return \array_pop($data);
|
||||
break;
|
||||
default:
|
||||
return isset($data[$key]) ? $data[$key] : null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sorts an array of objects by the specified key.
|
||||
*
|
||||
* @param arr $data The array of objects or associative arrays to sort.
|
||||
* @param str $key The object key or key path to use in sort evaluation.
|
||||
* @param str $order ASC or DESC.
|
||||
* @return arr The result array.
|
||||
*/
|
||||
public static function sort(array $data, $key, $order = null)
|
||||
{
|
||||
\uasort($data, function ($a, $b) use($key) {
|
||||
$a_val = Arrch::extractValues($a, $key);
|
||||
$b_val = Arrch::extractValues($b, $key);
|
||||
// Strings
|
||||
if (\is_string($a_val) && \is_string($b_val)) {
|
||||
return \strcasecmp($a_val, $b_val);
|
||||
} else {
|
||||
if ($a_val == $b_val) {
|
||||
return 0;
|
||||
} else {
|
||||
return $a_val > $b_val ? 1 : -1;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (\strtoupper($order ?: Arrch::$defaults['sort_order']) == 'DESC') {
|
||||
$data = \array_reverse($data, \true);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
/**
|
||||
* Evaluates an object based on an array of conditions
|
||||
* passed into the function, formatted like so...
|
||||
*
|
||||
* array('city', 'arlington');
|
||||
* array('city', '!=', 'arlington');
|
||||
*
|
||||
* @param arr $data The array of objects or associative arrays to search.
|
||||
* @param arr $conditions The conditions to evaluate against.
|
||||
* @return arr The result array.
|
||||
*/
|
||||
public static function where(array $data, array $conditions = array())
|
||||
{
|
||||
foreach ($conditions as $condition) {
|
||||
if (!\is_array($condition)) {
|
||||
\trigger_error('Condition ' . \var_export($condition, \true) . ' must be an array!', \E_USER_ERROR);
|
||||
} else {
|
||||
\array_map(function ($item, $key) use(&$data, $condition) {
|
||||
$return = 0;
|
||||
$operator = \array_key_exists(2, $condition) ? $condition[1] : '===';
|
||||
$search_value = \array_key_exists(2, $condition) ? $condition[2] : $condition[1];
|
||||
if (\is_array($condition[0])) {
|
||||
// array of keys
|
||||
if (\is_array($search_value)) {
|
||||
// array of values
|
||||
foreach ($condition[0] as $prop) {
|
||||
$value = Arrch::extractValues($item, $prop);
|
||||
foreach ($search_value as $query_val) {
|
||||
$return += Arrch::compare(array($value, $operator, $query_val)) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// single value
|
||||
foreach ($condition[0] as $prop) {
|
||||
$value = Arrch::extractValues($item, $prop);
|
||||
$return += Arrch::compare(array($value, $operator, $search_value)) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
} elseif (\is_array($search_value)) {
|
||||
// single key, array of query values
|
||||
$value = Arrch::extractValues($item, $condition[0]);
|
||||
$c = 0;
|
||||
foreach ($search_value as $query_val) {
|
||||
$c += Arrch::compare(array($value, $operator, $query_val)) ? 1 : 0;
|
||||
}
|
||||
// Negate options that don't pass all negative assertions
|
||||
if (\in_array($operator, array('!==', '!=', '!~')) && $c < \count($search_value)) {
|
||||
$c = 0;
|
||||
}
|
||||
$return += $c;
|
||||
} else {
|
||||
// single key, single value
|
||||
$value = Arrch::extractValues($item, $condition[0]);
|
||||
$return = Arrch::compare(array($value, $operator, $search_value));
|
||||
}
|
||||
// Unset
|
||||
if (!$return) {
|
||||
unset($data[$key]);
|
||||
}
|
||||
}, $data, \array_keys($data));
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
/**
|
||||
* Finds the requested value in a multidimensional array or an object and
|
||||
* returns it.
|
||||
*
|
||||
* @param mixed $item The item containing the value.
|
||||
* @param str $key The key or key path to the desired value.
|
||||
* @return mixed The found value or null.
|
||||
*/
|
||||
public static function extractValues($item, $key)
|
||||
{
|
||||
// Array of results
|
||||
$results = array();
|
||||
// Cast as array if object
|
||||
$item = \is_object($item) ? (array) $item : $item;
|
||||
// Array of keys
|
||||
$keys = \strstr($key, static::$key_split) ? \explode(static::$key_split, $key) : array($key);
|
||||
$keys = \array_filter($keys);
|
||||
// Key count
|
||||
$key_count = \count($keys);
|
||||
// key count > 0
|
||||
if ($key_count > 0) {
|
||||
$curr_key = \array_shift($keys);
|
||||
$arrayValues = \array_values($item);
|
||||
$child = \is_array($item) ? \array_shift($arrayValues) : null;
|
||||
// it's an array
|
||||
if (\is_array($item)) {
|
||||
// Clean non-ASCII keys
|
||||
foreach ($item as $k => $v) {
|
||||
$sanitized = \preg_replace('/[^(\\x20-\\x7F)]*/', '', $k);
|
||||
if ($sanitized !== $k) {
|
||||
$item[$sanitized] = $v;
|
||||
unset($item[$k]);
|
||||
}
|
||||
}
|
||||
// it has the keys
|
||||
if (\array_key_exists($curr_key, $item)) {
|
||||
$results = \array_merge($results, static::extractValues($item[$curr_key], \implode(static::$key_split, $keys)));
|
||||
// else it's child has the key
|
||||
} elseif (\is_array($child) || \is_object($child)) {
|
||||
if (\array_key_exists($curr_key, $child)) {
|
||||
foreach ($item as $child) {
|
||||
$results = \array_merge($results, static::extractValues($child, $key));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// no key
|
||||
} else {
|
||||
$results[] = $item;
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
/**
|
||||
* Runs comparison operations on an array of values formatted like so...
|
||||
*
|
||||
* e.g. array($value, $operator, $value)
|
||||
*
|
||||
* Returns true or false depending on the outcome of the requested
|
||||
* comparative operation (<, >, =, etc..).
|
||||
*
|
||||
* @param arr $array The comparison array.
|
||||
* @return bool Whether the operation evaluates to true or false.
|
||||
*/
|
||||
public static function compare(array $array)
|
||||
{
|
||||
$return = 0;
|
||||
foreach ($array[0] as $value) {
|
||||
if ($array[1] === '~') {
|
||||
// Check if variables loosely match right away
|
||||
if ($value != $array[2]) {
|
||||
if (\is_string($value) && \is_string($array[2])) {
|
||||
$return += \stristr($value, $array[2]) ? 1 : 0;
|
||||
} elseif (\is_null($value) && \is_null($array[2])) {
|
||||
$return += 1;
|
||||
} elseif (\is_array($value) || \is_object($value)) {
|
||||
$return += \stristr(\var_export($value, \true), $array[2]) ? 1 : 0;
|
||||
}
|
||||
} else {
|
||||
$return += 1;
|
||||
}
|
||||
} elseif ($array[1] === '!~') {
|
||||
if (\is_string($value) && \is_string($array[2])) {
|
||||
$return += !\stristr($value, $array[2]) ? 1 : 0;
|
||||
} elseif (\is_null($value) && \is_null($array[2])) {
|
||||
$return += 0;
|
||||
} elseif (\is_array($value) || \is_object($value)) {
|
||||
$return += !\stristr(\var_export($value, \true), $array[2]) ? 1 : 0;
|
||||
}
|
||||
} else {
|
||||
if (\is_array($value) || \is_object($value)) {
|
||||
\trigger_error('Cannot compare object of type ' . \strtoupper(\gettype($value)) . ' with the "' . $array[1] . '" operator.', \E_USER_WARNING);
|
||||
}
|
||||
if (!\in_array($array[1], static::$operators)) {
|
||||
\trigger_error('Operator "' . $array[1] . '" is not valid.', \E_USER_ERROR);
|
||||
} else {
|
||||
switch ($array[1]) {
|
||||
case '==':
|
||||
$return += $value == $array[2] ? 1 : 0;
|
||||
break;
|
||||
case '===':
|
||||
$return += $value === $array[2] ? 1 : 0;
|
||||
break;
|
||||
case '!=':
|
||||
$return += $value != $array[2] ? 1 : 0;
|
||||
break;
|
||||
case '!==':
|
||||
$return += $value !== $array[2] ? 1 : 0;
|
||||
break;
|
||||
case '>':
|
||||
$return += $value > $array[2] ? 1 : 0;
|
||||
break;
|
||||
case '<':
|
||||
$return += $value < $array[2] ? 1 : 0;
|
||||
break;
|
||||
case '>=':
|
||||
$return += $value >= $array[2] ? 1 : 0;
|
||||
break;
|
||||
case '<=':
|
||||
$return += $value <= $array[2] ? 1 : 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
/**
|
||||
* Recursive array merge for options arrays to eliminate duplicates
|
||||
* in a smart manner using a variable number of array arguments.
|
||||
*
|
||||
* @param arr Various options arrays.
|
||||
* @return arr The merged array.
|
||||
*/
|
||||
public static function merge()
|
||||
{
|
||||
$args = \func_get_args();
|
||||
$where = array();
|
||||
$options = array();
|
||||
foreach ($args as $o) {
|
||||
$options = \array_merge($options, $o);
|
||||
if (isset($o['where'])) {
|
||||
if (\count($where) === 0) {
|
||||
$where = $o['where'];
|
||||
} else {
|
||||
foreach ($o['where'] as $oc) {
|
||||
$matches = 0;
|
||||
foreach ($where as $wc) {
|
||||
if ($oc == $wc) {
|
||||
$matches += 1;
|
||||
}
|
||||
}
|
||||
if ($matches === 0) {
|
||||
$where[] = $oc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$options['where'] = $where;
|
||||
return $options;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user