Skip to content

Commit

Permalink
9.3.0 (#610)
Browse files Browse the repository at this point in the history
* feat: add support for POST advanced filters

* Fix styling

* fix: docs

* fix: wip

---------

Co-authored-by: binaryk <[email protected]>
  • Loading branch information
binaryk and binaryk authored Jul 2, 2024
1 parent 7145785 commit 4efd863
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 8 deletions.
80 changes: 77 additions & 3 deletions docs-v2/content/en/search/advanced-filters.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,22 @@ The frontend has to encode into base64 an array of filters. Each filter contains

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

## Apply advanced filters via POST Request (Version 9.3.0+)

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:

```javascript
const filters = [
{
'key': 'ready-posts-filter',
'value': null,
}
];

const response = await axios.post(`api/restify/posts/apply-restify-advanced-filters`, filters);
```


### Custom uri key

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:
Expand All @@ -102,6 +118,64 @@ class ReadyPostsFilter extends AdvancedFilter

};
```

### Custom title

```php
class ReadyPostsFilter extends AdvancedFilter
{
public static $title = 'Ready to publish posts';

//...

};
```

### Custom description

```php
class ReadyPostsFilter extends AdvancedFilter
{
public static $description = 'Filter all posts that are ready to publish';

//...

};
```

### Custom meta

```php
class ReadyPostsFilter extends AdvancedFilter
{
public function meta(): array
{
return [
'icon' => 'icon',
'color' => 'red',
'operators' => [
'like' => 'Like',
'eq' => 'Equal',
]
];
}
};
```

Meta will be rendered key/value in the frontend:

```json
{
...
"icon": "icon",
"color": "red",
"operators": {
"like": "Like",
"eq": "Equal"
}
}
```

### Advanced filter value

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:
Expand Down Expand Up @@ -392,16 +466,16 @@ In some scenarios, you might want to send additional data beyond the standard ke

Consider the following payload:
```json
const filters = btoa(JSON.stringify([
const filters = [
{
'key': ValueFilter::uriKey(),
'value': 'Valid%',
'operator' => 'like',
'column' => 'description',
}
]));
];

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

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.
Expand Down
5 changes: 5 additions & 0 deletions src/Bootstrap/RoutesDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ public function __invoke(?string $uriKey = null)
\Binaryk\LaravelRestify\Http\Controllers\RepositoryFilterController::class
)->name('filters.index');

Route::post(
$prefix.'/apply-restify-advanced-filters',
\Binaryk\LaravelRestify\Http\Controllers\RepositoryApplyFiltersController::class
)->name('filters.apply');

// Actions
Route::get(
$prefix.'/actions',
Expand Down
2 changes: 1 addition & 1 deletion src/Events/AdvancedFiltersApplied.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ class AdvancedFiltersApplied
public function __construct(
public Repository $repository,
public AdvancedFiltersCollection $advancedFiltersCollection,
public ?string $rawFilters = null,
public array $rawFilters = [],
) {}
}
4 changes: 1 addition & 3 deletions src/Filters/AdvancedFiltersCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,10 @@ public function apply(RestifyRequest $request, $query): self

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

$filters = json_decode(base64_decode($request->input('filters')), true);

$allowedFilters = $repository->collectAdvancedFilters($request);

return static::make($filters)
Expand Down
13 changes: 13 additions & 0 deletions src/Http/Controllers/RepositoryApplyFiltersController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Binaryk\LaravelRestify\Http\Controllers;

use Binaryk\LaravelRestify\Http\Requests\RepositoryApplyFiltersRequest;

class RepositoryApplyFiltersController extends RepositoryController
{
public function __invoke(RepositoryApplyFiltersRequest $request)
{
return $request->repository()->index($request);
}
}
5 changes: 5 additions & 0 deletions src/Http/Requests/RepositoryApplyFiltersRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

namespace Binaryk\LaravelRestify\Http\Requests;

class RepositoryApplyFiltersRequest extends RestifyRequest {}
7 changes: 7 additions & 0 deletions src/Http/Requests/RestifyRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,11 @@ public function related(): RelatedDto
return app(RelatedDto::class);
}
}

public function filters(): array
{
return $this instanceof RepositoryApplyFiltersRequest
? $this->input('filters', [])
: (json_decode(base64_decode($this->input('filters')), true) ?? []);
}
}
2 changes: 1 addition & 1 deletion src/Services/Search/RepositorySearchService.php
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ protected function applyFilters(RestifyRequest $request, Repository $repository,
$repository,
AdvancedFiltersCollection::collectQueryFilters($request, $repository)
->apply($request, $query),
$request->input('filters'),
$request->filters(),
)
);

Expand Down
26 changes: 26 additions & 0 deletions tests/Feature/Filters/AdvancedFilterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -242,4 +242,30 @@ public function test_filter_can_send_meta(): void
'filters' => $filters,
]))->assertJsonCount(0, 'data');
}

public function test_filter_can_be_sent_in_post_requests(): void
{
Post::factory()->create([
'title' => 'Valid post',
'description' => 'Zoo bar post',
]);

Post::factory()->create([
'title' => 'Active post',
'description' => 'Foo bar post',
]);

$filters = [
[
'key' => ValueFilter::uriKey(),
'value' => 'Valid%',
'operator' => 'like',
'column' => 'title',
],
];

$this->post(PostRepository::route('apply-restify-advanced-filters'), [
'filters' => $filters,
])->assertJsonCount(1, 'data');
}
}

0 comments on commit 4efd863

Please sign in to comment.