I have products which have also comments. This comments can be voted and comments can also have child comments. The comments get loaded via eager loading $with
which is defined in the product
model and the child comments get as well loaded via eager loading which is also defined in the comments
model. The child comments can also be voted (but don't have any child comments).
Product.php (Model)
namespace App;
class Product extends Model
{
/**
* @Protected_variables
*/
protected $with = [
'comments',
'user'
];
/**
* @Relationships
*/
public function user()
{
return $this->belongsTo('App\User');
}
public function comments()
{
return $this->morphMany('App\Comment', 'commentable');
}
}
Comment.php (Model)
namespace App;
class Comment extends Model
{
/**
* @Protected_variables
*/
protected $with = [
'children',
'user'
];
public function user()
{
return $this->belongsTo('App\User');
}
public function children()
{
return $this->hasMany('App\ChildComment');
}
public function likes()
{
return $this->belongsToMany('App\User', 'comments_likes', 'comment_id', 'user_id')->withTimestamps();
}
}
I use route model binding to receive my product in the ProductController.
Here is an example of the route Route::get('/product/{product}', ['as' => 'product.show', 'uses' => 'ProductController@show']);
and the function show
:
ProductController@show:
public function show(Product $product, Request $request)
{
if(request()->wantsJson()){
return response()->json([
'product' => $product
]);
}
return view('pages.productDetails')->with([
'product' => $product
]);
}
In the show
function I can now access the comments
of the product, as well as the child comments
of the comments
and all the other relations which get loaded via the $with
attribute in the models.
Now comes questions. As I already have loaded the relationship, how can I either 1. sort them now or 2. pass the sort arguments to the model to get a sorted relationship back?
When I write dd($product->comments->sortByDesc('created_at')->toArray());
I get my product
with the comments
which are sorted by created_at
. That's what I want. But I cannot assign the sorted collection to the product
collection like this $product->comments = $product->comments->sortByDesc('created_at');
because $product->comments
is @property-read
.
I also don't want to do another query and pass this $product->comments()>orderBy('created_at', 'desc')->get();
to my response. Because then the eager loading in the model redundant.
Is there a way to 1. either sort the relationship collection or 2. pass the sort arguments to the model to get a sorted relationship back?
I actually want to stick to my route binding model. I know I could pass the sorting arguments and product id
as arguments and then execute it via get
. But is there a solution to do that within the model eager loading?
Also, please note I want to sort my comments also by likes and the count of child comments they have. I don't want to sort them only by date, so I need to pass the sort argument to the model when choosing a solution for number 2.
Kind regards!