Laravel中如何通过API请求自动识别多态关联模型并保存Like记录
解决Laravel多态点赞的无分支实现方案
我来给你几个Laravel原生的简洁实现思路,完全不用写一堆if/switch分支,既符合框架设计风格,又能让代码保持干净。
方案一:多态路由 + 路由模型绑定(推荐,RESTful风格)
这是最符合Laravel设计哲学的方案,利用框架自带的路由模型绑定能力,直接让路由自动识别并注入对应的模型实例。
步骤1:定义多态路由
把原来的单一端点改成多态路由,这样不同模型的点赞请求通过不同的URL路径区分:
// routes/api.php Route::post('/{likeable}/likes', [LikeController::class, 'store']);
访问时的URL示例:
- 给Video点赞:
POST /api/videos/1/likes - 给Post点赞:
POST /api/posts/2/likes
步骤2:修改控制器方法
直接在方法参数中注入Model类型的变量,Laravel会自动根据URL解析出对应的Video或Post实例:
use Illuminate\Database\Eloquent\Model; use App\Models\Video; use App\Models\Post; public function store(StoreLikeRequest $request, Model $likeable) { // 安全校验:只允许指定的模型类型(避免恶意请求) abort_unless(in_array(get_class($likeable), [Video::class, Post::class]), 403, 'Invalid model type'); // 调用通用的点赞处理Action,无需区分模型 $result = (new StoreLikeAction($likeable, $request))->handle(); return $result; }
步骤3:简化请求验证
此时StoreLikeRequest只需要验证点赞相关的业务字段(比如用户身份),完全不用处理模型类型判断:
public function rules() { return [ // 示例:如果是登录用户点赞,可通过auth()获取,无需传参;如果需要其他字段,在这里验证 // 'some_field' => 'required|string', ]; }
方案二:单一端点 + 请求类模型解析(兼容原有端点)
如果你不想修改现有路由,想保留/api/like/store这种单一端点,可以在请求类里封装模型解析逻辑,用Laravel 8+支持的match表达式替代if/switch,代码依然简洁。
步骤1:更新请求类规则和模型解析方法
在StoreLikeRequest里添加type和id的验证,并新增一个自定义方法获取关联模型:
use App\Models\Video; use App\Models\Post; public function rules() { return [ 'type' => 'required|string|in:video,post', // 限制允许的模型类型 'id' => 'required|integer|exists:'.$this->input('type').'s,id', // 验证ID存在对应表中 // 其他业务字段验证... ]; } // 自定义方法:返回解析后的模型实例 public function getLikeableModel() { $modelClass = match($this->input('type')) { 'video' => Video::class, 'post' => Post::class, }; return $modelClass::findOrFail($this->input('id')); }
步骤2:修改控制器方法
直接调用请求类的自定义方法获取模型,剩下的逻辑完全通用:
public function store(StoreLikeRequest $request) { $likeable = $request->getLikeableModel(); $result = (new StoreLikeAction($likeable, $request))->handle(); return $result; }
通用点赞Action的优化
不管用哪种方案,都可以把点赞逻辑封装成通用的Action,利用多态关联自动处理模型类型存储:
// StoreLikeAction.php public function __construct(protected Model $likeable, protected StoreLikeRequest $request) {} public function handle() { $userId = auth()->id(); // 假设是登录用户点赞 // 避免重复点赞 if ($this->likeable->likes()->where('user_id', $userId)->exists()) { return response()->json(['message' => '您已经点过赞了'], 409); } // 多态关联会自动填充likeable_type和likeable_id字段 $like = $this->likeable->likes()->create([ 'user_id' => $userId, // 其他点赞相关字段... ]); return response()->json($like, 201); }
这样整个流程下来,完全看不到if/switch分支,代码既简洁又符合Laravel的设计风格,扩展性也很强——以后如果要给其他模型加点赞功能,只需要在路由允许的模型列表里添加对应类,或者在请求的type规则里新增选项即可。
内容的提问来源于stack exchange,提问作者Tim
相关产品推荐
相关产品推荐

