Skip to content

Commit ad9352e

Browse files
idormencoandreiio
andauthored
Add filtering by published at (#194)
* Add filtering by published at * Update NewsController.php * style: apply fix --------- Co-authored-by: Andrei Ioniță <hi@andrei.io>
1 parent ca68911 commit ad9352e

File tree

7 files changed

+246
-9
lines changed

7 files changed

+246
-9
lines changed

app/Http/Controllers/NewsController.php

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@
44

55
namespace App\Http\Controllers;
66

7+
use App\Http\Filters\PublishedAfterFilter;
8+
use App\Http\Filters\PublishedAtFilter;
9+
use App\Http\Filters\PublishedBeforeFilter;
710
use App\Http\Resources\NewsResource;
811
use App\Models\News;
9-
use Illuminate\Database\Eloquent\Relations\BelongsTo;
1012
use Illuminate\Http\Resources\Json\JsonResource;
13+
use Spatie\QueryBuilder\AllowedFilter;
14+
use Spatie\QueryBuilder\QueryBuilder;
1115

1216
class NewsController extends Controller
1317
{
@@ -16,16 +20,22 @@ public function __invoke(): JsonResource
1620
$this->authorize('accessApi');
1721

1822
return NewsResource::collection(
19-
News::query()
20-
->wherePublished()
23+
QueryBuilder::for(News::class)
24+
->allowedFilters([
25+
AllowedFilter::custom('published_at', new PublishedAtFilter),
26+
AllowedFilter::custom('published_before', new PublishedBeforeFilter),
27+
AllowedFilter::custom('published_after', new PublishedAfterFilter),
28+
])
2129
->with([
2230
'media',
23-
'organisation' => fn(BelongsTo $query) => $query
31+
'organisation' => fn ($query) => $query
2432
->withoutEagerLoads()
2533
->select('id', 'name'),
2634
])
27-
->orderBy('id', 'desc')
35+
->where('status', 'published')
36+
->defaultSort('-published_at')
2837
->paginate(25)
38+
->appends(request()->query())
2939
);
3040
}
3141
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Http\Filters;
6+
7+
use Illuminate\Database\Eloquent\Builder;
8+
use Illuminate\Support\Carbon;
9+
use Spatie\QueryBuilder\Filters\Filter;
10+
11+
class PublishedAfterFilter implements Filter
12+
{
13+
public function __invoke(Builder $query, $value, string $property): Builder
14+
{
15+
try {
16+
$date = Carbon::parse($value);
17+
} catch (\Exception $e) {
18+
return $query;
19+
}
20+
21+
return $query->whereDate('published_at', '>=', $date);
22+
}
23+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Http\Filters;
6+
7+
use Illuminate\Database\Eloquent\Builder;
8+
use Illuminate\Support\Carbon;
9+
use Spatie\QueryBuilder\Filters\Filter;
10+
11+
class PublishedAtFilter implements Filter
12+
{
13+
public function __invoke(Builder $query, $value, string $property): Builder
14+
{
15+
try {
16+
$date = Carbon::parse($value);
17+
} catch (\Exception $e) {
18+
return $query;
19+
}
20+
21+
return $query->whereDate('published_at', $date);
22+
}
23+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Http\Filters;
6+
7+
use Illuminate\Database\Eloquent\Builder;
8+
use Illuminate\Support\Carbon;
9+
use Spatie\QueryBuilder\Filters\Filter;
10+
11+
class PublishedBeforeFilter implements Filter
12+
{
13+
public function __invoke(Builder $query, $value, string $property): Builder
14+
{
15+
try {
16+
$date = Carbon::parse($value);
17+
} catch (\Exception $e) {
18+
return $query;
19+
}
20+
21+
return $query->whereDate('published_at', '<=', $date);
22+
}
23+
}

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
"laravel/tinker": "^2.8",
1818
"league/flysystem-aws-s3-v3": "^3.21",
1919
"pxlrbt/filament-excel": "^1.1",
20-
"sentry/sentry-laravel": "^4.1"
20+
"sentry/sentry-laravel": "^4.1",
21+
"spatie/laravel-query-builder": "^6.3"
2122
},
2223
"require-dev": {
2324
"barryvdh/laravel-debugbar": "^3.13",

composer.lock

Lines changed: 76 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/query-builder.php

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
return [
6+
7+
/*
8+
* By default the package will use the `include`, `filter`, `sort`
9+
* and `fields` query parameters as described in the readme.
10+
*
11+
* You can customize these query string parameters here.
12+
*/
13+
'parameters' => [
14+
'include' => 'include',
15+
16+
'filter' => 'filter',
17+
18+
'sort' => 'sort',
19+
20+
'fields' => 'fields',
21+
22+
'append' => 'append',
23+
],
24+
25+
/*
26+
* Related model counts are included using the relationship name suffixed with this string.
27+
* For example: GET /users?include=postsCount
28+
*/
29+
'count_suffix' => 'Count',
30+
31+
/*
32+
* Related model exists are included using the relationship name suffixed with this string.
33+
* For example: GET /users?include=postsExists
34+
*/
35+
'exists_suffix' => 'Exists',
36+
37+
/*
38+
* By default the package will throw an `InvalidFilterQuery` exception when a filter in the
39+
* URL is not allowed in the `allowedFilters()` method.
40+
*/
41+
'disable_invalid_filter_query_exception' => true,
42+
43+
/*
44+
* By default the package will throw an `InvalidSortQuery` exception when a sort in the
45+
* URL is not allowed in the `allowedSorts()` method.
46+
*/
47+
'disable_invalid_sort_query_exception' => true,
48+
49+
/*
50+
* By default the package will throw an `InvalidIncludeQuery` exception when an include in the
51+
* URL is not allowed in the `allowedIncludes()` method.
52+
*/
53+
'disable_invalid_includes_query_exception' => true,
54+
55+
/*
56+
* By default, the package expects relationship names to be snake case plural when using fields[relationship].
57+
* For example, fetching the id and name for a userOwner relation would look like this:
58+
* GET /users?fields[user_owner]=id,name
59+
*
60+
* Set this to `false` if you don't want that and keep the requested relationship names as-is and allows you to
61+
* request the fields using a camelCase relationship name:
62+
* GET /users?fields[userOwner]=id,name
63+
*/
64+
'convert_relation_names_to_snake_case_plural' => true,
65+
66+
/*
67+
* By default, the package expects relationship names to be snake case plural when using fields[relationship].
68+
* For example, fetching the id and name for a userOwner relation would look like this:
69+
* GET /users?fields[user_owner]=id,name
70+
*
71+
* Set this to one of `snake_case`, `camelCase` or `none` if you want to enable table name resolution in addition to the relation name resolution
72+
* GET /users?include=topOrders&fields[orders]=id,name
73+
*/
74+
'convert_relation_table_name_strategy' => false,
75+
76+
/*
77+
* By default, the package expects the field names to match the database names
78+
* For example, fetching the field named firstName would look like this:
79+
* GET /users?fields=firstName
80+
*
81+
* Set this to `true` if you want to convert the firstName into first_name for the underlying query
82+
*/
83+
'convert_field_names_to_snake_case' => false,
84+
];

0 commit comments

Comments
 (0)