Skip to content

Commit

Permalink
FEATURE: Add PropertyValueCriteriaMatcher
Browse files Browse the repository at this point in the history
The property value criteria matcher accepts a ``PropertyValueCriteriaInterface`` and
provides static methods to check wether a ``Node`` or a ``PropertyCollection`` matches those criteria.
  • Loading branch information
mficzel committed Feb 16, 2024
1 parent 783e08a commit 5f2db40
Show file tree
Hide file tree
Showing 3 changed files with 458 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ public function splitByScope(NodeType $nodeType): array
);
}

/**
* @phpstan-assert-if-true !null $this->getProperty()
*/
public function propertyExists(string $propertyName): bool
{
return isset($this->values[$propertyName]);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<?php

declare(strict_types=1);

namespace Neos\ContentRepository\Core\Projection\ContentGraph\Filter\PropertyValue;

use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\PropertyValue\Criteria\AndCriteria;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\PropertyValue\Criteria\NegateCriteria;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\PropertyValue\Criteria\OrCriteria;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\PropertyValue\Criteria\PropertyValueContains;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\PropertyValue\Criteria\PropertyValueCriteriaInterface;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\PropertyValue\Criteria\PropertyValueEndsWith;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\PropertyValue\Criteria\PropertyValueEquals;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\PropertyValue\Criteria\PropertyValueGreaterThan;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\PropertyValue\Criteria\PropertyValueGreaterThanOrEqual;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\PropertyValue\Criteria\PropertyValueLessThan;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\PropertyValue\Criteria\PropertyValueLessThanOrEqual;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\PropertyValue\Criteria\PropertyValueStartsWith;
use Neos\ContentRepository\Core\Projection\ContentGraph\Node;
use Neos\ContentRepository\Core\Projection\ContentGraph\PropertyCollection;

/**
* Performs property checks against a given set of constraints
*
* @internal
*/
final class PropertyValueCriteriaMatcher
{
public static function matchesPropertyCollection(PropertyCollection $propertyCollection, PropertyValueCriteriaInterface $propertyValueCriteria): bool
{
switch (true) {
case $propertyValueCriteria instanceof AndCriteria:
return self::matchesPropertyCollection($propertyCollection, $propertyValueCriteria->criteria1) && self::matchesPropertyCollection($propertyCollection, $propertyValueCriteria->criteria2);
case $propertyValueCriteria instanceof OrCriteria:
return self::matchesPropertyCollection($propertyCollection, $propertyValueCriteria->criteria1) || self::matchesPropertyCollection($propertyCollection, $propertyValueCriteria->criteria2);
case $propertyValueCriteria instanceof NegateCriteria:
return !self::matchesPropertyCollection($propertyCollection, $propertyValueCriteria->criteria);
case $propertyValueCriteria instanceof PropertyValueContains:
$propertyValue = $propertyCollection->serialized()->getProperty($propertyValueCriteria->propertyName->value)?->value;
if ($propertyValueCriteria->caseSensitive) {
return is_string($propertyValue)
? str_contains($propertyValue, $propertyValueCriteria->value)
: false;
} else {
return is_string($propertyValue)
? str_contains(mb_strtolower($propertyValue), mb_strtolower($propertyValueCriteria->value))
: false;
}
case $propertyValueCriteria instanceof PropertyValueEndsWith:
$propertyValue = $propertyCollection->serialized()->getProperty($propertyValueCriteria->propertyName->value)?->value;
if ($propertyValueCriteria->caseSensitive) {
return is_string($propertyValue)
? str_ends_with($propertyValue, $propertyValueCriteria->value)
: false;
} else {
return is_string($propertyValue)
? str_ends_with(mb_strtolower($propertyValue), mb_strtolower($propertyValueCriteria->value))
: false;
}
case $propertyValueCriteria instanceof PropertyValueStartsWith:
$propertyValue = $propertyCollection->serialized()->getProperty($propertyValueCriteria->propertyName->value)?->value;
if ($propertyValueCriteria->caseSensitive) {
return is_string($propertyValue)
? str_starts_with($propertyValue, $propertyValueCriteria->value)
: false;
} else {
return is_string($propertyValue)
? str_starts_with(mb_strtolower($propertyValue), mb_strtolower($propertyValueCriteria->value))
: false;
}
case $propertyValueCriteria instanceof PropertyValueEquals:
if (!$propertyCollection->serialized()->propertyExists($propertyValueCriteria->propertyName->value)) {
return false;
} elseif ($propertyValueCriteria->caseSensitive) {
return $propertyCollection->serialized()->getProperty($propertyValueCriteria->propertyName->value)?->value == $propertyValueCriteria->value;
} else {
return mb_strtolower($propertyCollection->serialized()->getProperty($propertyValueCriteria->propertyName->value)?->value) == mb_strtolower($propertyValueCriteria->value);

Check failure on line 77 in Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Filter/PropertyValue/PropertyValueCriteriaMatcher.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 Test linting-unit-functionaltests-mysql (deps: highest)

Parameter #1 $string of function mb_strtolower expects string, array<int|string, mixed>|ArrayObject<int|string, mixed>|bool|float|int|string|null given.

Check failure on line 77 in Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Filter/PropertyValue/PropertyValueCriteriaMatcher.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 Test linting-unit-functionaltests-mysql (deps: highest)

Parameter #1 $string of function mb_strtolower expects string, bool|float|int|string given.

Check failure on line 77 in Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Filter/PropertyValue/PropertyValueCriteriaMatcher.php

View workflow job for this annotation

GitHub Actions / PHP 8.3 Test linting-unit-functionaltests-mysql (deps: highest)

Parameter #1 $string of function mb_strtolower expects string, array<int|string, mixed>|ArrayObject<int|string, mixed>|bool|float|int|string|null given.

Check failure on line 77 in Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Filter/PropertyValue/PropertyValueCriteriaMatcher.php

View workflow job for this annotation

GitHub Actions / PHP 8.3 Test linting-unit-functionaltests-mysql (deps: highest)

Parameter #1 $string of function mb_strtolower expects string, bool|float|int|string given.
}
case $propertyValueCriteria instanceof PropertyValueGreaterThan:
return $propertyCollection->serialized()->propertyExists($propertyValueCriteria->propertyName->value)
&& $propertyCollection->serialized()->getProperty($propertyValueCriteria->propertyName->value)?->value > $propertyValueCriteria->value;
case $propertyValueCriteria instanceof PropertyValueGreaterThanOrEqual:
return $propertyCollection->serialized()->propertyExists($propertyValueCriteria->propertyName->value)
&& $propertyCollection->serialized()->getProperty($propertyValueCriteria->propertyName->value)?->value >= $propertyValueCriteria->value;
case $propertyValueCriteria instanceof PropertyValueLessThan:
return $propertyCollection->serialized()->propertyExists($propertyValueCriteria->propertyName->value)
&& $propertyCollection->serialized()->getProperty($propertyValueCriteria->propertyName->value)?->value < $propertyValueCriteria->value;
case $propertyValueCriteria instanceof PropertyValueLessThanOrEqual:
return $propertyCollection->serialized()->propertyExists($propertyValueCriteria->propertyName->value)
&& $propertyCollection->serialized()->getProperty($propertyValueCriteria->propertyName->value)?->value <= $propertyValueCriteria->value;
default:
throw new \InvalidArgumentException(sprintf('Invalid/unsupported property value criteria "%s"', get_debug_type($propertyValueCriteria)), 1679561073);
}
}

public static function matchesNode(Node $node, PropertyValueCriteriaInterface $propertyValueCriteria): bool
{
return static::matchesPropertyCollection($node->properties, $propertyValueCriteria);
}
}
Loading

0 comments on commit 5f2db40

Please sign in to comment.