This commit is contained in:
2020-02-01 16:47:12 +07:00
commit 4c619ad6e6
16739 changed files with 3329179 additions and 0 deletions

View File

@@ -0,0 +1,208 @@
<?php
/**
* @copyright Copyright (c) 2013-2017 2amigos! Consulting Group LLC
* @link http://2amigos.us
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
*/
namespace dosamigos\arrayquery;
use dosamigos\arrayquery\conditions\Equal;
use dosamigos\arrayquery\conditions\GreaterThan;
use dosamigos\arrayquery\conditions\GreaterThanOrEqual;
use dosamigos\arrayquery\conditions\LessThan;
use dosamigos\arrayquery\conditions\LessThanOrEqual;
use dosamigos\arrayquery\conditions\Like;
use dosamigos\arrayquery\conditions\NotLike;
/**
* ArrayQuery allows to filter an array by apply conditions.
*
* @author Antonio Ramirez <hola@2amigos.us>
* @link http://www.ramirezcobos.com/
* @link http://www.2amigos.us/
* @package dosamigos\arrayquery
*/
class ArrayQuery
{
/**
* @var array the data to search, filter.
*/
private $data;
/**
* @var array the array tokenized so user can search multidimensional array by key paths -ie `parentkey.child`
*/
private $tokens;
/**
* @var array the conditions to apply
*/
private $conditions = [];
/**
* @param array $array
*/
public function __construct(array $array)
{
$this->data = $array;
foreach ($array as $k => $item) {
$this->tokens[$k] = $this->tokenize($item, '', false);
}
}
/**
* Adds a condition to apply the array
*
* @param string $key the key to search in the array
* @param mixed $value the value to search. It supports SQL like operator plus some custom ones:
* - `~` or `like` : like `%value%` in SQL
* - `n~` or `nlike` : like `NOT LIKE` in SQL
* @param string $operator the operator. It can be `and` or `or`. If any of `or` matches it will be added to the
* successful results.
*
* @return static
*/
public function addCondition($key, $value, $operator = 'and')
{
if ($value != null) { // not accepting null values
$operation = null;
$operator = strcasecmp($operator, 'or') !== 0 ? 'and' : 'or';
if (preg_match('/^(?:\s*(<>|<=|>=|<|>|=|~|n~|like|nlike))?(.*)$/i', $value, $matches)) {
$operation = $matches[1];
$value = trim($matches[2]);
}
if (empty($operation) || strlen($operation) > 5) {
$operation = '=';
}
switch ($operation) {
case '<':
$condition = new LessThan($value);
break;
case '>':
$condition = new GreaterThan($value);
break;
case '<>':
$condition = new Equal($value);
$condition->reverse();
break;
case '<=':
$condition = new LessThanOrEqual($value);
break;
case '>=':
$condition = new GreaterThanOrEqual($value);
break;
case '~':
case 'like':
$condition = new Like($value);
break;
case 'n~':
case 'nlike':
$condition = new NotLike($value);
break;
case '=':
default:
$condition = new Equal($value);
}
$this->conditions[$operator][] = ['condition' => $condition, 'key' => $key];
}
return $this;
}
/**
* Returns the first matched result.
* @return array the first matched result, empty array if none found.
*/
public function one()
{
foreach ($this->tokens as $key => $token) {
if (!$this->matches($token)) {
continue;
}
return $this->data[$key];
}
return [];
}
/**
* Returns array of matched results.
* @return array the matched results.
*/
public function find()
{
if (empty($this->conditions)) {
return $this->data;
}
$results = [];
foreach ($this->tokens as $key => $token) {
if (!$this->matches($token)) {
continue;
}
$results[$key] = $this->data[$key];
}
return $results;
}
/**
* Tokenizes the array to ease the search in multidimensional arrays.
*
* @param array $array the array to tokenize
* @param string $prefix the key prefix
* @param bool $addParent whether to add parent value anyway. False
*
* @return array
*/
public function tokenize($array, $prefix = '', $addParent = true)
{
$paths = [];
$px = empty($prefix) ? null : $prefix . ".";
foreach ($array as $key => $items) {
if (is_array($items)) {
$addParent && $paths[$px . $key] = $items;
foreach ($this->tokenize($items, $px . $key) as $k => $path) {
$paths[$k] = $path;
}
} elseif (is_object($items)) {
$addParent && $paths[$px . $key] = $items;
foreach ($this->tokenize(get_object_vars($items), $px . $key) as $k => $path) {
$paths[$k] = $path;
}
} else {
$paths[$px . $key] = $items;
}
}
return $paths;
}
/**
* Checks data against conditions
*
* @param mixed $data the data to match against.
*
* @return bool true if matches condition
*/
private function matches($data)
{
$matches = true;
$conditions = isset($this->conditions['and']) ? $this->conditions['and'] : [];
foreach ($conditions as $condition) {
$key = $condition['key'];
$condition = $condition['condition'];
if (!array_key_exists($key, $data) || !$condition->matches($data[$key])) {
$matches = false;
break;
}
}
$conditions = isset($this->conditions['or']) ? $this->conditions['or'] : [];
foreach ($conditions as $condition) {
$key = $condition['key'];
$condition = $condition['condition'];
if (array_key_exists($key, $data) && $condition->matches($data[$key])) {
$matches = true;
break;
}
}
return $matches;
}
}

