-
-
Notifications
You must be signed in to change notification settings - Fork 61
Description
It would be nice to call Collection Functions directly in property string if applicable.
Instead of doing:
$authors->findBy([CountAggregateFunction::class, 'books->id', 2]),
I would like to do:
$authors->findBy(['books->id:count' => 2]).
Or even instead of:
$authors->findBy([CompareGreaterThanFunction::class, [CountAggregateFunction::class, 'books->id'], 2]),
just call:
$authors->findBy(['books->id:count>' => 2]).
For filtering, this is actually easily achievable outside of library with custom ConditionParser:
class CustomConditionParser extends ConditionParser
{
public function parsePropertyOperator(string $condition): array
{
// language=PhpRegExp
$regexp = '#^(?P<path>' . self::PATH_REGEXP . ')(:(?P<function>\w+))?(?P<operator>!=|<=|>=|=|>|<|~)?$#';
if (preg_match($regexp, $condition, $matches) !== 1) {
return [CompareEqualsFunction::class, $condition];
}
$operator = $matches['operator'] ?? '=';
$function = $matches['function'] ?? null;
$condition = $this->parsePropertyFunction($condition);
# TODO detect if custom function expects operator for comparison
return match ($operator) {
'=' => [CompareEqualsFunction::class, $condition],
'!=' => [CompareNotEqualsFunction::class, $condition],
'>=' => [CompareGreaterThanEqualsFunction::class, $condition],
'>' => [CompareGreaterThanFunction::class, $condition],
'<=' => [CompareSmallerThanEqualsFunction::class, $condition],
'<' => [CompareSmallerThanFunction::class, $condition],
'~' => [CompareLikeFunction::class, $condition],
default => throw new InvalidStateException,
};
}
public function parsePropertyFunction(string $propertyPath): array|string
{
// language=PhpRegExp
$regexp = '#^(?P<path>' . self::PATH_REGEXP . ')(:(?P<function>\w+))?(?P<operator>!=|<=|>=|=|>|<|~)?$#';
if (preg_match($regexp, $propertyPath, $matches) !== 1) {
throw new InvalidArgumentException('Unsupported condition format.');
}
$path = $matches['path'];
$function = $matches['function'] ?? null;
return $function ? match ($function) {
'avg' => [AvgAggregateFunction::class, $path],
'count' => [CountAggregateFunction::class, $path],
'max' => [MaxAggregateFunction::class, $path],
'min' => [MinAggregateFunction::class, $path],
'sum' => [SumAggregateFunction::class, $path],
default => [$function, $path],
} : $path;
}
}For sorting, I did not find a way to allow this without altering library:
$authors->orderBy('books->id:count').
If this is not planned to be part of the library, I would at least like sorting in Collection to make use of ConditionParser, somehow like this:
public function orderBy($expression, string $direction = ICollection::ASC): ICollection
{
$expression = $this->normalizeExpression($expression);
...
}
private function normalizeExpression(array|string $expression): array|string
{
$parser = $this->mapper->getRepository()->getConditionParser();
if (is_string($expression)) {
return $parser->parsePropertyFunction($expression);
# TODO support operator in sorting
}
if (isset($expression[0])) {
return $expression;
}
$normalizedExpression = [];
# TODO parse array expression
return $normalizedExpression;
}