I have routes with user binding like
Route::get('users/{user}/posts', [PostController::class, 'index']);
Route::get('users/{user}/comments', [CommentController::class, 'index']);
So I can use /users/1/posts
, /users/5/posts
etc, and in controller it's automatically available thanks to model binding
public function index(User $user)
{
dd($user);
}
But for current logged user I want to make possible to also use /me/
instead ID, like /users/me/posts
Is there a way to make it without defining separate controller methods where I would have to find user manually, and without duplicating all routes? So is it possible to "extend" default Laravel model binding globally?
CodePudding user response:
You can just use a fixed route parameter like this:
Route::get('users/me/posts', [PostController::class, 'index']);
Route::get('users/me/comments', [CommentController::class, 'index']);
Route::get('users/{user}/posts', [PostController::class, 'index']);
Route::get('users/{user}/comments', [CommentController::class, 'index']);
And then make the parameter optional in your controller method.
public function index(User $user = null)
{
$user = $user ?? Auth::user();
dd($user);
}
CodePudding user response:
Sure, you just need to use explicit route model binding instead of the default implicit binding. No need to change your routes or your controllers.
In your RouteServiceProvider::boot()
method, you can add the following binding for the user
parameter:
// use App\Models\User;
// use Illuminate\Support\Facades\Auth;
// use Illuminate\Support\Facades\Route;
public function boot()
{
Route::bind('user', function ($value) {
if ($value == 'me') {
return Auth::user();
}
return User::findOrFail($value);
});
}
Now all your routes with the {user}
parameter defined will use that function to bind the User
model in the route.
You may want to update the function to be able to handle case sensitivity, or handle when the route is accessed as a guest, but that's up to your implementation details.