diff --git a/docs/en/expression-builder.rst b/docs/en/expression-builder.rst index e0224418..2b076cd5 100644 --- a/docs/en/expression-builder.rst +++ b/docs/en/expression-builder.rst @@ -154,6 +154,16 @@ contains $collection->matching(new Criteria($expression)); +notContains +-------- + +.. code-block:: php + $expressionBuilder = Criteria::expr(); + + $expression = $expressionBuilder->notContains('foo', 'value1'); + + $collection->matching(new Criteria($expression)); + memberOf -------- diff --git a/docs/en/expressions.rst b/docs/en/expressions.rst index ef431bd3..aa7c671c 100644 --- a/docs/en/expressions.rst +++ b/docs/en/expressions.rst @@ -16,6 +16,7 @@ following operator constants: - ``Comparison::IN`` - ``Comparison::NIN`` - ``Comparison::CONTAINS`` +- ``Comparison::NCONTAINS`` - ``Comparison::MEMBER_OF`` - ``Comparison::STARTS_WITH`` - ``Comparison::ENDS_WITH`` diff --git a/src/Expr/ClosureExpressionVisitor.php b/src/Expr/ClosureExpressionVisitor.php index 4319b9b5..f319601d 100644 --- a/src/Expr/ClosureExpressionVisitor.php +++ b/src/Expr/ClosureExpressionVisitor.php @@ -144,6 +144,7 @@ public function walkComparison(Comparison $comparison) return ! in_array($fieldValue, $value, is_scalar($fieldValue)); }, Comparison::CONTAINS => static fn ($object): bool => str_contains((string) self::getObjectFieldValue($object, $field), (string) $value), + Comparison::NCONTAINS => 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); diff --git a/src/Expr/Comparison.php b/src/Expr/Comparison.php index f1ea07fa..b62cc60a 100644 --- a/src/Expr/Comparison.php +++ b/src/Expr/Comparison.php @@ -19,6 +19,7 @@ class Comparison implements Expression final public const IN = 'IN'; final public const NIN = 'NIN'; final public const CONTAINS = 'CONTAINS'; + final public const NCONTAINS = 'NCONTAINS'; final public const MEMBER_OF = 'MEMBER_OF'; final public const STARTS_WITH = 'STARTS_WITH'; final public const ENDS_WITH = 'ENDS_WITH'; diff --git a/src/ExpressionBuilder.php b/src/ExpressionBuilder.php index fc25e3a9..248f7de4 100644 --- a/src/ExpressionBuilder.php +++ b/src/ExpressionBuilder.php @@ -103,6 +103,12 @@ public function contains(string $field, mixed $value) return new Comparison($field, Comparison::CONTAINS, new Value($value)); } + /** @return Comparison */ + public function notContains(string $field, mixed $value) + { + return new Comparison($field, Comparison::NCONTAINS, new Value($value)); + } + /** @return Comparison */ public function memberOf(string $field, mixed $value) { diff --git a/tests/Common/Collections/ExpressionBuilderTest.php b/tests/Common/Collections/ExpressionBuilderTest.php index cfba7626..79773ae3 100644 --- a/tests/Common/Collections/ExpressionBuilderTest.php +++ b/tests/Common/Collections/ExpressionBuilderTest.php @@ -122,6 +122,14 @@ public function testContains(): void self::assertEquals(Comparison::CONTAINS, $expr->getOperator()); } + public function testNotContains(): void + { + $expr = $this->builder->notContains('a', 'b'); + + self::assertInstanceOf(Comparison::class, $expr); + self::assertEquals(Comparison::NCONTAINS, $expr->getOperator()); + } + public function testMemberOf(): void { $expr = $this->builder->memberOf('b', ['a']);