多对多 多态
//用户模型
class User extends Authenticatable
{
use HasFactory, Notifiable, HasApiTokens, DateFormat, Filterable;
protected $table = 'users';
//关注的用户
public function followUser()
{
return $this->morphedByMany($this, 'followable', 'followable', 'user_id', 'followable_id')
->withTimestamps();
}
//关注的专家
public function followExpert()
{
return $this->morphedByMany('App\Models\Expert', 'followable', 'followable', 'user_id', 'followable_id')
->withTimestamps();
}
//关注的主播
public function followAnchors()
{
return $this->morphedByMany('App\Models\Anchors', 'followable', 'followable', 'user_id', 'followable_id')
->withTimestamps();
}
//关注的作者
public function followAuthors()
{
return $this->morphedByMany('App\Models\Authors', 'followable', 'followable', 'user_id', 'followable_id')
->withTimestamps();
}
//关注者,即主动关注用户的人
public function followerUser()
{
return $this->morphToMany($this, 'followable', 'followable', 'followable_id', 'user_id')
->withTimestamps();
}
}
//专家模型
class Expert extends BaseModel
{
protected $table = 'expert';
//关注者,即主动关注专家的人
public function followerUser()
{
return $this->morphToMany('App\Models\User', 'followable', 'followable', 'followable_id', 'user_id')
->withTimestamps();
}
}
//主播模型
class Anchors extends BaseModel
{
protected $table = 'anchors';
//关注者,即主动关注主播的人
public function followerUser()
{
return $this->morphToMany('App\Models\User', 'followable', 'followable', 'followable_id', 'user_id')
->withTimestamps();
}
}
//作者模型
class Authors extends BaseModel
{
protected $table = 'authors';
//关注者,即主动关注作者的人
public function followerUser()
{
return $this->morphToMany('App\Models\User', 'followable', 'followable', 'followable_id', 'user_id')
->withTimestamps();
}
}
//控制器代码
class FollowController extends Controller
{
//关注/取消
public function toggle(Request $request)
{
$request->validate([
'followable_id'=>'bail|required|integer',
'followable_type'=>'bail|required|string|in:user,expert,authors,anchors'
]);
//利用可变方法动态创建模型对象
$type_model = "\App\Models\\".ucfirst($request->input('followable_type'));
$follow = $type_model::findOrFail($request->input('followable_id'));
//调用关注人关联和toggle方法动态切换关注和取消关注
$result = $follow->followerUser()->toggle($request->user()->id);
if ($result['attached']) {
$status = 1;
} else {
$status = 0;
}
return response()->json(compact('status'));
}
//关注列表
public function index(Request $request)
{
$request->validate([
'followable_type'=>'bail|required|string|in:user,expert,authors,anchors'
]);
//根据类型可变方法动态加载我的关注关联,实现4个类型列表
$followable_funname = 'follow'.ucfirst($request->input('followable_type'));
$builder = $request->user()->$followable_funname();
if ($request->input('followable_type') == 'user') {
$builder->select('users.id', 'name', 'avatar');
} elseif ($request->input('followable_type') == 'expert') {
$builder->select('expert.id', 'name', 'nickname', 'photo', 'tags')
->where('is_show', 1);
} elseif ($request->input('followable_type') == 'authors') {
$builder->select('authors.id', 'authors.user_id', 'introduction')
->with([
'user'=>function ($query) {
$query->select('id', 'name', 'avatar');
}
])
->where('status', 1);
} elseif ($request->input('followable_type') == 'anchors') {
$builder->select('anchors.id', 'anchors.user_id', 'games_type')
->with([
'user'=>function ($query) {
$query->select('id', 'name', 'avatar');
}
])
->where('status', 1);
}
//按关注时间排序
$followed = $builder->orderBy('followable.created_at', 'desc')
->forPage($request->input('page', 1), $request->input('per_page', 1))
->get();
return $followed;
}
}
这种抽象的写法可以减少接口数量,要看具体需求是否合适