Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/collection-filtering.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ Filtering over virtual properties is generally unsupported and provides undefine

#### LIKE filtering

`LIKE` filtering is supported and directly provided in Nextras Orm. Use the `~` comparison operator. The value must be wrapped as a `Nextras\Orm\Collection\Expression\LikeExpression` instance; use its static builders to create one: choose from `startsWith`, `endsWith`, or `contains`. Alternatively, you may provide your wildcard expression with the `raw` method. Be aware that the `raw` method expects sanitized input.
`LIKE` filtering is supported and directly provided in Nextras Orm. Use the `~` comparison operator. The value must be wrapped as a `Nextras\Orm\Collection\Expression\LikeExpression` instance; use its static builders to create one: choose from `startsWith`, `endsWith`, `contains` or `notContains`. Alternatively, you may provide your wildcard expression with the `raw` method. Be aware that the `raw` method expects sanitized input.

```php
// finds all users with email hosted on gmail.com
Expand Down
10 changes: 10 additions & 0 deletions src/Collection/Expression/LikeExpression.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,21 @@ public static function contains(string $input): LikeExpression
return new self($input, self::MODE_CONTAINS);
}

/**
* Wraps input as not contains filter (i.e. string may start and end 0-n other characters).
* Special LIKE characters are sanitized.
*/
public static function notContains(string $input): LikeExpression
{
return new self($input, self::MODE_NOT_CONTAINS);
}


public const MODE_RAW = 0;
public const MODE_STARTS_WITH = 1;
public const MODE_ENDS_WITH = 2;
public const MODE_CONTAINS = 3;
public const MODE_NOT_CONTAINS = 4;


private function __construct(
Expand Down
6 changes: 6 additions & 0 deletions src/Collection/Functions/CompareLikeFunction.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ protected function evaluateInPhp(int $mode, $sourceValue, $targetValue): bool
$regexp = '~^.*' . preg_quote($targetValue, '~') . '.*$~';
return Strings::match($sourceValue, $regexp) !== null;

} elseif ($mode === LikeExpression::MODE_NOT_CONTAINS) {
$regexp = '~^.*' . preg_quote($targetValue, '~') . '.*$~';
return Strings::match($sourceValue, $regexp) === null;

} else {
throw new InvalidStateException();
}
Expand All @@ -126,6 +130,8 @@ protected function evaluateInDb(int $mode, DbalExpressionResult $expression, $va
return $expression->append('LIKE %_like', $value);
} elseif ($mode === LikeExpression::MODE_CONTAINS) {
return $expression->append('LIKE %_like_', $value);
} elseif ($mode === LikeExpression::MODE_NOT_CONTAINS) {
return $expression->append('NOT LIKE %_like_', $value);
} else {
throw new InvalidStateException();
}
Expand Down
7 changes: 7 additions & 0 deletions tests/cases/integration/Collection/collection.like.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@ class CollectionLikeTest extends DataTestCase

$count = $this->orm->books->findBy(['title~' => LikeExpression::contains('ook X')])->count();
Assert::same(0, $count);


$count = $this->orm->books->findBy(['title~' => LikeExpression::notContains('ABC')])->count();
Assert::same(4, $count);

$count = $this->orm->books->findBy(['title~' => LikeExpression::notContains('Book')])->count();
Assert::same(0, $count);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ SELECT "books".* FROM "books" AS "books" WHERE "books"."title" LIKE '%ook X';
SELECT "books".* FROM "books" AS "books" WHERE "books"."title" LIKE '%ook%';
SELECT "books".* FROM "books" AS "books" WHERE "books"."title" LIKE '%ook 1%';
SELECT "books".* FROM "books" AS "books" WHERE "books"."title" LIKE '%ook X%';
SELECT "books".* FROM "books" AS "books" WHERE "books"."title" NOT LIKE '%ABC%';
SELECT "books".* FROM "books" AS "books" WHERE "books"."title" NOT LIKE '%Book%';