I got a rather simple application where a user can report other users comments and recipes. I use a polymorphic relation to store the reports. Which works fine; however, I am now trying to get the offences that a user has made.
Getting users reports is not a problem, this can be done directly using user->reports()
but I would very much like to get the reports in which other people has reported said user. I can get this to work using either the hasManyThrough
relation or queries BUT only on one model at a time.
ex.
public function offenses() {
return $this->hasManyThrough('Recipe', 'Reports');
}
Or
->with('user.recipe.reports')
The problem is that my reportable object is not just recipes, it could be comments, images, etc. So instead of having to use multiple functions, the logical way would be to parse the relationship between hasManyThrough various parameters somehow.
Theoretically looking like this:
public function offenses() {
return $this->hasManyThrough(['Recipe', 'RecipeComments'], 'Reports');
}
Is this in any way possible? With some undocumented syntax? If not is there any clever workarounds/hacks?
Would an acceptable solution be to add another column on my report table and only add offender_id like this?
ID | User_id | Offender_id | Reportable_type | Reportable_id
That would mean I could just make a relation on my user model that connects offences through that column. But would this be considered redundant? Since I already have the offender through the reportable model?
Polymorphic Model
class Report extends Model {
public function reportable() {
return $this->morphTo();
}
public function User() {
return $this->belongsTo('App\User');
}
}
Recipe Model
class Recipe extends Model {
public function user() {
return $this->belongsTo('App\User');
}
public function reports() {
return $this->morphMany('App\Report', 'reportable');
}
}
Comment Model
class RecipeComment extends Model {
public function user() {
return $this->belongsTo('App\User');
}
public function reports() {
return $this->morphMany('App\Report', 'reportable');
}
}
Using your current model, you can receive all the reported models for a user by the following code:
$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]);
This is messy at best, because:
The best solution, is as you have figured out above:
Add an offender_id
column to your report
table.
It is cleaner and follows the DRY principle.
Typical Case Scenarios
Get all Recipe Comment reports for User
Report::where('offender_id','=',Auth::check()->id)
->where('reportable_type','=','RecipeComment')
->get();
Count offense by type for User
Report::where('offender_id','=',Auth::check()->id)
->grouBy('reportable_type')
->select(Db::raw('count(*)'),'reportable_type')
->get();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With