Laravel полон скрытых жемчужин, недокументированных или малоизвестных функций, опций и «хаков». Все что я нашёл, за время своей работы, я оформил в отдельную статью. Это третья часть, а начало здесь: Советы по Laravel. Часть 1 и Советы по Laravel. Часть 2.
Совет 41. Когда (НЕ НУЖНО) запускать «composer update»
Не совсем о Laravel, но… Никогда не запускайте composer update на боевом сервере — это медленно и может «сломать» репозиторий. лучше это сделать локально на вашем компьютере и отправить новый composer.lock в репозиторий и только после этого запустить composer install на сервере.
Совет 42. Двухуровневая переменная $loop в Blade
В Блейдовском foreach вы можете использовать переменную $loop даже в двухуровневом цикле для получения родительской переменной.
@foreach ($users as $user) @foreach ($user->posts as $post) @if ($loop->parent->first) This is first iteration of the parent loop. @endif @endforeach @endforeach
Совет 43. Как избежать ошибки в {{ $post->user->name }}, если пользователь удален?
Вы можете назначить модель по умолчанию в отношениях belongsTo, чтобы избежать фатальных ошибок при ее вызове, например: {{ $post->user->name }}, если $post->user не существует.
/** * Получить автора сообщения */ public function user() { return $this->belongsTo('App\User')->withDefault(); }
Совет 44. Загрузка массива шаблонов
Вы можете загружать шаблоны Blade из массива при помощи view()->first($array), это загрузит только первый существющий. Полезно, когда у вас может быть пользовательский файл, не сгенерированный для одной из «тем», подстрахованный дефолтным вариантом.
return view()->first(['custom.admin', 'admin'], $data);
Совет 45. Привязка маршрута к модели: Определите ключ
Вы можете привязать маршрут к модели, например так:
Route::get('api/users/{user}', function(App\User $user) { ... }
и но не только по полю ID. Если вы хотите, чтобы {user} использовал поле username, то сделайте в модели:
public function getRouteKeyName() { return 'username'; }
Совет 46. Перенаправление на определенный метод контроллера
Вы можете сделать redirect() не только на URL или конкретный маршрут, но и на конкретный метод конкретного контроллера, и даже передать параметры. Используйте это:
return redirect()->action('SomeController@method', ['param' => $value]);
Совет 47. А вы знаете об Auth::once()?
Вы можете залогинить пользователя только на один запрос, используя метод Auth::once(). Ни сессии, ни куки использоваться не будут, что подразумевает, этот метод может быть полезен при создании API без сохранения состояния (stateless API).
if (Auth::once($credentials)) { // }
Совет 48. Жадная загрузка с точными полями
Вы можете использовать в Laravel жадную загрузку (Eager Loading) и указать какие точно поля вы хотите получить из отношений.
$users = App\Book::with('author:id,name')->get();
Совет 49. Проверяйте даты словами «now» или «yesterday»
Вы можете провести валидацию дат правилами до и после (before/after) и задавать различные параметр, например: «tomorrow» (завтра), «now» (сегодня), «yesterday» (вчера). Например: ‘start_date’ => ‘after:now’. Под капотом у этого используется функция strtotime().
$rules = [ 'start_date' => 'after:tomorrow', 'end_date' => 'after:start_date' ];
Совет 50. Легко обновляем родительское updated_at
Если вы обновляете запись и хотите обновить поле updated_at в родительском отношении (например, вы добавляете новый комментарий и хотите обновить posts.updated_at), просто используйте свойство $touches = [‘post’]; в дочерней модели.
class Comment extends Model { /** * Обновляем все отношения * * @var array */ protected $touches = ['post']; }
Совет 51. Быстрая навигация из Маршрутов в Контроллер
Вместо такого маршрута:
Route::get('page', 'PageController@action');
Вы можете указать контроллер как класс:
Route::get('page', [\App\Http\Controllers\PageController::class, 'action']);
После этого вы сможете нажать «PageController» в PhpStorm и перейти непосредственно в Контроллер, вместо того, чтобы искать его вручную.
Совет 52. Всегда проверяйте, существует ли Отношение
Никогда не используйте $model->relationship->field без проверки, существует ли объект отношений. Он может быть удален по любой причине, вне вашего кода, кем-то другим по задаче и т. д. Выполните if-else или {{ $model->relationship->field ?? » }} в Blade
Совет 53. Не фильтруйте по NULL в Коллекциях
Вы можете фильтровать по NULL в Eloquent, но если вы фильтруете коллекцию — делайте это по пустой строке, в этом поле больше нет нуля.
// Это работает $messages = Message::where('read_at is null')->get(); // Не работает - вернет 0 сообщений $messages = Message::all(); $unread_messages = $messages->where('read_at is null')->count(); // Это работает $unread_messages = $messages->where('read_at', '')->count();
Совет 54. Дефолтная тема письма в уведомлениях Laravel
Если вы отправляете Laravel Notification и не указываете тему в toMail(), то темой становится имя нотификационного класса с переводом ВерблюжьегоРегистра в пробелы.
Итак, если у вас есть:
class UserRegistrationEmail extends Notification { // ...
То вы получите электронное письмо с темой «User Registration Email»
Совет 55. Composer: проверка новых версий
Если вы хотите узнать, у каких из ваших пакетов в composer.json вышли новые версии, просто запустите «composer outdated». Вы получите полный список со всей информацией, например:
phpdocumentor/type-resolver 0.4.0 0.7.1 phpunit/php-code-coverage 6.1.4 7.0.3 Library that provides collection, processing, and rende... phpunit/phpunit 7.5.9 8.1.3 The PHP Unit Testing framework. ralouphie/getallheaders 2.0.5 3.0.3 A polyfill for getallheaders. sebastian/global-state 2.0.0 3.0.0 Snapshotting of global state
Совет 56. Резервный маршрут — когда не найдено никакого другого маршрута
Если вы хотите указать дополнительную логику для отсутствующих маршрутов, то вместо того, чтобы выбрасывать 404-ую страницу, вы можете создать для неё специальный маршрут, разместив его самым последним:
Route::group(['middleware' => ['auth'], 'prefix' => 'admin', 'as' => 'admin.'], function () { Route::get('/home', 'HomeController@index'); Route::resource('tasks', 'Admin\TasksController'); }); // Еще какие-то маршруты.... Route::fallback(function() { return 'Хм… Почему ты оказался здесь?'; });
Совет 57. Создайте свою собственную Blade команду
Это очень просто — добавьте свой собственный метод в app/Providers/AppServiceProvider.php:
Например, если вы хотите заменять <br> на перевод строки:
<textarea>@br2nl($post->post_text)</textarea>
Добавьте её создание в метод boot() в AppServiceProvider:
public function boot() { Blade::directive('br2nl', function ($string) { return "<?php echo preg_replace('/\<br(\s*)?\/?\>/i', \"\n\", $string); ?>"; }); }
Совет 58. Используйте withCount() для подсчета дочерних записей
Если у вас есть отношение hasMany() и вы хотите подсчитать количество «дочерних» записей, не нужно писать дополнительный запрос.
Например, если у вас есть записи и комментарии в модели User, сделайте с помощью withCount():
public function index() { $users = User::withCount(['posts', 'comments'])->get(); return view('users', compact('users')); }
А затем, в файле Blade, вы получите доступ к этим числам при помощи свойства [relationship]_count:
@foreach ($users as $user) <tr> <td>{{ $user->name }}</td> <td class="text-center">{{ $user->posts_count }}</td> <td class="text-center">{{ $user->comments_count }}</td> </tr> @endforeach
Совет 59. Используйте groupBy для коллекций с пользовательской функцией обратного вызова
Если вы хотите сгруппировать результат по некоторому условию, которое не является полем в вашей базе данных, то вы можете сделать это через замыкание. Например, если вы хотите сгруппировать пользователей по дате регистрации:
$users = User::all()->groupBy(function($item) { return $item->created_at->format('Y-m-d'); })
Обратите внимание: это делается в Коллекции, поэтому выполняется ПОСЛЕ того, как результаты получены из базы данных.
Совет 60. Команды Blade: IncludeIf, IncludeWhen, IncludeFirst
Если вы не уверены, существует ли шаблон Blade, то вы можете использовать следующие команды:
Загрузит заголовок, если шаблон Blade существует
@includeIf(‘partials.header’)
Загрузит заголовок только для пользователя с role_id равным 1
@includeWhen(auth()->user()->role_id == 1, ‘partials.header’)
Попытается загрузить adminlte.header, если не найдет, то загрузит default.header
@includeFirst(‘adminlte.header’, ‘default.header’)
Автор: Povilas Korop
Перевод: Алексей Широков
Наш Телеграм-канал — следите за новостями о Laravel.