Skip to content

Commit a1ab5b6

Browse files
committed
filters rework
1 parent 478dd96 commit a1ab5b6

File tree

5 files changed

+67
-63
lines changed

5 files changed

+67
-63
lines changed

src/Fields/Field.php

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,9 @@ abstract class Field implements Arrayable, JsonSerializable
116116
protected bool|Closure $searchable = false;
117117

118118
/**
119-
* The search query resolver callback.
119+
* The filter query resolver callback.
120120
*/
121-
protected ?Closure $searchQueryResolver = null;
121+
protected ?Closure $filterQueryResolver = null;
122122

123123
/**
124124
* Determine if the field is computed.
@@ -313,35 +313,27 @@ public function isSortable(): bool
313313
/**
314314
* Set the searchable attribute.
315315
*/
316-
public function searchable(bool|Closure $value = true): static
316+
public function searchable(bool|Closure $value = true, ?Closure $callback = null): static
317317
{
318-
$this->searchable = $value;
318+
$callback ??= function (Request $request, Builder $query, mixed $value, string $attribute): Builder {
319+
return $query->where($query->qualifyColumn($attribute), 'like', "%{$value}%", 'or');
320+
};
319321

320-
return $this;
322+
return $this->filterable($callback, $value);
321323
}
322324

323325
/**
324326
* Determine if the field is searchable.
325327
*/
326328
public function isSearchable(): bool
327329
{
328-
if ($this->computed) {
330+
if (! $this->isFilterable()) {
329331
return false;
330332
}
331333

332334
return $this->searchable instanceof Closure ? call_user_func($this->searchable) : $this->searchable;
333335
}
334336

335-
/**
336-
* Set the search query resolver.
337-
*/
338-
public function searchWithQuery(Closure $callback): static
339-
{
340-
$this->searchQueryResolver = $callback;
341-
342-
return $this;
343-
}
344-
345337
/**
346338
* Set the translatable attribute.
347339
*/
@@ -365,13 +357,35 @@ public function isTranslatable(): bool
365357
}
366358

367359
/**
368-
* Resolve the search query.
360+
* Set the filterable attribute.
361+
*/
362+
public function filterable(?Closure $callback = null, bool|Closure $search = false): static
363+
{
364+
$this->searchable = $search;
365+
366+
$this->filterQueryResolver = $callback ?: function (Request $request, Builder $query, mixed $value, string $attribute): Builder {
367+
return $query->where($query->qualifyColumn($attribute), $value);
368+
};
369+
370+
return $this;
371+
}
372+
373+
/**
374+
* Determine whether the field is filterable.
375+
*/
376+
public function isFilterable(): bool
377+
{
378+
return ! $this->computed && $this->filterQueryResolver instanceof Closure;
379+
}
380+
381+
/**
382+
* Resolve the filter query.
369383
*/
370-
public function resolveSearchQuery(Request $request, Builder $query, mixed $value): Builder
384+
public function resolveFilterQuery(Request $request, Builder $query, mixed $value): Builder
371385
{
372-
return is_null($this->searchQueryResolver)
373-
? $query
374-
: call_user_func_array($this->searchQueryResolver, [$request, $query, $value]);
386+
return $this->isFilterable()
387+
? call_user_func_array($this->filterQueryResolver, [$request, $query, $value, $this->getModelAttribute()])
388+
: $query;
375389
}
376390

377391
/**

src/Fields/Relation.php

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -251,11 +251,26 @@ public function isNullable(): bool
251251
/**
252252
* {@inheritdoc}
253253
*/
254-
public function searchable(bool|Closure $value = true, array $columns = ['id']): static
254+
public function searchable(bool|Closure $value = true, ?Closure $callback = null, array $columns = ['id']): static
255255
{
256256
$this->searchableColumns = $columns;
257257

258-
return parent::searchable($value);
258+
$callback ??= function (Request $request, Builder $query, mixed $value, array $attributes): Builder {
259+
return $query->has($this->getModelAttribute(), '>=', 1, 'or', static function (Builder $query) use ($attributes, $value): Builder {
260+
foreach ($attributes as $attribute) {
261+
$query->where(
262+
$query->qualifyColumn($attribute),
263+
'like',
264+
"%{$value}%",
265+
$attributes[0] === $attribute ? 'and' : 'or'
266+
);
267+
}
268+
269+
return $query;
270+
});
271+
};
272+
273+
return parent::searchable($value, $callback);
259274
}
260275

