Laravel 模型用户自定义绑定“/users/me/xxx”
Laravel model user custom binding "/users/me/xxx"
我有像
这样的用户绑定路由
Route::get('users/{user}/posts', [PostController::class, 'index']);
Route::get('users/{user}/comments', [CommentController::class, 'index']);
所以我可以使用 /users/1/posts
、/users/5/posts
等,并且由于模型绑定,它在控制器中自动可用
public function index(User $user)
{
dd($user);
}
但是对于当前登录的用户,我希望也可以使用 /me/
而不是 ID,例如 /users/me/posts
有没有办法在不定义单独的控制器方法的情况下,我必须手动查找用户,并且不复制所有路由?那么是否有可能在全球范围内“扩展”默认 Laravel 模型绑定?
我认为使用像这样的固定路由参数是最可持续的解决方案,尤其是在共享代码库的情况下。它将涉及一些重复的代码,但会立即清楚哪些路由可用。并且可以预定义分组回调,避免重复路由定义。
$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);
然后在您的控制器方法中将参数设为可选。
public function index(User $user = null)
{
$user = $user ?? Auth::user();
dd($user);
}
另一种可能性是覆盖模型上的 resolveRouteBinding
方法。如果您使用这种方法(或 Patricus 的解决方案),我建议您在路由文件中留下注释,解释您所做的事情。
class User extends Model {
public function resolveRouteBinding($value, $field = null): ?self
{
return $value === 'me'
? Auth::user()
: parent::resolveRouteBinding($value, $field);
}
}
当然,您只需要使用 explicit route model binding 而不是默认的隐式绑定。无需更改路线或控制器。
在您的 RouteServiceProvider::boot()
方法中,您可以为 user
参数添加以下绑定:
// 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);
});
}
现在所有定义了 {user}
参数的路由都将使用该函数绑定路由中的 User
模型。
您可能希望更新函数以能够处理区分大小写的问题,或者在以访客身份访问路由时进行处理,但这取决于您的实施细节。
我有像
这样的用户绑定路由Route::get('users/{user}/posts', [PostController::class, 'index']);
Route::get('users/{user}/comments', [CommentController::class, 'index']);
所以我可以使用 /users/1/posts
、/users/5/posts
等,并且由于模型绑定,它在控制器中自动可用
public function index(User $user)
{
dd($user);
}
但是对于当前登录的用户,我希望也可以使用 /me/
而不是 ID,例如 /users/me/posts
有没有办法在不定义单独的控制器方法的情况下,我必须手动查找用户,并且不复制所有路由?那么是否有可能在全球范围内“扩展”默认 Laravel 模型绑定?
我认为使用像这样的固定路由参数是最可持续的解决方案,尤其是在共享代码库的情况下。它将涉及一些重复的代码,但会立即清楚哪些路由可用。并且可以预定义分组回调,避免重复路由定义。
$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);
然后在您的控制器方法中将参数设为可选。
public function index(User $user = null)
{
$user = $user ?? Auth::user();
dd($user);
}
另一种可能性是覆盖模型上的 resolveRouteBinding
方法。如果您使用这种方法(或 Patricus 的解决方案),我建议您在路由文件中留下注释,解释您所做的事情。
class User extends Model {
public function resolveRouteBinding($value, $field = null): ?self
{
return $value === 'me'
? Auth::user()
: parent::resolveRouteBinding($value, $field);
}
}
当然,您只需要使用 explicit route model binding 而不是默认的隐式绑定。无需更改路线或控制器。
在您的 RouteServiceProvider::boot()
方法中,您可以为 user
参数添加以下绑定:
// 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);
});
}
现在所有定义了 {user}
参数的路由都将使用该函数绑定路由中的 User
模型。
您可能希望更新函数以能够处理区分大小写的问题,或者在以访客身份访问路由时进行处理,但这取决于您的实施细节。