#php #laravel #sorting #eloquent #eager-loading
#php #laravel #сортировка #красноречивый #загрузка в режиме ожидания
Вопрос:
У меня есть продукты, у которых также есть комментарии. За эти комментарии можно проголосовать, и комментарии также могут иметь дочерние комментарии. Комментарии загружаются с помощью быстрой загрузки, $with
которая определена в product
модели, и дочерние комментарии также загружаются с помощью быстрой загрузки, которая также определена в comments
модели. За дочерние комментарии также можно проголосовать (но у них нет дочерних комментариев).
Product.php (Модель)
namespace App;
class Product extends Model
{
/**
* @Protected_variables
*/
protected $with = [
'comments',
'user'
];
/**
* @Relationships
*/
public function user()
{
return $this->belongsTo('AppUser');
}
public function comments()
{
return $this->morphMany('AppComment', 'commentable');
}
}
Comment.php (Модель)
namespace App;
class Comment extends Model
{
/**
* @Protected_variables
*/
protected $with = [
'children',
'user'
];
public function user()
{
return $this->belongsTo('AppUser');
}
public function children()
{
return $this->hasMany('AppChildComment');
}
public function likes()
{
return $this->belongsToMany('AppUser', 'comments_likes', 'comment_id', 'user_id')->withTimestamps();
}
}
Я использую привязку модели маршрута для получения моего продукта в ProductController.
Вот пример маршрута Route::get('/product/{product}', ['as' => 'product.show', 'uses' => 'ProductController@show']);
и функции 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
]);
}
В show
функции я теперь могу получить доступ к comments
продукту, а также child comments
к comments
и ко всем другим отношениям, которые загружаются через $with
атрибут в моделях.
Теперь возникают вопросы. Поскольку я уже загрузил связь, как я могу либо 1. отсортировать их сейчас, либо 2. передать аргументы сортировки модели, чтобы получить обратно отсортированную связь?
Когда я пишу, dd($product->comments->sortByDesc('created_at')->toArray());
я получаю свой product
с comments
которые отсортированы по created_at
. Это то, что я хочу. Но я не могу назначить отсортированную коллекцию product
коллекции, подобной этой, $product->comments = $product->comments->sortByDesc('created_at');
потому что $product->comments
это @property-read
.
Я также не хочу выполнять еще один запрос и передавать это $product->comments()>orderBy('created_at', 'desc')->get();
в свой ответ. Потому что тогда нетерпеливая загрузка в модель избыточна.
Есть ли способ 1. либо отсортировать коллекцию отношений, либо 2. передать аргументы сортировки модели, чтобы получить обратно отсортированную связь?
На самом деле я хочу придерживаться своей модели привязки маршрута. Я знаю, что мог бы передать аргументы сортировки и продукт id
в качестве аргументов, а затем выполнить его через get
. Но есть ли решение сделать это в рамках модели, ожидающей загрузки?
Кроме того, пожалуйста, обратите внимание, что я хочу сортировать свои комментарии также по лайкам и количеству дочерних комментариев, которые у них есть. Я не хочу сортировать их только по дате, поэтому мне нужно передать аргумент сортировки модели при выборе решения для номера 2.
С наилучшими пожеланиями!
Ответ №1:
Вы можете установить порядок по умолчанию для отношения или создать для него совершенно новое отношение.
public function comments()
{
return $this->morphMany('AppComment', 'commentable')->orderBy('created_at', 'desc');
}
Редактировать: если вы решите использовать порядок по умолчанию и вам нужно удалить этот другой запрос, который вы можете использовать reorder()
см. https://laravel.com/docs/7.x/queries#ordering-grouping-limit-and-offset
Комментарии:
1. Но теперь это порядок по умолчанию, как вы говорите. Как я могу передать аргументы сортировки? Я хочу отсортировать по
comment
дате, поcomment
лайкам и по количествуchild comments
наcomment