You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+45-1Lines changed: 45 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -34,7 +34,7 @@ There is nothing else to do. No service provider to register, no config to publi
34
34
35
35
`LikeOperator::applyContains()` adds a wildcard safe `LIKE` (or `ILIKE` on PostgreSQL) clause to a query.
36
36
37
-
`applyContains()` and `applyContainsOnDate()` type hint `Illuminate\Database\Eloquent\Builder`. They can be called on an Eloquent builder, and inside a closure that Laravel hands one, such as the closure passed to `Eloquent\Builder::where()`. They cannot be called on a plain `Illuminate\Database\Query\Builder`, or inside a closure that receives one (for example the closure passed to `orWhereIn()`, `whereExists()` or `Query\Builder::from()`). Accepting both builder types is a known limitation, deferred to a later release.
37
+
`applyContains()`, its OR and negated variants, and `applyContainsOnDate()` type hint `Illuminate\Database\Eloquent\Builder`. They can be called on an Eloquent builder, and inside a closure that Laravel hands one, such as the closure passed to `Eloquent\Builder::where()`. They cannot be called on a plain `Illuminate\Database\Query\Builder`, or inside a closure that receives one (for example the closure passed to `orWhereIn()`, `whereExists()` or `Query\Builder::from()`). Accepting both builder types is a known limitation, deferred to a later release.
38
38
39
39
```php
40
40
use Illuminate\Database\Eloquent\Builder;
@@ -49,6 +49,50 @@ Movie::query()
49
49
50
50
`applyContains()` wraps the column through the query's grammar, picks the operator with `LikeOperator::for()`, builds the pattern with `LikeOperator::containsPattern()` and issues one `whereRaw()` call with the correct `ESCAPE` clause for the driver. `applyContainsOnDate()` does the same thing but first casts the date column to text in the right dialect (`::text` on PostgreSQL, `CAST(... AS CHAR)` on MySQL and MariaDB, `CAST(... AS TEXT)` elsewhere), for matching a partial date, month or year that is displayed rather than compared.
51
51
52
+
### OR and negated variants
53
+
54
+
`applyContains()` accepts two optional arguments that mirror Laravel's own `whereLike()`: `$boolean` (`'and'` by default, or `'or'`) and `$not` (`false` by default). `applyContainsOnDate()` accepts the same two. For readability `applyContains()` also has three named shortcuts:
55
+
56
+
| Method | Clause added |
57
+
| --- | --- |
58
+
|`applyContains($query, $column, $term)`|`and <column> LIKE ?`|
59
+
|`orApplyContains($query, $column, $term)`|`or <column> LIKE ?`|
60
+
|`applyNotContains($query, $column, $term)`|`and <column> NOT LIKE ?`|
61
+
|`orApplyNotContains($query, $column, $term)`|`or <column> NOT LIKE ?`|
62
+
63
+
On PostgreSQL the operator is `ILIKE` or `NOT ILIKE`. Escaping and the `ESCAPE` clause are identical in all four. Any `$boolean` other than `'and'` or `'or'` (case insensitive) throws an `InvalidArgumentException`.
64
+
65
+
An OR clause joins whatever came before it in the same `where` group, so wrap OR clauses in a closure to keep them from leaking into the rest of the query:
66
+
67
+
```php
68
+
use Illuminate\Database\Eloquent\Builder;
69
+
use PlinCode\SqlDialect\LikeOperator;
70
+
71
+
Job::query()
72
+
->where(function (Builder $query) use ($keywords) {
`NULL` follows SQL's three valued logic and the package does not change it. `NULL LIKE '%x%'` and `NULL NOT LIKE '%x%'` both evaluate to `NULL`, so a row whose column is `NULL` is left out by the negated variants as well as by the positive ones. When those rows should be kept, add the null check yourself:
`containsPattern()` (and the `escapeWildcards()` it calls) neutralise `%`, `_` and `\` in the search term with `addcslashes()`, so a term containing those characters is matched literally instead of being interpreted as a wildcard. That is why `applyContains()` always appends an `ESCAPE` clause: it tells the driver which character in the pattern is the escape character it just used.
53
97
54
98
`$column` is interpolated straight into the raw SQL through the connection's grammar and must be a column name your own code supplies, never request input; `$term`, the search value, is always passed as a bound parameter. `Grammar::wrap()` quotes identifiers, it does not validate or escape arbitrary strings, so it is not a safeguard against passing user input as `$column`.
0 commit comments