Как упорядочить результаты запросов в Eloquent

Eloquent – это объектно-реляционный преобразователь (ORM), который включен в структуру Laravel по умолчанию. В этой серии статей вы узнаете, как делать запросы к базе данных и как работать с отношениями в Laravel Eloquent. Также вы сможете попрактиковаться на примерах: мы попробуем улучшить демо-приложение с помощью новых моделей и отношений.

Примечание: Все мануалы данной серии можно найти по тегу Laravel Eloquent.

В предыдущей части этой серии вы узнали, как извлечь записи БД с помощью метода all() в модели Eloquent. Вспомните, как мы использовали метод sortDesc() для сортировки записей в порядке убывания.

Метод sortDesc() является частью класса Collection – мощного служебного класса Laravel, который работает как улучшенная версия массивов PHP. Вместо того чтобы упорядочивать результаты в самом запросе к БД, этот метод инвертирует порядок коллекции (то есть последний элемент появляется первым в коллекции). Такой подход хорошо работает в небольших наборах результатов, однако не поддерживает сортировку результатов в самом запросе к базе данных (а значит, не обеспечивает достаточного уровня гибкости).

Чтобы отсортировать результаты в запросе к БД, нужно использовать метод orderBy() и указать поле таблицы, которое вы хотите использовать в качестве критерия для упорядочивания. Такой подход дает больше гибкости при построении запроса, и в итоге он сможет извлекать из БД только те результаты, которые вам нужны.

Давайте изменим код в файле routes/web.php, чтобы отобразить результаты, упорядоченные на основе поля таблицы created_at (от самых новых к самым старым).

Примечание: Eloquent управляет полями created_at и updated_at, если вы включаете определение timestamps() в миграцию таблицы. Вы не должны обновлять эти поля вручную, но можете использовать их для сортировки и фильтрации запросов.

Откройте файл в редакторе кода:

routes/web.php

Вот как он выглядит сейчас:

<?php

use Illuminate\Support\Facades\Route;
use App\Models\Link;
use App\Models\LinkList;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    $links = Link::all()->sortDesc();
    return view('index', [
        'links' => $links,
        'lists' => LinkList::all()
    ]);
});

Route::get('/{slug}', function ($slug) {
    $list = LinkList::where('slug', $slug)->first();
    if (!$list) {
        abort(404);
    }

    return view('index', [
        'list' => $list,
        'links' => $list->links,
        'lists' => LinkList::all()
    ]);
})->name('link-list');

Обратите внимание, маршрут /{slug}, отвечающий за формирование списка ссылок по слагам, в настоящее время не использует никаких методов сортировки. Ссылки извлекаются через переменную list при помощи отношения, определенного в модели LinkList.

Если сейчас вы добавите в список несколько ссылок, запрос по умолчанию выведет результаты, упорядоченные от старых к новым. Для изменения порядка коллекции в вызове $list->links вы можете использовать метод sortDesc(), однако метод orderBy() обеспечивает большую гибкость и в дальнейшем позволяет включать дополнительные условия фильтрации. Вы можете связать этот метод с вызовом where() для получения еще более подробных результатов.

Замените выделенную строку в предыдущем примере кода следующей строкой:

'links' => $list->links()->orderBy('created_at', 'desc')->get(),

Обратите внимание, на этот раз мы вызываем встроенный сборщик запросов через метод $list->links(), который относится к методу отношений (их мы определили в классе LinkList). Это не то же самое, что вызвать $ list->links в качестве свойства класса (без скобок) – это вызывает в модели метод для выборки всех ссылок, связанных с заданным списком.

Вот как должен выглядеть готовый файл routes/web.php, когда вы закончите его редактировать:

<?php

use Illuminate\Support\Facades\Route;
use App\Models\Link;
use App\Models\LinkList;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    $links = Link::all()->sortDesc();
    return view('index', [
        'links' => $links,
        'lists' => LinkList::all()
    ]);
});

Route::get('/{slug}', function ($slug) {
    $list = LinkList::where('slug', $slug)->first();
    if (!$list) {
        abort(404);
    }

    return view('index', [
        'list' => $list,
        'links' => $list->links()->orderBy('created_at', 'desc')->get(),
        'lists' => LinkList::all()
    ]);
})->name('link-list');

Сохраните и закройте файл. Теперь добавьте пару новых ссылок, используя Artisan-команду link:new. Вы можете использовать стандартный список:

docker-compose exec app php artisan link:new

Команда вернет такой результат:

Link URL:
 > https://laravel.com/docs/8.x/eloquent

 Link Description:
 > Laravel Eloquent Docs

 Link List (leave blank to use default):
 >

New Link:
https://laravel.com/docs/8.x/eloquent - Laravel Eloquent Docs
Listed in: default

 Is this information correct? (yes/no) [no]:
 > yes

Saved.

Если вы перезагрузите страницу с вашим списком ссылок, вы увидите, что теперь ссылки упорядочены от самых новых до самых старых.

Аналогичным образом можно упорядочить ссылки в алфавитном порядке (по описанию ссылки): для этого вам придется изменить строку в файле routes/web.php, чтобы использовать другое поле таблицы в вызове метода. Эта строка должна выглядеть следующим образом:

'links' => $list->links()->orderBy('description', 'asc')->get(),

Если вы обновите страницу после такого изменения, вы увидите, что теперь ссылки упорядочены в алфавитном порядке.

В следующем мануале этой серии вы узнаете, как узнать общее количество извлеченных результатов с помощью запроса Laravel Eloquent.

Tags: , , ,

Добавить комментарий