如何在Laravel应用中实现无Follow模型的用户关注API
问题描述
我想在Laravel应用中添加用户关注其他用户的功能,调研后确定无需创建Follow模型,已创建follow_users中间表,表结构如下:
Schema::create('follow_users', function (Blueprint $table) { $table->id(); $table->foreignId('user_id')->constrained()->onUpdate('cascade')->onDelete('cascade'); $table->foreignId('follow_id')->constrained('users', 'id')->onUpdate('cascade')->onDelete('cascade'); $table->timestamps(); });
我知道无需id和timestamps字段,但仍希望保留它们。
路由配置(仅展示相关部分):
Route::middleware('auth:sanctum')->prefix('v2')->group(function () { Route::apiResource('/follows', FollowController::class); });
User模型中已定义关联方法:
public function followings(): BelongsToMany { return $this->belongsToMany(User::class, 'follow_users', 'follow_id', 'user_id')->withTimestamps(); }
我已创建FollowController,计划实现index、store、show、update、delete方法,但之前的控制器都是通过模型create方法存储数据(如下示例),由于没有Follow模型和FollowResource,不知道如何通过User模型将数据保存到中间表:
public function store(StoreCommentRequest $request) { $suggestion = Comment::create($request->validated()); return CommentResource::make($suggestion); }
解决方案
1. 修正User模型的关联定义
你当前的followings关联参数顺序有误,正确的多对多关联参数规则是:
- 第二个参数:中间表名
- 第三个参数:当前模型(User)在中间表的外键字段(即
user_id) - 第四个参数:关联模型(User)在中间表的外键字段(即
follow_id)
修正后的关联方法:
public function followings(): BelongsToMany { return $this->belongsToMany(User::class, 'follow_users', 'user_id', 'follow_id') ->withTimestamps(); // 启用中间表的timestamps自动更新 } // 额外补充:如需获取当前用户的粉丝列表,可添加此关联 public function followers(): BelongsToMany { return $this->belongsToMany(User::class, 'follow_users', 'follow_id', 'user_id') ->withTimestamps(); }
2. 创建表单请求验证
先创建StoreFollowRequest验证关注请求的合法性:
php artisan make:request StoreFollowRequest
在app/Http/Requests/StoreFollowRequest.php中编写验证规则:
use Illuminate\Validation\Rule; public function rules() { return [ 'follow_id' => [ 'required', 'integer', 'exists:users,id', // 禁止关注自己 Rule::notIn([auth()->id()]) ] ]; }
3. 实现FollowController的各个方法
store(关注用户)
利用Laravel多对多关联的attach方法,将当前用户与目标用户的关系写入中间表:
use App\Http\Requests\StoreFollowRequest; use App\Http\Resources\UserResource; public function store(StoreFollowRequest $request) { $followId = $request->validated()['follow_id']; // 避免重复关注 if (!auth()->user()->followings()->where('follow_id', $followId)->exists()) { auth()->user()->followings()->attach($followId); } // 返回被关注用户的信息 $followedUser = \App\Models\User::findOrFail($followId); return UserResource::make($followedUser); }
index(获取当前用户的关注列表)
返回当前用户关注的所有用户:
use App\Http\Resources\UserResource; public function index() { $followings = auth()->user()->followings()->paginate(); return UserResource::collection($followings); }
show(检查是否关注某用户)
用于验证当前用户是否关注了指定ID的用户,同时返回目标用户信息:
use App\Http\Resources\UserResource; public function show($id) { $user = \App\Models\User::findOrFail($id); $isFollowing = auth()->user()->followings()->where('follow_id', $id)->exists(); return response()->json([ 'user' => UserResource::make($user), 'is_following' => $isFollowing ]); }
destroy(取消关注)
使用detach方法移除中间表的关联记录:
public function destroy($id) { auth()->user()->followings()->detach($id); return response()->json([ 'message' => '已取消关注' ], 200); }
update(可选)
由于中间表除了id和timestamps没有其他业务字段,关注关系本身不需要更新操作,可直接返回405状态:
public function update(Request $request, $id) { return response()->json([ 'message' => '该操作不支持' ], 405); }
4. 关于资源返回
因为没有Follow模型,直接用UserResource返回用户信息即可;如果需要获取关注时间等中间表字段,可以在关联中添加withPivot:
// 在followings关联中添加 ->withPivot('created_at', 'updated_at') // 使用时可获取中间表数据 foreach(auth()->user()->followings as $following) { $following->pivot->created_at; // 获取关注时间 }
内容的提问来源于stack exchange,提问作者Jamie Holcomb
相关产品推荐
相关产品推荐

