使用 Laravel Eloquents HasManyThrough 关系,通过多态性实现多重关系
Using Laravel Eloquents HasManyThrough relation with multiple relations through polymorphism
我得到了一个相当简单的应用程序,用户可以在其中报告其他用户的评论和食谱。我使用多态关系来存储报告。哪个工作正常;但是,我现在正在尝试获取用户的违规行为。
获得用户报告不是问题,这可以直接使用 user->reports()
完成,但我非常想获得其他人报告过该用户的报告。我可以使用 hasManyThrough
关系或一次只在一个模型上查询来使它工作。
例如
public function offenses() {
return $this->hasManyThrough('Recipe', 'Reports');
}
或
->with('user.recipe.reports')
问题是我的 reportable 对象不仅仅是食谱,它可能是评论、图像等。因此,不必使用多个函数,合乎逻辑的方法是解析之间的关系hasMany通过各种参数不知何故。
理论上是这样的:
public function offenses() {
return $this->hasManyThrough(['Recipe', 'RecipeComments'], 'Reports');
}
这有可能吗?使用一些未记录的语法?如果没有有什么妙招workarounds/hacks?
可能的解决方案?
acceptable 解决方案是否是在我的报告 table 上添加另一列,并且只添加 offender_id 像这样?
编号 | User_id | Offender_id | Reportable_type | Reportable_id
这意味着我可以在我的用户模型上建立一个关系,通过该列连接攻击。但这会被认为是多余的吗?因为我已经通过 reportable 模型得到了罪犯?
型号
多态模型
class Report extends Model {
public function reportable() {
return $this->morphTo();
}
public function User() {
return $this->belongsTo('App\User');
}
}
配方模型
class Recipe extends Model {
public function user() {
return $this->belongsTo('App\User');
}
public function reports() {
return $this->morphMany('App\Report', 'reportable');
}
}
评论模型
class RecipeComment extends Model {
public function user() {
return $this->belongsTo('App\User');
}
public function reports() {
return $this->morphMany('App\Report', '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]);
这充其量是混乱的,因为:
- 我们无法对结果进行排序,因为我们使用的是两个单独的数据库查询。
- 如果你有其他模特有汇报关系,那场面可想而知
最好的解决方案,正如你上面所想的那样:
将 offender_id
列添加到您的 report
table。
更干净,遵循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();
我得到了一个相当简单的应用程序,用户可以在其中报告其他用户的评论和食谱。我使用多态关系来存储报告。哪个工作正常;但是,我现在正在尝试获取用户的违规行为。
获得用户报告不是问题,这可以直接使用 user->reports()
完成,但我非常想获得其他人报告过该用户的报告。我可以使用 hasManyThrough
关系或一次只在一个模型上查询来使它工作。
例如
public function offenses() {
return $this->hasManyThrough('Recipe', 'Reports');
}
或
->with('user.recipe.reports')
问题是我的 reportable 对象不仅仅是食谱,它可能是评论、图像等。因此,不必使用多个函数,合乎逻辑的方法是解析之间的关系hasMany通过各种参数不知何故。
理论上是这样的:
public function offenses() {
return $this->hasManyThrough(['Recipe', 'RecipeComments'], 'Reports');
}
这有可能吗?使用一些未记录的语法?如果没有有什么妙招workarounds/hacks?
可能的解决方案?
acceptable 解决方案是否是在我的报告 table 上添加另一列,并且只添加 offender_id 像这样?
编号 | User_id | Offender_id | Reportable_type | Reportable_id
这意味着我可以在我的用户模型上建立一个关系,通过该列连接攻击。但这会被认为是多余的吗?因为我已经通过 reportable 模型得到了罪犯?
型号
多态模型
class Report extends Model {
public function reportable() {
return $this->morphTo();
}
public function User() {
return $this->belongsTo('App\User');
}
}
配方模型
class Recipe extends Model {
public function user() {
return $this->belongsTo('App\User');
}
public function reports() {
return $this->morphMany('App\Report', 'reportable');
}
}
评论模型
class RecipeComment extends Model {
public function user() {
return $this->belongsTo('App\User');
}
public function reports() {
return $this->morphMany('App\Report', '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]);
这充其量是混乱的,因为:
- 我们无法对结果进行排序,因为我们使用的是两个单独的数据库查询。
- 如果你有其他模特有汇报关系,那场面可想而知
最好的解决方案,正如你上面所想的那样:
将 offender_id
列添加到您的 report
table。
更干净,遵循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();