Laravel полон скрытых жемчужин, недокументированных или малоизвестных функций, опций и «хаков». Все что я нашёл, за время своей работы, я оформил в отдельную статью. Это третья часть, а начало здесь: Советы по Laravel. Часть 1 и Советы по Laravel. Часть 2.
Не совсем о Laravel, но… Никогда не запускайте composer update на боевом сервере — это медленно и может «сломать» репозиторий. лучше это сделать локально на вашем компьютере и отправить новый composer.lock в репозиторий и только после этого запустить composer install на сервере.
В Блейдовском 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
Вы можете назначить модель по умолчанию в отношениях belongsTo, чтобы избежать фатальных ошибок при ее вызове, например: {{ $post->user->name }}, если $post->user не существует.
/**
* Получить автора сообщения
*/
public function user()
{
return $this->belongsTo('App\User')->withDefault();
}
Вы можете загружать шаблоны Blade из массива при помощи view()->first($array), это загрузит только первый существющий. Полезно, когда у вас может быть пользовательский файл, не сгенерированный для одной из «тем», подстрахованный дефолтным вариантом.
return view()->first(['custom.admin', 'admin'], $data);
Вы можете привязать маршрут к модели, например так:
Route::get('api/users/{user}', function(App\User $user) { ... }
и но не только по полю ID. Если вы хотите, чтобы {user} использовал поле username, то сделайте в модели:
public function getRouteKeyName() {
return 'username';
}
Вы можете сделать redirect() не только на URL или конкретный маршрут, но и на конкретный метод конкретного контроллера, и даже передать параметры. Используйте это:
return redirect()->action('SomeController@method', ['param' => $value]);
Вы можете залогинить пользователя только на один запрос, используя метод Auth::once(). Ни сессии, ни куки использоваться не будут, что подразумевает, этот метод может быть полезен при создании API без сохранения состояния (stateless API).
if (Auth::once($credentials)) {
//
}
Вы можете использовать в Laravel жадную загрузку (Eager Loading) и указать какие точно поля вы хотите получить из отношений.
$users = App\Book::with('author:id,name')->get();
Вы можете провести валидацию дат правилами до и после (before/after) и задавать различные параметр, например: «tomorrow» (завтра), «now» (сегодня), «yesterday» (вчера). Например: ‘start_date’ => ‘after:now’. Под капотом у этого используется функция strtotime().
$rules = [
'start_date' => 'after:tomorrow',
'end_date' => 'after:start_date'
];
Если вы обновляете запись и хотите обновить поле updated_at в родительском отношении (например, вы добавляете новый комментарий и хотите обновить posts.updated_at), просто используйте свойство $touches = [‘post’]; в дочерней модели.
class Comment extends Model
{
/**
* Обновляем все отношения
*
* @var array
*/
protected $touches = ['post'];
}
Вместо такого маршрута:
Route::get('page', 'PageController@action');
Вы можете указать контроллер как класс:
Route::get('page', [\App\Http\Controllers\PageController::class, 'action']);
После этого вы сможете нажать «PageController» в PhpStorm и перейти непосредственно в Контроллер, вместо того, чтобы искать его вручную.
Никогда не используйте $model->relationship->field без проверки, существует ли объект отношений. Он может быть удален по любой причине, вне вашего кода, кем-то другим по задаче и т. д. Выполните if-else или {{ $model->relationship->field ?? » }} в Blade
Вы можете фильтровать по 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();
Если вы отправляете Laravel Notification и не указываете тему в toMail(), то темой становится имя нотификационного класса с переводом ВерблюжьегоРегистра в пробелы.
Итак, если у вас есть:
class UserRegistrationEmail extends Notification { // ...
То вы получите электронное письмо с темой «User Registration Email»
Если вы хотите узнать, у каких из ваших пакетов в 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
Если вы хотите указать дополнительную логику для отсутствующих маршрутов, то вместо того, чтобы выбрасывать 404-ую страницу, вы можете создать для неё специальный маршрут, разместив его самым последним:
Route::group(['middleware' => ['auth'], 'prefix' => 'admin', 'as' => 'admin.'], function () {
Route::get('/home', 'HomeController@index');
Route::resource('tasks', 'Admin\TasksController');
});
// Еще какие-то маршруты....
Route::fallback(function() {
return 'Хм… Почему ты оказался здесь?';
});
Это очень просто — добавьте свой собственный метод в 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); ?>";
});
}
Если у вас есть отношение 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
Если вы хотите сгруппировать результат по некоторому условию, которое не является полем в вашей базе данных, то вы можете сделать это через замыкание. Например, если вы хотите сгруппировать пользователей по дате регистрации:
$users = User::all()->groupBy(function($item) {
return $item->created_at->format('Y-m-d');
}
Обратите внимание: это делается в Коллекции, поэтому выполняется ПОСЛЕ того, как результаты получены из базы данных.
Если вы не уверены, существует ли шаблон 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
Перевод: Demiurge Ash