Skip to content

Commit a425bd2

Browse files
committed
Set the global filter value according to the URL + tests
1 parent bd345f1 commit a425bd2

8 files changed

Lines changed: 153 additions & 11 deletions

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Code16\Sharp\Exceptions;
4+
5+
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
6+
7+
class SharpInvalidFilterValueException extends SharpException implements HttpExceptionInterface
8+
{
9+
public function getStatusCode(): int
10+
{
11+
return 404;
12+
}
13+
}

src/Filters/GlobalRequiredFilter.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace Code16\Sharp\Filters;
44

5+
use Code16\Sharp\Exceptions\SharpInvalidFilterValueException;
6+
57
abstract class GlobalRequiredFilter extends SelectRequiredFilter
68
{
79
final public function currentValue(): mixed
@@ -29,7 +31,11 @@ final public function setCurrentValue(mixed $value): void
2931
->where('id', $value)
3032
->first();
3133

32-
session()->put($this->getSessionKey(), $formattedValue['id'] ?? null);
34+
if (! $formattedValue) {
35+
throw new SharpInvalidFilterValueException('['.$value.'] is not a valid value for this filter.');
36+
}
37+
38+
session()->put($this->getSessionKey(), $formattedValue['id']);
3339
}
3440

3541
private function getSessionKey(): string

src/Filters/SelectFilter.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,7 @@ protected function formattedValues(): array
7575

7676
if (! is_array(collect($values)->first())) {
7777
return collect($values)
78-
->map(function ($label, $id) {
79-
return compact('id', 'label');
80-
})
78+
->map(fn ($label, $id) => compact('id', 'label'))
8179
->values()
8280
->all();
8381
}

src/Http/Context/SharpContext.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,13 @@ public function globalFilterValue(string $handlerClassOrKey): array|string|null
2626
public function globalFilterUrlSegmentValue(): string
2727
{
2828
return collect(sharp()->config()->get('global_filters'))
29-
->map(fn ($globalFilterClassOrInstance) => is_string($globalFilterClassOrInstance) ? app($globalFilterClassOrInstance) : $globalFilterClassOrInstance)
29+
->map(fn ($globalFilterClassOrInstance) => is_string($globalFilterClassOrInstance)
30+
? app($globalFilterClassOrInstance)
31+
: $globalFilterClassOrInstance
32+
)
3033
->map(fn (GlobalRequiredFilter $globalFilter) => $globalFilter->currentValue())
3134
->filter()
32-
->implode('-') ?: GlobalFilters::$defaultKey;
35+
->implode(':') ?: GlobalFilters::$defaultKey;
3336
}
3437

3538
public function retainedFilterValue(string $handlerClassOrKey): array|string|null

src/Http/Controllers/GlobalFilterController.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Code16\Sharp\Http\Controllers;
44

5+
use Code16\Sharp\Exceptions\SharpInvalidFilterValueException;
56
use Code16\Sharp\Filters\GlobalFilters\GlobalFilters;
67
use Code16\Sharp\Filters\GlobalRequiredFilter;
78
use Illuminate\Http\RedirectResponse;
@@ -14,7 +15,11 @@ public function update(string $filterKey, GlobalFilters $globalFilters): Redirec
1415

1516
abort_if(! $handler instanceof GlobalRequiredFilter, 404);
1617

17-
$handler->setCurrentValue(request('value'));
18+
try {
19+
$handler->setCurrentValue(request('value'));
20+
} catch (SharpInvalidFilterValueException) {
21+
// Reset global filter to its previous value instead of showing an error
22+
}
1823

1924
return redirect()->route('code16.sharp.home');
2025
}

src/Http/Middleware/HandleGlobalFilters.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,34 @@
33
namespace Code16\Sharp\Http\Middleware;
44

55
use Closure;
6+
use Code16\Sharp\Filters\GlobalRequiredFilter;
7+
use Illuminate\Http\Request;
68
use Illuminate\Support\Facades\URL;
79

810
class HandleGlobalFilters
911
{
10-
public function handle($request, Closure $next)
12+
public function handle(Request $request, Closure $next)
1113
{
1214
URL::defaults(['filterKey' => sharp()->context()->globalFilterUrlSegmentValue()]);
1315

16+
if ($request->isMethod('GET') && ($filterKey = $request->route('filterKey'))) {
17+
$filterKeys = explode(':', $filterKey);
18+
$configuredGlobalFilters = collect(sharp()->config()->get('global_filters'))
19+
->map(fn ($globalFilterClassOrInstance) => is_string($globalFilterClassOrInstance)
20+
? app($globalFilterClassOrInstance)
21+
: $globalFilterClassOrInstance
22+
);
23+
24+
if (count($configuredGlobalFilters) != 0 && count($filterKeys) != count($configuredGlobalFilters)) {
25+
return redirect()->route('code16.sharp.home');
26+
}
27+
28+
$configuredGlobalFilters
29+
->each(fn (GlobalRequiredFilter $globalFilter, $index) => $globalFilter
30+
->setCurrentValue($filterKeys[$index])
31+
);
32+
}
33+
1434
return $next($request);
1535
}
1636
}