View File

@@ -0,0 +1,77 @@
<?php
/**
* @copyright Copyright (c) 2013-2017 2amigOS! Consulting Group LLC
* @link http://2amigos.us
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
*/
namespace dosamigos\arrayquery\conditions;
/**
* Condition abstract base class where all conditions extend from
*
* @author Antonio Ramirez <hola@2amigos.us>
* @link http://www.ramirezcobos.com/
* @link http://www.2amigos.us/
* @package dosamigos\arrayquery\conditions
*/
abstract class Condition
{
/**
* @var mixed the value to match against
*/
protected $value;
/**
* @var bool whether to reverse or not
*/
protected $negate = false;
/**
* @param mixed $value the value to match against
*/
public function __construct($value)
{
$this->value = $value;
}
/**
* Reverses the condition
* @return $this
*/
public function reverse()
{
$this->negate = !$this->negate;
return $this;
}
/**
* Checks whether the value passes condition
*
* @param mixed $data the data to match
*
* @return mixed
*/
abstract public function matches($data);
/**
* Checks whether the value and the data are of same type
*
* @param mixed $value
* @param mixed $against
*
* @return bool true if both are of same type
*/
protected function checkType($value, $against)
{
if (is_numeric($value) && is_numeric($against)) {
$value = filter_var($value, FILTER_SANITIZE_NUMBER_FLOAT);
$against = filter_var($against, FILTER_SANITIZE_NUMBER_FLOAT);
}
if (gettype($value) != gettype($against)) {
return false;
}
return true;
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* @copyright Copyright (c) 2013-2017 2amigOS! Consulting Group LLC
* @link http://2amigos.us
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
*/
namespace dosamigos\arrayquery\conditions;
/**
* Equal checks if value is equal to the data searched.
*
* @author Antonio Ramirez <hola@2amigos.us>
* @link http://www.ramirezcobos.com/
* @link http://www.2amigos.us/
* @package dosamigos\arrayquery\conditions
*/
class Equal extends Condition
{
/**
* @inheritdoc
*/
public function matches($data)
{
return (($this->checkType($data, $this->value) && strcmp($data, $this->value) === 0) xor $this->negate);
}
}

View File

@@ -0,0 +1,38 @@
<?php
/**
* @copyright Copyright (c) 2013-2017 2amigOS! Consulting Group LLC
* @link http://2amigos.us
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
*/
namespace dosamigos\arrayquery\conditions;
/**
* GreaterThan checks if value is greater than the data searched.
*
* @author Antonio Ramirez <hola@2amigos.us>
* @link http://www.ramirezcobos.com/
* @link http://www.2amigos.us/
* @package dosamigos\arrayquery\conditions
*/
class GreaterThan extends Condition
{
/**
* Returns [[LessThan]] condition
* @return LessThan
*/
public function reverse()
{
return new LessThan($this->value);
}
/**
* @inheritdoc
*/
public function matches($data)
{
return ($this->checkType($data, $this->value) && $data > $this->value);
}
}

View File

@@ -0,0 +1,40 @@
<?php
/**
* @copyright Copyright (c) 2013-2017 2amigOS! Consulting Group LLC
* @link http://2amigos.us
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
*/
namespace dosamigos\arrayquery\conditions;
/**
* GreaterThanOrEqual checks if value is greater or equal to the data searched.
*
* @author Antonio Ramirez <hola@2amigos.us>
* @link http://www.ramirezcobos.com/
* @link http://www.2amigos.us/
* @package dosamigos\arrayquery\conditions
*/
class GreaterThanOrEqual extends Condition
{
/**
* Returns [[LessThanOrEqual]] condition
* @return LessThanOrEqual
*/
public function reverse()
{
return new LessThanOrEqual($this->value);
}
/**
* @inheritdoc
*/
public function matches($data)
{
$gt = new GreaterThan($this->value);
$e = new Equal($this->value);
return $gt->matches($data) || $e->matches($data);
}
}

View File

@@ -0,0 +1,39 @@
<?php
/**
* @copyright Copyright (c) 2013-2017 2amigOS! Consulting Group LLC
* @link http://2amigos.us
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
*/
namespace dosamigos\arrayquery\conditions;
/**
* LessThan checks if value is less than to the data searched.
*
* @author Antonio Ramirez <hola@2amigos.us>
* @link http://www.ramirezcobos.com/
* @link http://www.2amigos.us/
* @package dosamigos\arrayquery\conditions
*/
class LessThan extends Condition
{
/**
* Returns [[GreaterThan]] condition
* @return GreaterThan
*/
public function reverse()
{
return new GreaterThan($this->value);
}
/**
* @inheritdoc
*/
public function matches($data)
{
return ($this->checkType($data, $this->value) && $data < $this->value);
}
}

View File

@@ -0,0 +1,41 @@
<?php
/**
* @copyright Copyright (c) 2013-2017 2amigOS! Consulting Group LLC
* @link http://2amigos.us
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
*/
namespace dosamigos\arrayquery\conditions;
/**
* LessThanOrEqual checks if value is less than or equal to the data searched.
*
* @author Antonio Ramirez <hola@2amigos.us>
* @link http://www.ramirezcobos.com/
* @link http://www.2amigos.us/
* @package dosamigos\arrayquery\conditions
*/
class LessThanOrEqual extends Condition
{
/**
* Returns [[GreaterThanOrEqual]] condition
* @return GreaterThanOrEqual
*/
public function reverse()
{
return new GreaterThanOrEqual($this->value);
}
/**
* @inheritdoc
*/
public function matches($data)
{
$gt = new LessThan($this->value);
$e = new Equal($this->value);
return $gt->matches($data) || $e->matches($data);
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* @copyright Copyright (c) 2013-2017 2amigOS! Consulting Group LLC
* @link http://2amigos.us
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
*/
namespace dosamigos\arrayquery\conditions;
/**
* Like checks if value is matches any words in theå data searched.
*
* @author Antonio Ramirez <hola@2amigos.us>
* @link http://www.ramirezcobos.com/
* @link http://www.2amigos.us/
* @package dosamigos\arrayquery\conditions
*/
class Like extends Condition
{
/**
* @inheritdoc
*/
public function matches($data)
{
return is_string($data) && mb_stripos($data, $this->value) !== false;
}
}

View File

@@ -0,0 +1,27 @@
<?php
/**
* @copyright Copyright (c) 2013-2017 2amigOS! Consulting Group LLC
* @link http://2amigos.us
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
*/
namespace dosamigos\arrayquery\conditions;
/**
* NotLike checks if value is not within the data searched.
*
* @author Antonio Ramirez <hola@2amigos.us>
* @link http://www.ramirezcobos.com/
* @link http://www.2amigos.us/
* @package dosamigos\arrayquery\conditions
*/
class NotLike extends Like
{
/**
* @inheritdoc
*/
public function matches($data)
{
return !parent::matches($data);
}
}