first commit
This commit is contained in:
257
vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ClosureExpressionVisitor.php
vendored
Normal file
257
vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ClosureExpressionVisitor.php
vendored
Normal file
@ -0,0 +1,257 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Collections\Expr;
|
||||
|
||||
use ArrayAccess;
|
||||
use Closure;
|
||||
use RuntimeException;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
use function iterator_to_array;
|
||||
use function method_exists;
|
||||
use function preg_match;
|
||||
use function preg_replace_callback;
|
||||
use function strlen;
|
||||
use function strpos;
|
||||
use function strtoupper;
|
||||
use function substr;
|
||||
|
||||
/**
|
||||
* Walks an expression graph and turns it into a PHP closure.
|
||||
*
|
||||
* This closure can be used with {@Collection#filter()} and is used internally
|
||||
* by {@ArrayCollection#select()}.
|
||||
*/
|
||||
class ClosureExpressionVisitor extends ExpressionVisitor
|
||||
{
|
||||
/**
|
||||
* Accesses the field of a given object. This field has to be public
|
||||
* directly or indirectly (through an accessor get*, is*, or a magic
|
||||
* method, __get, __call).
|
||||
*
|
||||
* @param object|array $object
|
||||
* @param string $field
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getObjectFieldValue($object, $field)
|
||||
{
|
||||
if (is_array($object)) {
|
||||
return $object[$field];
|
||||
}
|
||||
|
||||
$accessors = ['get', 'is'];
|
||||
|
||||
foreach ($accessors as $accessor) {
|
||||
$accessor .= $field;
|
||||
|
||||
if (method_exists($object, $accessor)) {
|
||||
return $object->$accessor();
|
||||
}
|
||||
}
|
||||
|
||||
if (preg_match('/^is[A-Z]+/', $field) === 1 && method_exists($object, $field)) {
|
||||
return $object->$field();
|
||||
}
|
||||
|
||||
// __call should be triggered for get.
|
||||
$accessor = $accessors[0] . $field;
|
||||
|
||||
if (method_exists($object, '__call')) {
|
||||
return $object->$accessor();
|
||||
}
|
||||
|
||||
if ($object instanceof ArrayAccess) {
|
||||
return $object[$field];
|
||||
}
|
||||
|
||||
if (isset($object->$field)) {
|
||||
return $object->$field;
|
||||
}
|
||||
|
||||
// camelcase field name to support different variable naming conventions
|
||||
$ccField = preg_replace_callback('/_(.?)/', static function ($matches) {
|
||||
return strtoupper($matches[1]);
|
||||
}, $field);
|
||||
|
||||
foreach ($accessors as $accessor) {
|
||||
$accessor .= $ccField;
|
||||
|
||||
if (method_exists($object, $accessor)) {
|
||||
return $object->$accessor();
|
||||
}
|
||||
}
|
||||
|
||||
return $object->$field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for sorting arrays of objects based on multiple fields + orientations.
|
||||
*
|
||||
* @param string $name
|
||||
* @param int $orientation
|
||||
*
|
||||
* @return Closure
|
||||
*/
|
||||
public static function sortByField($name, $orientation = 1, ?Closure $next = null)
|
||||
{
|
||||
if (! $next) {
|
||||
$next = static function () : int {
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
|
||||
return static function ($a, $b) use ($name, $next, $orientation) : int {
|
||||
$aValue = ClosureExpressionVisitor::getObjectFieldValue($a, $name);
|
||||
|
||||
$bValue = ClosureExpressionVisitor::getObjectFieldValue($b, $name);
|
||||
|
||||
if ($aValue === $bValue) {
|
||||
return $next($a, $b);
|
||||
}
|
||||
|
||||
return ($aValue > $bValue ? 1 : -1) * $orientation;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function walkComparison(Comparison $comparison)
|
||||
{
|
||||
$field = $comparison->getField();
|
||||
$value = $comparison->getValue()->getValue(); // shortcut for walkValue()
|
||||
|
||||
switch ($comparison->getOperator()) {
|
||||
case Comparison::EQ:
|
||||
return static function ($object) use ($field, $value) : bool {
|
||||
return ClosureExpressionVisitor::getObjectFieldValue($object, $field) === $value;
|
||||
};
|
||||
|
||||
case Comparison::NEQ:
|
||||
return static function ($object) use ($field, $value) : bool {
|
||||
return ClosureExpressionVisitor::getObjectFieldValue($object, $field) !== $value;
|
||||
};
|
||||
|
||||
case Comparison::LT:
|
||||
return static function ($object) use ($field, $value) : bool {
|
||||
return ClosureExpressionVisitor::getObjectFieldValue($object, $field) < $value;
|
||||
};
|
||||
|
||||
case Comparison::LTE:
|
||||
return static function ($object) use ($field, $value) : bool {
|
||||
return ClosureExpressionVisitor::getObjectFieldValue($object, $field) <= $value;
|
||||
};
|
||||
|
||||
case Comparison::GT:
|
||||
return static function ($object) use ($field, $value) : bool {
|
||||
return ClosureExpressionVisitor::getObjectFieldValue($object, $field) > $value;
|
||||
};
|
||||
|
||||
case Comparison::GTE:
|
||||
return static function ($object) use ($field, $value) : bool {
|
||||
return ClosureExpressionVisitor::getObjectFieldValue($object, $field) >= $value;
|
||||
};
|
||||
|
||||
case Comparison::IN:
|
||||
return static function ($object) use ($field, $value) : bool {
|
||||
return in_array(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value, true);
|
||||
};
|
||||
|
||||
case Comparison::NIN:
|
||||
return static function ($object) use ($field, $value) : bool {
|
||||
return ! in_array(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value, true);
|
||||
};
|
||||
|
||||
case Comparison::CONTAINS:
|
||||
return static function ($object) use ($field, $value) {
|
||||
return strpos(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value) !== false;
|
||||
};
|
||||
|
||||
case Comparison::MEMBER_OF:
|
||||
return static function ($object) use ($field, $value) : bool {
|
||||
$fieldValues = ClosureExpressionVisitor::getObjectFieldValue($object, $field);
|
||||
|
||||
if (! is_array($fieldValues)) {
|
||||
$fieldValues = iterator_to_array($fieldValues);
|
||||
}
|
||||
|
||||
return in_array($value, $fieldValues, true);
|
||||
};
|
||||
|
||||
case Comparison::STARTS_WITH:
|
||||
return static function ($object) use ($field, $value) : bool {
|
||||
return strpos(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value) === 0;
|
||||
};
|
||||
|
||||
case Comparison::ENDS_WITH:
|
||||
return static function ($object) use ($field, $value) : bool {
|
||||
return $value === substr(ClosureExpressionVisitor::getObjectFieldValue($object, $field), -strlen($value));
|
||||
};
|
||||
|
||||
default:
|
||||
throw new RuntimeException('Unknown comparison operator: ' . $comparison->getOperator());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function walkValue(Value $value)
|
||||
{
|
||||
return $value->getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function walkCompositeExpression(CompositeExpression $expr)
|
||||
{
|
||||
$expressionList = [];
|
||||
|
||||
foreach ($expr->getExpressionList() as $child) {
|
||||
$expressionList[] = $this->dispatch($child);
|
||||
}
|
||||
|
||||
switch ($expr->getType()) {
|
||||
case CompositeExpression::TYPE_AND:
|
||||
return $this->andExpressions($expressionList);
|
||||
case CompositeExpression::TYPE_OR:
|
||||
return $this->orExpressions($expressionList);
|
||||
default:
|
||||
throw new RuntimeException('Unknown composite ' . $expr->getType());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $expressions
|
||||
*/
|
||||
private function andExpressions(array $expressions) : callable
|
||||
{
|
||||
return static function ($object) use ($expressions) : bool {
|
||||
foreach ($expressions as $expression) {
|
||||
if (! $expression($object)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $expressions
|
||||
*/
|
||||
private function orExpressions(array $expressions) : callable
|
||||
{
|
||||
return static function ($object) use ($expressions) : bool {
|
||||
foreach ($expressions as $expression) {
|
||||
if ($expression($object)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
}
|
||||
}
|
80
vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Comparison.php
vendored
Normal file
80
vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Comparison.php
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Collections\Expr;
|
||||
|
||||
/**
|
||||
* Comparison of a field with a value by the given operator.
|
||||
*/
|
||||
class Comparison implements Expression
|
||||
{
|
||||
public const EQ = '=';
|
||||
public const NEQ = '<>';
|
||||
public const LT = '<';
|
||||
public const LTE = '<=';
|
||||
public const GT = '>';
|
||||
public const GTE = '>=';
|
||||
public const IS = '='; // no difference with EQ
|
||||
public const IN = 'IN';
|
||||
public const NIN = 'NIN';
|
||||
public const CONTAINS = 'CONTAINS';
|
||||
public const MEMBER_OF = 'MEMBER_OF';
|
||||
public const STARTS_WITH = 'STARTS_WITH';
|
||||
public const ENDS_WITH = 'ENDS_WITH';
|
||||
|
||||
/** @var string */
|
||||
private $field;
|
||||
|
||||
/** @var string */
|
||||
private $op;
|
||||
|
||||
/** @var Value */
|
||||
private $value;
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
* @param string $operator
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __construct($field, $operator, $value)
|
||||
{
|
||||
if (! ($value instanceof Value)) {
|
||||
$value = new Value($value);
|
||||
}
|
||||
|
||||
$this->field = $field;
|
||||
$this->op = $operator;
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getField()
|
||||
{
|
||||
return $this->field;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Value
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getOperator()
|
||||
{
|
||||
return $this->op;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function visit(ExpressionVisitor $visitor)
|
||||
{
|
||||
return $visitor->walkComparison($this);
|
||||
}
|
||||
}
|
68
vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/CompositeExpression.php
vendored
Normal file
68
vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/CompositeExpression.php
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Collections\Expr;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Expression of Expressions combined by AND or OR operation.
|
||||
*/
|
||||
class CompositeExpression implements Expression
|
||||
{
|
||||
public const TYPE_AND = 'AND';
|
||||
public const TYPE_OR = 'OR';
|
||||
|
||||
/** @var string */
|
||||
private $type;
|
||||
|
||||
/** @var Expression[] */
|
||||
private $expressions = [];
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @param array $expressions
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function __construct($type, array $expressions)
|
||||
{
|
||||
$this->type = $type;
|
||||
|
||||
foreach ($expressions as $expr) {
|
||||
if ($expr instanceof Value) {
|
||||
throw new RuntimeException('Values are not supported expressions as children of and/or expressions.');
|
||||
}
|
||||
if (! ($expr instanceof Expression)) {
|
||||
throw new RuntimeException('No expression given to CompositeExpression.');
|
||||
}
|
||||
|
||||
$this->expressions[] = $expr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of expressions nested in this composite.
|
||||
*
|
||||
* @return Expression[]
|
||||
*/
|
||||
public function getExpressionList()
|
||||
{
|
||||
return $this->expressions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function visit(ExpressionVisitor $visitor)
|
||||
{
|
||||
return $visitor->walkCompositeExpression($this);
|
||||
}
|
||||
}
|
14
vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Expression.php
vendored
Normal file
14
vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Expression.php
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Collections\Expr;
|
||||
|
||||
/**
|
||||
* Expression for the {@link Selectable} interface.
|
||||
*/
|
||||
interface Expression
|
||||
{
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function visit(ExpressionVisitor $visitor);
|
||||
}
|
55
vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ExpressionVisitor.php
vendored
Normal file
55
vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ExpressionVisitor.php
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Collections\Expr;
|
||||
|
||||
use RuntimeException;
|
||||
use function get_class;
|
||||
|
||||
/**
|
||||
* An Expression visitor walks a graph of expressions and turns them into a
|
||||
* query for the underlying implementation.
|
||||
*/
|
||||
abstract class ExpressionVisitor
|
||||
{
|
||||
/**
|
||||
* Converts a comparison expression into the target query language output.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function walkComparison(Comparison $comparison);
|
||||
|
||||
/**
|
||||
* Converts a value expression into the target query language part.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function walkValue(Value $value);
|
||||
|
||||
/**
|
||||
* Converts a composite expression into the target query language output.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function walkCompositeExpression(CompositeExpression $expr);
|
||||
|
||||
/**
|
||||
* Dispatches walking an expression to the appropriate handler.
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function dispatch(Expression $expr)
|
||||
{
|
||||
switch (true) {
|
||||
case $expr instanceof Comparison:
|
||||
return $this->walkComparison($expr);
|
||||
case $expr instanceof Value:
|
||||
return $this->walkValue($expr);
|
||||
case $expr instanceof CompositeExpression:
|
||||
return $this->walkCompositeExpression($expr);
|
||||
default:
|
||||
throw new RuntimeException('Unknown Expression ' . get_class($expr));
|
||||
}
|
||||
}
|
||||
}
|
33
vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Value.php
vendored
Normal file
33
vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Value.php
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Common\Collections\Expr;
|
||||
|
||||
class Value implements Expression
|
||||
{
|
||||
/** @var mixed */
|
||||
private $value;
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __construct($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function visit(ExpressionVisitor $visitor)
|
||||
{
|
||||
return $visitor->walkValue($this);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user