Skip to content

Commit 4efd863

Browse files
authored
9.3.0 (#610)
* feat: add support for POST advanced filters * Fix styling * fix: docs * fix: wip --------- Co-authored-by: binaryk <[email protected]>
1 parent 7145785 commit 4efd863

File tree

9 files changed

+136
-8
lines changed

9 files changed

+136
-8
lines changed

docs-v2/content/en/search/advanced-filters.md

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,22 @@ The frontend has to encode into base64 an array of filters. Each filter contains
8989

9090
- `value` - this is optional, and represents the value the advanced filter will as a third argument in the `filter` method
9191

92+
## Apply advanced filters via POST Request (Version 9.3.0+)
93+
94+
Starting from version 9.3.0, Laravel Restify introduces the ability to apply advanced filters using a POST request. This enhancement simplifies the process of sending complex filter payloads without the need for base64 encoding. Now, you can send the filters directly as JSON in the request body:
95+
96+
```javascript
97+
const filters = [
98+
{
99+
'key': 'ready-posts-filter',
100+
'value': null,
101+
}
102+
];
103+
104+
const response = await axios.post(`api/restify/posts/apply-restify-advanced-filters`, filters);
105+
```
106+
107+
92108
### Custom uri key
93109

94110
Since your class names could change along the way, you can define a `$uriKey` property to your filters, so the frontend will use always the same `key` when applying a filter:
@@ -102,6 +118,64 @@ class ReadyPostsFilter extends AdvancedFilter
102118

103119
};
104120
```
121+
122+
### Custom title
123+
124+
```php
125+
class ReadyPostsFilter extends AdvancedFilter
126+
{
127+
public static $title = 'Ready to publish posts';
128+
129+
//...
130+
131+
};
132+
```
133+
134+
### Custom description
135+
136+
```php
137+
class ReadyPostsFilter extends AdvancedFilter
138+
{
139+
public static $description = 'Filter all posts that are ready to publish';
140+
141+
//...
142+
143+
};
144+
```
145+
146+
### Custom meta
147+
148+
```php
149+
class ReadyPostsFilter extends AdvancedFilter
150+
{
151+
public function meta(): array
152+
{
153+
return [
154+
'icon' => 'icon',
155+
'color' => 'red',
156+
'operators' => [
157+
'like' => 'Like',
158+
'eq' => 'Equal',
159+
]
160+
];
161+
}
162+
};
163+
```
164+
165+
Meta will be rendered key/value in the frontend:
166+
167+
```json
168+
{
169+
...
170+
"icon": "icon",
171+
"color": "red",
172+
"operators": {
173+
"like": "Like",
174+
"eq": "Equal"
175+
}
176+
}
177+
```
178+
105179
### Advanced filter value
106180

107181
The third argument of the `filter` method is the raw value send by the frontend. Sometimes it might be an array, so you have to get the value using array access:
@@ -392,16 +466,16 @@ In some scenarios, you might want to send additional data beyond the standard ke
392466

393467
Consider the following payload:
394468
```json
395-
const filters = btoa(JSON.stringify([
469+
const filters = [
396470
{
397471
'key': ValueFilter::uriKey(),
398472
'value': 'Valid%',
399473
'operator' => 'like',
400474
'column' => 'description',
401475
}
402-
]));
476+
];
403477

404-
const response = await axios.get(`api/restify/posts?filters=${filters}`);
478+
const response = await axios.post(`api/restify/posts/apply-restify-advanced-filters`, filters);
405479
```
406480

407481
In this payload, besides the standard key and value, we are also sending operator and column. The operator specifies the type of SQL operation, and the column specifies the database column to filter.

src/Bootstrap/RoutesDefinition.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ public function __invoke(?string $uriKey = null)
2222
\Binaryk\LaravelRestify\Http\Controllers\RepositoryFilterController::class
2323
)->name('filters.index');
2424

25+
Route::post(
26+
$prefix.'/apply-restify-advanced-filters',
27+
\Binaryk\LaravelRestify\Http\Controllers\RepositoryApplyFiltersController::class
28+
)->name('filters.apply');
29+
2530
// Actions
2631
Route::get(
2732
$prefix.'/actions',

src/Events/AdvancedFiltersApplied.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ class AdvancedFiltersApplied
1010
public function __construct(
1111
public Repository $repository,
1212
public AdvancedFiltersCollection $advancedFiltersCollection,
13-
public ?string $rawFilters = null,
13+
public array $rawFilters = [],
1414
) {}
1515
}

src/Filters/AdvancedFiltersCollection.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,10 @@ public function apply(RestifyRequest $request, $query): self
2626

2727
public static function collectQueryFilters(RestifyRequest $request, Repository $repository): self
2828
{
29-
if (! $request->input('filters')) {
29+
if (! $filters = $request->filters()) {
3030
return static::make([]);
3131
}
3232

33-
$filters = json_decode(base64_decode($request->input('filters')), true);
34-
3533
$allowedFilters = $repository->collectAdvancedFilters($request);
3634

3735
return static::make($filters)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Binaryk\LaravelRestify\Http\Controllers;
4+
5+
use Binaryk\LaravelRestify\Http\Requests\RepositoryApplyFiltersRequest;
6+
7+
class RepositoryApplyFiltersController extends RepositoryController
8+
{
9+
public function __invoke(RepositoryApplyFiltersRequest $request)
10+
{
11+
return $request->repository()->index($request);
12+
}
13+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
namespace Binaryk\LaravelRestify\Http\Requests;
4+
5+
class RepositoryApplyFiltersRequest extends RestifyRequest {}

src/Http/Requests/RestifyRequest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,11 @@ public function related(): RelatedDto
7070
return app(RelatedDto::class);
7171
}
7272
}
73+
74+
public function filters(): array
75+
{
76+
return $this instanceof RepositoryApplyFiltersRequest
77+
? $this->input('filters', [])
78+
: (json_decode(base64_decode($this->input('filters')), true) ?? []);
79+
}
7380
}

src/Services/Search/RepositorySearchService.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ protected function applyFilters(RestifyRequest $request, Repository $repository,
210210
$repository,
211211
AdvancedFiltersCollection::collectQueryFilters($request, $repository)
212212
->apply($request, $query),
213-
$request->input('filters'),
213+
$request->filters(),
214214
)
215215
);
216216

tests/Feature/Filters/AdvancedFilterTest.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,4 +242,30 @@ public function test_filter_can_send_meta(): void
242242
'filters' => $filters,
243243
]))->assertJsonCount(0, 'data');
244244
}
245+
246+
public function test_filter_can_be_sent_in_post_requests(): void
247+
{
248+
Post::factory()->create([
249+
'title' => 'Valid post',
250+
'description' => 'Zoo bar post',
251+
]);
252+
253+
Post::factory()->create([
254+
'title' => 'Active post',
255+
'description' => 'Foo bar post',
256+
]);
257+
258+
$filters = [
259+
[
260+
'key' => ValueFilter::uriKey(),
261+
'value' => 'Valid%',
262+
'operator' => 'like',
263+
'column' => 'title',
264+
],
265+
];
266+
267+
$this->post(PostRepository::route('apply-restify-advanced-filters'), [
268+
'filters' => $filters,
269+
])->assertJsonCount(1, 'data');
270+
}
245271
}

0 commit comments

Comments
 (0)