You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 08:20:01