I need to display posts by tags. My solution works for a single tag like this:
route:
Route::get('/posts', [PostController::class, 'index'])->middleware('auth');
Post model filter:
public function scopeFilter($query, array $filters) { if ($filters['tag'] ?? false) { $tagId = Tag::where('name', $filters['tag'])->first()->id; $query->whereHas('tags', function($q) use ($tagId) { $q->where('tag_id', $tagId); }); } }
Method index of PostController:
public function index() { return view('posts', [ 'posts' => Post::latest()->filter(request(['tag']))->get() ]); }
This code applies to the following URL: "http://127.0.0.1:8000/posts/?tag=test". But I need to find a way to search for posts with more tags, for example I want to find posts with tags "test" and "unit". To do this I want to use a URL like this: "http://127.0.0.1:8000/posts/?tag=test&unit". I'm stuck because I thought "request(['tag'])" would return "test&unit" but it only returns "test". Is it possible to somehow get the "unit" tag from this request?
P粉5961619152024-04-04 18:26:32
GET
requests using query strings can accept multiple parameters. instead of ?tag=test&unit
(which won't really work anyway, since &unit
will be parsed as $request->input('unit')
, and will be null
, &
are reserved characters), you can send it as:
http://127.0.0.1:8000/posts?tags[]=test&tags[]=unit
On the backend, when you access request()->input('tags')
, you get the following array:
$tags = request()->input('tags'); // ['test', 'unit']
So, put them together:
// ScopeFilter method on your `Post` Model
public function scopeFilter($query, array $tagNames) {
if (!empty($tagNames)) {
$tagIds = Tag::whereIn('name', $tagNames)->pluck('id');
return $query->whereHas('tags', function($subQuery) use ($tagIds) {
return $subQuery->whereIn('tags.id', $tagIds);
});
// Alternative without `$tagIds`, using `$tagNames` directly
// return $query->whereHas('tags', function($subQuery) use ($tagNames) {
// return $subQuery->whereIn('tags.name', $tagNames);
// });
}
return $query;
}
// Usage
public function index() {
return view('posts', [
'posts' => Post::latest()->filter(request()->input('tags', []))->get()
]);
}
whereIn()
request()->input('tags', [])
to access ?tags[]=...&tags[]=...
, if not Provided is an empty array.