В Ларавеле есть удобный хелпер-метод: firstOrFail()
, позволяющий получить по заданному запросу из БД первую найденную модель, либо вывалиться в 404, если моделей не найдено. Удобство в том, что использование хелпера позволяет избавиться от необходимости отдельно проверять наличие результата.
$page = ContentPage::where('slug', $slug)->firstOrFail();
вместо
$page = ContentPage::where('slug', $slug)->take(1)->get(); if ($page->isEmpty()) abort(404);
Очевидно, первый вариант лаконичнее и читабельнее.
Так вот, хотелось бы, чтобы то же самое можно было делать, когда мы хотим загрузить несколько моделей, или уйти в 404, если не нашли ни одной. То есть чтобы был хелпер-метод getOrFail()
, который делает то же, что и firstOrFail, но возвращает несколько моделей.
Для этого можно написать макрос. В Laravel есть такой трейт, Macroable, и классы, которые его используют, можно расширять своими макро-методами. Расширим класс Illuminate\Database\Eloquent\Builder
. Добавим в AppServiceProvider
:
public function boot(): void { // ... Builder::macro('getOrFail', function () { return tap( $this->get(), fn ($results) => abort_unless($results->count(), 404) ); }); }
теперь мы можем писать, например, так:
$contentPages = ContentPage::where('slug', $slug)->getOrFail();
и получим либо коллекцию моделей ContentPage, либо ошибку 404, без необходимости отдельно проверять, что коллекция не пустая.
P.S. Да, slug
в данном примере не уникальный, может быть несколько моделей с одинаковым slug
. Вместо этого у меня есть уникальный ключ ['slug', 'language']
.