Laravel 5+
Подсказки при работе с Laravel
Автор: Povilas Korop Перевод: itmathrepetitor.ru
Подсказка 1. Invoke-контроллер
Начиная с Laravel 5.6.28 для создания контроллера с одним единственным методом можно использовать __invoke() или создать специальный invoke-контроллер.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<?php namespace App\Http\Controllers; use App\User; use App\Http\Controllers\Controller; class ShowProfile extends Controller { /** * Показ профиля данного пользователя. * * @param int $id * @return Response */ public function __invoke($id) { return view('user.profile', ['user' => User::findOrFail($id)]); } } |
Роут:
1 |
Route::get('user/{id}', 'ShowProfile'); |
Artisan-команда для генерация такого контроллера:
1 |
php artisan make:controller ShowProfile --invokable |
Подсказка 2. Беззнаковое целое
В миграциях при объявлении внешнего ключа используйте unsignedInteger() или integer()->unsigned() вместо integer() во избежание mysql-ошибки.
1 2 3 4 5 |
Schema::create('employees', function (Blueprint $table) { $table-> unsignedInteger ('company_id'); $table->foreign('company_id')->references('id')->on('companies'); // ... }); |
Подсказка 3. Сортировка в связях Eloquent
Вы можете применить orderBy() прямо в связях Eloquent:
1 2 3 4 5 6 7 8 |
public function products() { return $this->hasMany(Product::class); } public function productsByName() { return $this->hasMany(Product::class)->orderBy('name'); } |
Подсказка 4. Последовательность миграций
Миграции выполняются в алфавитном порядке названий файлов. Поэтому для изменения порядка можно изменить начало названия файла. Например, 2020_08_04_070443_create_posts_table.php выполнится раньше, чем 2020_08_05_0704433_create_invoices_table.php. После переименования 2020_08_05_0704433_create_invoices_table.php в 2020_08_04_000001_create_invoices_table.php порядок выполнения изменится.
Подсказка 5. Прямой код SQL
Можно вставлять sql-код напрямую в цепочки запросов eloquent (или DB::). Например,
1 |
Product::groupBy('category_id')->havingRaw('COUNT(*) > 1')->get(); |
1 2 3 4 |
\DB::table('users')->update([ 'penalties' => \DB::raw('penalties+1'), 'position' => \DB::raw('position+2'), ]); |
Подсказка 6. Переменная $loop для foreach в blade
Внутри цикла можно определять, является ли итерация первой или последней. Также можно определить номер итерации ($loop->count).
1 2 3 4 5 6 7 8 9 |
@foreach ($users as $user) @if ($loop->first) Это первая итерация @endif @if ($loop->last) Это последняя итерация @endif <p>This is user {{ $user->id }}</p> @endforeach |
Подсказка 7. Сравнение дат в Eloquent
1 2 3 4 5 |
Product::whereDate('created_at', '2018-01-31')->get(); Product::whereMonth('created_at', '12')->get(); Product::whereDay('created_at', '31')->get(); Product::whereYear('created_at', date('Y'))->get(); Product::whereTime('created_at', '=', '14:13:58')->get(); |
Подсказка 8. Группировка роутов
1 2 3 4 5 6 7 |
Route::group(['prefix' => 'account', 'as' => 'account.'], function() { Route::get('login', 'AccountController@login'); Route::get('register', 'AccountController@register'); Route::group(['middleware' => 'auth'], function() { Route::get('edit', 'AccountController@edit'); }); }); |
Подсказка 9. Инкремент и декремент в запросах к бд
1 2 |
Post::find($post_id)->increment('view_count'); // на 1 User::find($user_id)->increment('points', 50); // на 50 |
Подсказка 10. Проверка view на существование
1 2 3 |
if (view()->exists('custom.page')) { // загрузить view } |
Можно указать массив с видами, тогда будет загружен первый существующий.
1 |
return view()->first(['custom.dashboard', 'dashboard'], $data); |
Подсказка 11. Отключение timestamps-столбцов в модели
Если таблица не содержит столбцов created_at и updated_at, то необходимо в модели указать своство public $timestamps = false;
1 2 3 4 |
class Company extends Model { public $timestamps = false; } |
Подсказка 12. Поля миграция для таймзон
Кроме timestamps в миграциях можно создавать поля timestampsTz(), dateTimeTz(), timeTz(), timestampTz(), softDeletesTz().
1 2 3 4 5 6 |
Schema::create('employees', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->string('email'); $table->timestampsTz(); }); |
Подсказка 13. Eloquent-метод has() имеет второй уровень
1 2 3 |
// Author -> hasMany(Book::class); // Book -> hasMany(Rating::class); $authors = Author::has(' books.ratings ')->get(); |
Подсказка 14. Редкие типы столбцов в миграциях
1 2 3 4 5 |
$table->geometry('positions'); $table->ipAddress('visitor'); $table->macAddress('device'); $table->point('position'); $table->uuid('id'); |
Подробнее https://laravel.com/docs/master/migrations#creating-columns
Подсказка 15. Справка в artisan
Для описания artisan-команды запустите ее с флагом –help. Например, результатом php artisan make:model –help будет:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
Options: -a, --all Generate a migration, factory, and resource controller for the model -c, --controller Create a new controller for the model -f, --factory Create a new factory for the model --force Create the class even if the model already exists. -m, --migration Create a new migration file for the model. -p, --pivot Indicates if the generated model should be a custom intermediate table model. -r, --resource Indicates if the generated controller should be a resource controller. -h, --help Display this help message -q, --quiet Do not output any message -V, --version Display this application version --ansi Force ANSI output --no-ansi Disable ANSI output -n, --no-interaction Do not ask any interactive question --env[=ENV] The environment the command should run under -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug |
Подсказка 16. Timestamp по умолчанию
Для столбца ->timestamp() можно применить ->userCurrent(). Тогда значение по умолчанию будет CURRENT_TIMESTAMP.
1 2 |
$table->timestamp('created_at')->useCurrent(); $table->timestamp('updated_at')->useCurrent(); |
Подсказка 17. Присваивание user_id с помощью Observers
Выполним make:observer и в методе creating() присвоим user()->id():
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class PostObserver { /** * Handle to the post "creating" event. * * @param \App\Post $post * @return void */ public function creating(Post $post) { $post->user_id = auth()->id(); } } |
Подсказка 18. Soft-deletes: множественное восстановление удаленных записей
Восстановление нескольких записей можно осуществить одной строкой кода:
1 |
Post::withTrashed()->where('author_id', 1)->restore(); |
Подсказка 19. HasMany(). Фильтр по количеству дочерних записей.
1 2 |
// Author -> hasMany(Book::class) $authors = Author::has('books', '>', 5)->get(); |
Подсказка 20. Валидация размеров изображения
1 |
'photo' => 'dimensions:max_width=4096,max_height=4096' |
Подсказка 21. Группа роутов для динамических поддоменов
1 2 3 4 5 |
Route::domain('{username}.workspace.com')->group(function () { Route::get('user/{id}', function ( $username , $id) { // }); }); |
Подсказка 22. Версия Laravel
Для определения точной версии приложения пригодится команда:
1 |
php artisan --version |
Подсказка 23. Отправка email в log
Для тестирования отправки email в файле .env можно указать MAIL_DRIVER=log. В результате все email будут сохранены в storage/logs/laravel.log и не будут отправлены.
Подсказка 24. Blade-шаблон для ошибок
Если вы хотите создать специальную страницу для ошибки с конкретным HTTP-кодом, например, 500, то можно создать файл resources/views/errors/500.blade.php, который будет автоматически отображаться в случае ошибки с таким кодом.
Подсказка 25. Callback для фабрики
Можно добавить действие после того, как запись была создана.
1 2 3 |
$factory->afterCreating(App\User::class, function ($user, $faker) { $user->accounts()->save(factory(App\Account::class)->make()); }); |
Подсказка 26. Параметры artisan-команды
При создании artisan-команды можно запросить данные от пользователя несколькими способами: $this->confirm(), $this->anticipate(), $this->choice().
1 2 3 4 5 6 7 8 9 |
// Да или нет? if ($this->confirm('Продолжить?')) { // } // Список вариантов для автозаполнения $name = $this->anticipate('What is your name?', ['Taylor', 'Dayle']); // Список вариантов с индексом по умолчанию $name = $this->choice('What is your name?', ['Taylor', 'Dayle'], $defaultIndex); |
Подсказка 27. Предпросмотр для Mailables
Если для отправки email вы используете Mailables, то вы можете посмотреть результат напрямую в браузере без собственно отправки. Для этого необходимо в роуте вернуть объект Mailable:
1 2 3 4 |
Route::get('/mailable', function () { $invoice = App\Invoice::find(1); return new App\Mail\InvoicePaid($invoice); }); |
Подсказка 28. Роут без контроллера
Если роут предназначен просто для отображения вида, то можно использовать функцию Route::view():
1 2 3 4 5 6 7 8 9 10 11 12 |
// Вместо этого кода Route::get('about', 'TextsController@about'); // и этого class TextsController extends Controller { public function about() { return view('texts.about'); } } // Можно писать так: Route::view('about', 'texts.about'); |
Подсказка 29. @auth в blade-шаблоне
Вместо конструкции:
1 2 3 |
@if(auth()->user()) // The user is authenticated. @endif |
Используйте:
1 2 3 |
@auth // The user is authenticated. @endauth |
Подсказка 30. Столбцы в eloquent-методе all()
При вызове Model::all() можно указать, какие именно столбцы необходимо вернуть из таблицы.
1 |
$users = User::all(['id', 'name', 'email']); |
Подсказка 31. Localhost в файле .env
Не забудьте в файле .env изменить значение APP_URL с http://localhost на реальный адрес, так как он будет использован в email-оповещения и не только.
1 2 3 4 5 |
APP_NAME=Laravel APP_ENV=local APP_KEY=base64:9PHz3TL5C4YrdV6Gg/Xkkmx9btaE93j7rQTUZWm2MqU= APP_DEBUG=true APP_URL=<strong>http://localhost</strong> |
Подсказка 32. Что скрывается за Auth::routes()?
Достаточно посмотреть файл /vendor/laravel/framework/src/illuminate/Routing/Router.php.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
public function auth(array $options = []) { // Authentication Routes... $this->get('login', 'Auth\LoginController@showLoginForm')->name('login'); $this->post('login', 'Auth\LoginController@login'); $this->post('logout', 'Auth\LoginController@logout')->name('logout'); // Registration Routes... if ($options['register'] ?? true) { $this->get('register', 'Auth\RegisterController@showRegistrationForm')->name('register'); $this->post('register', 'Auth\RegisterController@register'); } // Password Reset Routes... $this->get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm')->name('password.request'); $this->post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.email'); $this->get('password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset'); $this->post('password/reset', 'Auth\ResetPasswordController@reset')->name('password.update'); // Email Verification Routes... if ($options['verify'] ?? false) { $this->emailVerification(); } } public function emailVerification() { $this->get('email/verify', 'Auth\VerificationController@show')->name('verification.notice'); $this->get('email/verify/{id}', 'Auth\VerificationController@verify')->name('verification.verify'); $this->get('email/resend', 'Auth\VerificationController@resend')->name('verification.resend'); } |
Подсказка 33. Eloquent …orFail
На ряду с findOrFail() в Eloquent существует метод firstOrFail, который генерирует ошибку 404, если по запросу нет ни одной записи.
1 |
$user = User::where('email', 'user@email.com')->firstOrFail(); |