Skip to content
Advertisement

Laravel model user custom binding “/users/me/xxx”

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?

Advertisement

Answer

I believe using a fixed route parameter like this is the most sustainable solution, especially if this is a shared code base. It will involve some repeated code, but makes it immediately clear what routes are available. And you can predefine the grouping callback to avoid repeating the route definitions.

$routeGroup = function ($r) {
    $r->get('posts', [PostController::class, 'index']);
    $r->get('comments', [CommentController::class, 'index']);
};

Route::prefix('users/{user}')->group($routeGroup);
Route::prefix('users/me')->group($routeGroup);

And then make the parameter optional in your controller method.

public function index(User $user = null)
{
    $user = $user ?? Auth::user();
    dd($user);
}

Another possibility is overriding the resolveRouteBinding method on your model. If you go with this method (or Patricus’ solution) I’d suggest leaving comments in the route file explaining what you’ve done.

class User extends Model {
    public function resolveRouteBinding($value, $field = null): ?self
    {
        return $value === 'me'
            ? Auth::user()
            : parent::resolveRouteBinding($value, $field);
    }
}
User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement