Laravel9如何通过模型实例动态实现associate关联绑定
实现结论
该需求完全可以实现,不需要修改User模型上已有的三个belongsTo关联定义,核心通过模型类名匹配对应关联方法,即可完成动态绑定。
具体实现方案
核心思路
- 先配置允许绑定到用户的模型白名单,建立「模型类 => User模型对应关联方法名」的映射关系,从入口拦截非法模型的绑定请求
- 根据传入的模型实例,从白名单中匹配到对应的关联方法名
- 查询目标用户实例后,动态调用关联方法完成associate绑定,最后持久化保存即可
代码实现
在UserRepository中编写如下代码:
<?php namespace App\Repositories; use App\Models\User; use App\Models\Distributor; use App\Models\Agency; use App\Models\Advertiser; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\ModelNotFoundException; use InvalidArgumentException; class UserRepository { /** * 允许绑定到用户的模型白名单 * 键为模型完整类名,值为User模型中对应的关联方法名 */ protected array $allowedBindModels = [ Distributor::class => 'distributor', Agency::class => 'agency', Advertiser::class => 'advertiser', ]; /** * 通用用户关联绑定方法 * @param int $id 用户ID * @param Model $modelInstance 待绑定的模型实例,仅支持白名单内的三类模型 * @return bool * @throws InvalidArgumentException 传入不支持绑定的模型时抛出 * @throws ModelNotFoundException 对应用户不存在时抛出 */ public function associate($id, Model $modelInstance) { $modelClass = $modelInstance::class; // 校验传入模型是否支持绑定 if (!isset($this->allowedBindModels[$modelClass])) { throw new InvalidArgumentException(sprintf( '模型[%s]不支持绑定到用户', $modelClass )); } // 查询目标用户,不存在直接抛错 $user = User::findOrFail($id); $relation = $this->allowedBindModels[$modelClass]; // 动态调用关联方法完成绑定并保存 return $user->{$relation}()->associate($modelInstance)->save(); } }
调用示例
原有三个仓库中的associateUser逻辑可以全部替换为对该通用方法的调用,示例如下:
// 绑定分销商 $userRepository->associate($userId, $distributor); // 绑定代理商 $userRepository->associate($userId, $agency); // 绑定广告主 $userRepository->associate($userId, $advertiser);
实现说明:不直接取模型短类名转小驼峰生成关联名,是因为显式配置白名单映射的可维护性更强,后续如果关联名调整、新增可绑定模型,只需修改
$allowedBindModels配置即可,避免隐式匹配带来的不可预知错误。
内容的提问来源于stack exchange,提问作者Bleu
相关产品推荐
相关产品推荐

