From bf6655a534a6775d30cafa67bd801276bda1d98d Mon Sep 17 00:00:00 2001 From: polo Date: Tue, 13 Aug 2024 23:45:21 +0200 Subject: =?UTF-8?q?VERSION=200.2=20doctrine=20ORM=20et=20entit=C3=A9s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Expr/ClosureExpressionVisitor.php | 222 +++++++++++++++++++++ .../doctrine/collections/src/Expr/Comparison.php | 62 ++++++ .../collections/src/Expr/CompositeExpression.php | 70 +++++++ .../doctrine/collections/src/Expr/Expression.php | 14 ++ .../collections/src/Expr/ExpressionVisitor.php | 52 +++++ vendor/doctrine/collections/src/Expr/Value.php | 26 +++ 6 files changed, 446 insertions(+) create mode 100644 vendor/doctrine/collections/src/Expr/ClosureExpressionVisitor.php create mode 100644 vendor/doctrine/collections/src/Expr/Comparison.php create mode 100644 vendor/doctrine/collections/src/Expr/CompositeExpression.php create mode 100644 vendor/doctrine/collections/src/Expr/Expression.php create mode 100644 vendor/doctrine/collections/src/Expr/ExpressionVisitor.php create mode 100644 vendor/doctrine/collections/src/Expr/Value.php (limited to 'vendor/doctrine/collections/src/Expr') diff --git a/vendor/doctrine/collections/src/Expr/ClosureExpressionVisitor.php b/vendor/doctrine/collections/src/Expr/ClosureExpressionVisitor.php new file mode 100644 index 0000000..4319b9b --- /dev/null +++ b/vendor/doctrine/collections/src/Expr/ClosureExpressionVisitor.php @@ -0,0 +1,222 @@ +$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 fn ($matches) => strtoupper((string) $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. + * + * @return Closure + */ + public static function sortByField(string $name, int $orientation = 1, Closure|null $next = null) + { + if (! $next) { + $next = static fn (): int => 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(); + + return match ($comparison->getOperator()) { + Comparison::EQ => static fn ($object): bool => self::getObjectFieldValue($object, $field) === $value, + Comparison::NEQ => static fn ($object): bool => self::getObjectFieldValue($object, $field) !== $value, + Comparison::LT => static fn ($object): bool => self::getObjectFieldValue($object, $field) < $value, + Comparison::LTE => static fn ($object): bool => self::getObjectFieldValue($object, $field) <= $value, + Comparison::GT => static fn ($object): bool => self::getObjectFieldValue($object, $field) > $value, + Comparison::GTE => static fn ($object): bool => self::getObjectFieldValue($object, $field) >= $value, + Comparison::IN => static function ($object) use ($field, $value): bool { + $fieldValue = ClosureExpressionVisitor::getObjectFieldValue($object, $field); + + return in_array($fieldValue, $value, is_scalar($fieldValue)); + }, + Comparison::NIN => static function ($object) use ($field, $value): bool { + $fieldValue = ClosureExpressionVisitor::getObjectFieldValue($object, $field); + + return ! in_array($fieldValue, $value, is_scalar($fieldValue)); + }, + Comparison::CONTAINS => static fn ($object): bool => str_contains((string) self::getObjectFieldValue($object, $field), (string) $value), + Comparison::MEMBER_OF => 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); + }, + Comparison::STARTS_WITH => static fn ($object): bool => str_starts_with((string) self::getObjectFieldValue($object, $field), (string) $value), + Comparison::ENDS_WITH => static fn ($object): bool => str_ends_with((string) self::getObjectFieldValue($object, $field), (string) $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); + } + + return match ($expr->getType()) { + CompositeExpression::TYPE_AND => $this->andExpressions($expressionList), + CompositeExpression::TYPE_OR => $this->orExpressions($expressionList), + CompositeExpression::TYPE_NOT => $this->notExpression($expressionList), + default => throw new RuntimeException('Unknown composite ' . $expr->getType()), + }; + } + + /** @param callable[] $expressions */ + private function andExpressions(array $expressions): Closure + { + return static function ($object) use ($expressions): bool { + foreach ($expressions as $expression) { + if (! $expression($object)) { + return false; + } + } + + return true; + }; + } + + /** @param callable[] $expressions */ + private function orExpressions(array $expressions): Closure + { + return static function ($object) use ($expressions): bool { + foreach ($expressions as $expression) { + if ($expression($object)) { + return true; + } + } + + return false; + }; + } + + /** @param callable[] $expressions */ + private function notExpression(array $expressions): Closure + { + return static fn ($object) => ! $expressions[0]($object); + } +} diff --git a/vendor/doctrine/collections/src/Expr/Comparison.php b/vendor/doctrine/collections/src/Expr/Comparison.php new file mode 100644 index 0000000..f1ea07f --- /dev/null +++ b/vendor/doctrine/collections/src/Expr/Comparison.php @@ -0,0 +1,62 @@ +'; + final public const LT = '<'; + final public const LTE = '<='; + final public const GT = '>'; + final public const GTE = '>='; + final public const IS = '='; // no difference with EQ + final public const IN = 'IN'; + final public const NIN = 'NIN'; + final public const CONTAINS = 'CONTAINS'; + final public const MEMBER_OF = 'MEMBER_OF'; + final public const STARTS_WITH = 'STARTS_WITH'; + final public const ENDS_WITH = 'ENDS_WITH'; + + private readonly Value $value; + + public function __construct(private readonly string $field, private readonly string $op, mixed $value) + { + if (! ($value instanceof Value)) { + $value = new Value($value); + } + + $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); + } +} diff --git a/vendor/doctrine/collections/src/Expr/CompositeExpression.php b/vendor/doctrine/collections/src/Expr/CompositeExpression.php new file mode 100644 index 0000000..b7b4544 --- /dev/null +++ b/vendor/doctrine/collections/src/Expr/CompositeExpression.php @@ -0,0 +1,70 @@ + */ + private array $expressions = []; + + /** + * @param Expression[] $expressions + * + * @throws RuntimeException + */ + public function __construct(private readonly string $type, array $expressions) + { + 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; + } + + if ($type === self::TYPE_NOT && count($this->expressions) !== 1) { + throw new RuntimeException('Not expression only allows one expression as child.'); + } + } + + /** + * Returns the list of expressions nested in this composite. + * + * @return list + */ + public function getExpressionList() + { + return $this->expressions; + } + + /** @return string */ + public function getType() + { + return $this->type; + } + + /** + * {@inheritDoc} + */ + public function visit(ExpressionVisitor $visitor) + { + return $visitor->walkCompositeExpression($this); + } +} diff --git a/vendor/doctrine/collections/src/Expr/Expression.php b/vendor/doctrine/collections/src/Expr/Expression.php new file mode 100644 index 0000000..70ad45f --- /dev/null +++ b/vendor/doctrine/collections/src/Expr/Expression.php @@ -0,0 +1,14 @@ + $this->walkComparison($expr), + $expr instanceof Value => $this->walkValue($expr), + $expr instanceof CompositeExpression => $this->walkCompositeExpression($expr), + default => throw new RuntimeException('Unknown Expression ' . $expr::class), + }; + } +} diff --git a/vendor/doctrine/collections/src/Expr/Value.php b/vendor/doctrine/collections/src/Expr/Value.php new file mode 100644 index 0000000..776770d --- /dev/null +++ b/vendor/doctrine/collections/src/Expr/Value.php @@ -0,0 +1,26 @@ +value; + } + + /** + * {@inheritDoc} + */ + public function visit(ExpressionVisitor $visitor) + { + return $visitor->walkValue($this); + } +} -- cgit v1.2.3