使用Laravel-Eloquets-HasMany通过多态性来突破具有多重关系的关系



我得到了一个相当简单的应用程序,用户可以在其中报告其他用户的评论和食谱。我使用多态关系来存储报告。哪种效果很好;然而,我现在正试图得到一个用户犯下的罪行。

获取用户报告不是问题,这可以直接使用user->reports()来完成,但我非常希望获得其他人报告该用户的报告。我可以使用hasManyThrough关系或查询来实现这一点,但一次只能对一个模型进行查询。

例如

public function offenses() {
return $this->hasManyThrough('Recipe', 'Reports');
}

->with('user.recipe.reports')

问题是,我的可报告对象不仅仅是食谱,它可能是注释、图像等。因此,不必使用多个函数,逻辑方法是通过各种参数解析hasMany之间的关系。

理论上看起来是这样的:

public function offenses() {
return $this->hasManyThrough(['Recipe', 'RecipeComments'], 'Reports');
}

这有可能吗?使用一些未记录的语法?如果没有,还有什么聪明的变通方法/窍门吗?

可能的解决方案

一个可以接受的解决方案是在我的报告表上添加另一列,然后只添加这样的offender_id吗?

ID|User_ID|罪犯_ID|Reportable_type|Reportable_ID

这意味着我可以在我的用户模型上建立一个关系,通过该栏将犯罪行为联系起来。但这会被认为是多余的吗?既然我已经让罪犯通过可报告模型了?


型号

多态模型

class Report extends Model {
public function reportable() {
return $this->morphTo();
}
public function User() {
return $this->belongsTo('AppUser');
}
}

配方模型

class Recipe extends Model {
public function user() {
return $this->belongsTo('AppUser');
}
public function reports() {
return $this->morphMany('AppReport', 'reportable');
}
}

注释模型

class RecipeComment extends Model {   
public function user() {
return $this->belongsTo('AppUser');
}
public function reports() {
return $this->morphMany('AppReport', 'reportable');
}
}

使用当前模型,您可以通过以下代码接收用户报告的所有模型:

$recipeCommentReport = RecipeComment::whereHas('reports',function($q){
return $q->where('user_id','=',Auth::user()->id) 
});
$recipeReport = Recipe::whereHas('reports',function($q){
return $q->where('user_id','=',Auth::user()->id) 
});
//Get all reports into one
$reports = $recipeReport->merge([$recipeCommentReport]);

这充其量是一团糟,因为:

  1. 我们无法对结果进行排序,因为我们使用了两个独立的数据库查询
  2. 如果你有其他模型有报告关系,想象一下混乱

最好的解决方案,正如您上面所了解的:

offender_id列添加到report表中。

它更清洁,并遵循DRY原理。

典型案例场景

获取用户的所有配方注释报告

Report::where('offender_id','=',Auth::check()->id)
->where('reportable_type','=','RecipeComment')
->get();

按用户的类型计算攻击

Report::where('offender_id','=',Auth::check()->id)
->grouBy('reportable_type')
->select(Db::raw('count(*)'),'reportable_type')
->get();

最新更新