Laravel8マイナーバージョンアップで追加された機能を振り返る

[Laravel Advent Calendar 2021](https://qiita.com/advent-calendar/2021/laravel) 22日目の投稿です。

# はじめに
2022年の頭に待望の新LTS版であるLaravel9がリリースされます。LTSしか使わないぞ！という人にとっては、Laravel6からいきなり9に乗り換えることになるはずです。正直8までの間の破壊的変更はそれほど多くは無いため、バージョンアップはさほど難しくないでしょう。

しかし一方で、Laravel8では毎週なにがしかの新機能を追加するマイナーバージョンアップが行われており、そのバージョンアップ回数はすでに70を超えています。このままだと9に乗り換えても、旧態依然とした実装を続けてしまいそうということで、8のマイナーバージョンアップで追加された目玉機能をまとめてみることにします。なお、追加された機能はもれなく公式マニュアルにも反映されているので、そちらを再度1から読むというのもオススメです。

なお、今回Advent Calenderでは、[細かすぎて伝わらないLaravel選手権8（laravel8）](https://qiita.com/okdyy75/items/0f3566597a8f7e0107b0)とのネタ被りを避けて別のお題を考えていましたが、あまり面白い記事にならなさそうということでネタ被り上等で記事を書く方針に切り替えました。

# 重要度別Laravel8追加機能

## 個人的重要度★★★
### Laravel Sail
Laravel8のマイナーバージョンアップで、標準のDocker環境が提供されるようになりました。これは、元々界隈では有名な`vessel`というパッケージからインスピレーションを得て追加されたものであり、Dockerさえインストールしておけば、`laravel new`でプロジェクトを作成した後、すぐに開発を始められることを意味します。詳しくはこちらの[マニュアル](https://laravel.com/docs/8.x/sail)を参照してください。
[関連doc](https://laravel.com/docs/8.x/sail)

### Sanctum
LaravelのAPI認証スタックは、`auth:api` から `auth:sanctum` を使う方式が標準となりました。これにより、Laravel8以降ではapiトークンを管理するテーブルが追加されています。
[関連PR](https://github.com/laravel/laravel/pull/5663)

### LazyLoading防止
ActiveRecordパターンでは、知らずにLazyLoadingを使用してしまい、アプリケーションのパフォーマンス問題になることがあります。それを未然に防ぐためにLazyLoading発生箇所で例外を投げてくれるようになりました。今後は、AppServiceProviderのbootメソッドで`Model::preventLazyLoading(! $this->app->isProduction());`という処理を追加することで、この防止機能を有効化することができます。
[関連PR](https://github.com/laravel/framework/pull/37480) / [関連doc](https://laravel.com/docs/8.x/eloquent-relationships#preventing-lazy-loading)

### One-Of-Many
例えばリレーションシップ先の「最新」や「最も古い」子モデルを取得したい時に使用するリレーションシップメソッドとなります。今まではEloquentでの実装を諦めて、QueryBuilderでゴリゴリ書いていたと思いますが、それがメソッドを追加するだけで実現できるのは、非常にありがたいです。内部的にはinner joinを発行しているようです。

[関連PR](https://github.com/laravel/framework/pull/37362) / [関連doc](https://laravel.com/docs/8.x/eloquent-relationships#has-one-of-many)

### Enum対応
PHP8.1から追加されたEnumクラスを使ったバリデーション、キャストができるようになっています。enumを使いたい場合、今まではlaravel-enumのようなサードパーティ製のパッケージを導入していましたが、今後は標準の構成でもenumを便利に使うことができます。

### 並列テスト
Laravelのテストを並行して実行することができます。これにより、テスト完了までにかかる時間が大幅に短縮できるようになりました。
[関連PR](https://github.com/laravel/framework/pull/36034) / [関連doc](https://laravel.com/docs/8.x/testing#running-tests-in-parallel)

## 個人的重要度★★
### 便利なキャスト追加
Laravel8のマイナーバージョンアップでは、Eloquentキャストが大量に追加されています。
#### encrypted
文字列を暗号化して指定の型にキャストできます。
#### immutable_date & immutable_datetime
CarbonではなくCarbonImuutableを使ってキャストできます。

#### AsArrayObject & AsCollection
今まではarrayやcollectionにキャストし、その後特定のプロパティに対して値の変更を行おうとしてもできませんでした。しかしAsArrayObject::class、AsCollection::classにキャストすればそれが可能になります。
[関連PR](https://github.com/laravel/framework/pull/36245) / [関連doc](https://laravel.com/docs/8.x/eloquent-mutators#array-and-json-casting)

### より便利になったスカフォールド
#### --requestオプション
make:controllerでControllerを作成する時に、FormRequestも一緒に作成できます。

####  --typeオプション
make:controllerでControllerを作成する時に、独自に作成したカスタムスタブを使用することができます。

#### make:test、--test、--pestオプション
テストケースのスカフォールドを作成できます。ControllerやModelをmakeする時にPHPUnitまたはPESTのテストケースも一緒に作成できます。

### explain()
DBのEXPLAINコマンドで得られる結果を出力できます。

### upsert()
DBのupsertコマンドを使えます。bulkでの処理もできるためバッチ処理でinsertかupdateを判断して実行する処理を実装してた人には嬉しいです。

### cursorPaginate()
`paginate()`では、limit/offset方式でDBに問い合わせを行っていました。これはページングの途中でデータが増えた場合に次ページの開始レコードがずれてしまう問題や、後方のページを取得する時のパフォーマンスが劣化する問題を抱えていました。`cursorPaginate()`では、idベースでページングを行うため、これらの問題を回避できます。
[関連PR](https://github.com/laravel/framework/pull/37216)

### schedule:work
スケジューリングしたタスクを簡単にテストできるコマンドです。Dockerだとcronもインストールされていないので、 タスクがスケジュール通り動くかを確認するのはやや面倒でした。

### migrationでの無名クラス使用
今までmigrationファイルは、クラス名が衝突しないように名付けで悩むことがありました。しかし無名クラスを使用できるようになりクラス名の衝突の懸念がなくなりました。
[関連PR](https://github.com/laravel/framework/pull/36906)

### パスワードルール
passwordをバリデーションするときのルールをより厳密に定義することができます。これにより単に文字列の長さだけでなく、文字列に大文字小文字が1文字以上含まれているかなどのバリデーションができるようになります。
[関連PR](https://github.com/laravel/framework/pull/36960) / [関連doc](https://laravel.com/docs/8.x/validation#validating-passwords)

## 個人的重要度★
### missing()
ルートモデルバインディング時に対象のオブジェクトが無い場合は、今まではNotFoundExceptionがthrowされて404エラー画面が表示されていました。しかし、`missing()` を使うと、その場合の挙動を好きなように指定できるようになります。
[関連doc](https://laravel.com/docs/8.x/routing#customizing-missing-model-behavior)

### Prohibitedバリデーションルール
システムが受け取りを拒否するフィールドをバリデーションします。
[関連doc](https://laravel-news.com/laravel-prohibited-validation-rules)

### Cookie::expire()
今まではCookieを消す時に、 `Cookie::queue(Cookie::forget('name'));` という直感的ではない記述が必要でした。しかし今後は、 `Cookie::expire('name');` と記述することができます。

### classディレクティブ
bladeテンプレートのclass属性において、条件式を導入できるようになります。これにより、特定の条件を満たした場合に、classを有効にすることができ、各種パーツの状態変更時の色や形状の変更が簡単になります。
[関連doc](https://laravel.com/docs/8.x/blade#conditional-classes)

### whereRelation()
whereHas()よりも直感的にリレーション先のテーブルに対する条件マッチクエリを記述できます。
[関連doc](https://laravel.com/docs/8.x/eloquent-relationships#inline-relationship-existence-queries)

# おわりに
とりあえず、私が個人的に重要と考える機能を列挙してみました。ただ、プロジェクトによって抱えている課題は異なりますので、上に含まれていない中にも重要な機能があるかもしれません。もし私が見落としているもので良さそうな新機能があれば、コメント欄にて教えていただければ幸いです。

# 参考ドキュメント
[laravel/framework CHANGELOG-8.x](https://github.com/laravel/framework/blob/8.x/CHANGELOG-8.x.md)
[laravel/laravel CHANGELOG](https://github.com/laravel/laravel/blob/8.x/CHANGELOG.md)
[Laravel News](https://laravel-news.com/search?index=articles&q=Laravel8+released)