tests/Http/GlobalFilterControllerTest.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,12 @@ public function defaultValue(): mixed
5858
$this->assertEquals(2, sharp()->context()->globalFilterValue('test'));
5959
});
6060

61-
it('the current value of the global filter is sent with every inertia request', function () {
61+
it('sends the current value of the global filter with every inertia request', function () {
6262
sharp()->config()->declareEntity(PersonEntity::class);
6363

6464
$this
65-
->get('/sharp/root/s-list/person')
65+
->followingRedirects()
66+
->get('/sharp/s-list/person')
6667
->assertInertia(fn (Assert $page) => $page
6768
->has('globalFilters.config.filters._root.0', fn (Assert $filter) => $filter
6869
->where('key', 'test')
@@ -77,7 +78,8 @@ public function defaultValue(): mixed
7778
->post(route('code16.sharp.filters.update', 'test'), ['value' => 3]);
7879

7980
$this
80-
->get('/sharp/root/s-list/person')
81+
->followingRedirects()
82+
->get('/sharp/s-list/person')
8183
->assertInertia(fn (Assert $page) => $page
8284
->has('globalFilters.config.filters._root.0', fn (Assert $filter) => $filter
8385
->where('key', 'test')
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<?php
2+
3+
use Code16\Sharp\Filters\GlobalRequiredFilter;
4+
use Code16\Sharp\Tests\Fixtures\Entities\DashboardEntity;
5+
use Code16\Sharp\Tests\Fixtures\Entities\PersonEntity;
6+
use Code16\Sharp\Tests\Fixtures\Entities\SinglePersonEntity;
7+
8+
beforeEach(function () {
9+
sharp()->config()->declareEntity(PersonEntity::class);
10+
login();
11+
});
12+
13+
it('redirects to route with default filterKey when missing', function () {
14+
sharp()->config()
15+
->declareEntity(DashboardEntity::class)
16+
->declareEntity(SinglePersonEntity::class);
17+
18+
$this->get('/sharp/s-list/person')
19+
->assertRedirect('/sharp/root/s-list/person');
20+
21+
$this->get('/sharp/s-list/person/s-show/person/1')
22+
->assertRedirect('/sharp/root/s-list/person/s-show/person/1');
23+
24+
$this->get('/sharp/s-list/person/s-show/person/1/s-form/person/1')
25+
->assertRedirect('/sharp/root/s-list/person/s-show/person/1/s-form/person/1');
26+
27+
$this->get('/sharp/s-list/person/s-show/person/1/s-show/person/2/s-form/person/2')
28+
->assertRedirect('/sharp/root/s-list/person/s-show/person/1/s-show/person/2/s-form/person/2');
29+
30+
$this->get('/sharp/s-dashboard/dashboard')
31+
->assertRedirect('/sharp/root/s-dashboard/dashboard');
32+
33+
$this->get('/sharp/s-show/single-person')
34+
->assertRedirect('/sharp/root/s-show/single-person');
35+
});
36+
37+
it('redirects to route with correct filterKey when missing and global filters are defined', function () {
38+
fakeGlobalFilter();
39+
40+
$this->get('/sharp/s-list/person')
41+
->assertRedirect('/sharp/two/s-list/person');
42+
43+
$this->post(route('code16.sharp.filters.update', 'test'), ['value' => 'three']);
44+
45+
$this->get('/sharp/s-list/person/s-show/person/1')
46+
->assertRedirect('/sharp/three/s-list/person/s-show/person/1');
47+
});
48+
49+
it('sets the current filterKey according to the URL', function () {
50+
fakeGlobalFilter();
51+
52+
$this->post(route('code16.sharp.filters.update', 'test'), ['value' => 'three']);
53+
$this->get('/sharp/one/s-list/person/s-show/person/1')
54+
->assertOk();
55+
56+
expect(sharp()->context()->globalFilterValue('test'))->toEqual('one');
57+
});
58+
59+
it('wont set an invalid value of the current filterKey according to the URL', function () {
60+
fakeGlobalFilter();
61+
62+
$this->get('/sharp/five/s-list/person/s-show/person/1')
63+
->assertNotFound();
64+
65+
expect(sharp()->context()->globalFilterValue('test'))->toEqual('two');
66+
});
67+
68+
// TODO test multiple filters
69+
70+
function fakeGlobalFilter(): void
71+
{
72+
sharp()->config()->addGlobalFilter(
73+
new class() extends GlobalRequiredFilter
74+
{
75+
public function buildFilterConfig(): void
76+
{
77+
$this->configureKey('test');
78+
}
79+
80+
public function values(): array
81+
{
82+
return [
83+
'one' => 'Company One',
84+
'two' => 'Company Two',
85+
'three' => 'Company Three',
86+
];
87+
}
88+
89+
public function defaultValue(): mixed
90+
{
91+
return 'two';
92+
}
93+
}
94+
);
95+
}

0 commit comments

Comments
 (0)