Привязка модели маршрута Laravel с отсортированной загрузкой в режиме ожидания?

#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