261276
/**
@@ -267,15 +282,17 @@ public function getSearchableColumns(): array
267282
}
268283

269284
/**
270-
* {@inheritdoc}
285+
* Resolve the filter query.
271286
*/
272-
public function isSearchable(): bool
287+
public function resolveFilterQuery(Request $request, Builder $query, mixed $value): Builder
273288
{
274-
if ($this->isSubResource()) {
275-
return false;
289+
if (! $this->isFilterable()) {
290+
return parent::resolveFilterQuery($request, $query, $value);
276291
}
277292

278-
return parent::isSearchable();
293+
return call_user_func_array($this->filterQueryResolver, [
294+
$request, $query, $value, $this->getSearchableColumns(),
295+
]);
279296
}
280297

281298
/**

src/Filters/Search.php

Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
use Cone\Root\Fields\Field;
66
use Cone\Root\Fields\Fields;
7-
use Cone\Root\Fields\Relation;
87
use Illuminate\Database\Eloquent\Builder;
98
use Illuminate\Http\Request;
109

@@ -30,43 +29,17 @@ public function __construct(Fields $fields)
3029
*/
3130
public function apply(Request $request, Builder $query, mixed $value): Builder
3231
{
33-
$attributes = $this->getSearchableAttributes();
34-
35-
if (empty($value) || empty($attributes)) {
32+
if (empty($value)) {
3633
return $query;
3734
}
3835

39-
return $query->where(static function (Builder $query) use ($attributes, $value): void {
40-
foreach ($attributes as $attribute => $fields) {
41-
$operator = array_key_first($attributes) === $attribute ? 'and' : 'or';
42-
43-
if (is_array($fields)) {
44-
$query->has($attribute, '>=', 1, $operator, static function (Builder $query) use ($fields, $value): Builder {
45-
foreach ($fields as $field) {
46-
$operator = $fields[0] === $field ? 'and' : 'or';
47-
48-
$query->where($query->qualifyColumn($field), 'like', "%{$value}%", $operator);
49-
}
50-
51-
return $query;
52-
});
53-
} else {
54-
$query->where($query->qualifyColumn($attribute), 'like', "%{$value}%", $operator);
55-
}
56-
}
36+
return $query->where(function (Builder $query) use ($request, $value): void {
37+
$this->fields->each(function (Field $field) use ($request, $query, $value): void {
38+
$field->resolveFilterQuery($request, $query, $value);
39+
});
5740
});
5841
}
5942

60-
/**
61-
* Get the serachable attributes.
62-
*/
63-
public function getSearchableAttributes(): array
64-
{
65-
return $this->fields->mapWithKeys(static fn (Field $field): array => [
66-
$field->getModelAttribute() => $field instanceof Relation ? $field->getSearchableColumns() : null,
67-
])->all();
68-
}
69-
7043
/**
7144
* {@inheritdoc}
7245
*/

src/Root.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class Root
2525
*
2626
* @var string
2727
*/
28-
public const string VERSION = '2.6.0';
28+
public const string VERSION = '2.6.1';
2929

3030
/**
3131
* The registered booting callbacks.

tests/Filters/SearchTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ class SearchTest extends TestCase
1414
public function test_a_search_filter_modifies_query(): void
1515
{
1616
$filter = new Search(new Fields([
17-
new Text('Name'),
18-
new BelongsToMany('Teams'),
17+
(new Text('Name'))->searchable(),
18+
(new BelongsToMany('Teams'))->searchable(),
1919
]));
2020

2121
$this->assertSame(

0 commit comments

Comments
 (0)