RAKUS Developers Blog | ラクス エンジニアブログ

株式会社ラクスのITエンジニアによる技術ブログです。

PHPerのための「Laravel9について語る」【PHP TechCafeイベントレポート】

弊社で毎月開催し、PHPエンジニアの間で好評いただいている勉強会「PHP TechCafe」。
2022年3月のイベントでは『PHPerのための「Laravel9について語る」』をテーマに語り合いました。

弊社のメンバーがLaravel9の新機能などの情報を元に、他の参加者に意見をいただいて語り合いながらLaravel9について理解を深めました。
今回はその内容についてレポートします。

rakus.connpass.com

PHP TechCafeとは

本題に入る前に「PHP TechCafe」について軽く説明します。
PHP TechCafe」とは弊社が主催しているエンジニア向けのイベントで、エンジニア同士で技術について話し合う憩いの場(カフェ)です。

月に1回開催し、コロナ禍の現在はオンラインで開催しています。
対象者はPHP入門の初級エンジニアからシニアエンジニアを幅広くカバーし、学びの場を提供してエキスパートまでの自己成長を支援することを目的にしています。
PHP TechCafe」は以下の3部構成です(日によって変わることもあります)。

  • ライトニングトーク(LT)
  • PHPer's NEWS
  • 特集

2022年3月の特集は『PHPerのための「Laravel 9 について語る」』をテーマに開催いたしました。
今回はその中で紹介された内容や盛り上がったポイントをレポートします。

PHPerのための「Laravel 9 について語る」

Laravel9の特徴

まずはお約束のLaravel9の特徴からです。

PHP8対応

PHP8に対応し、8未満には対応しなくなりました。

LTSが消えた

どんどんバージョンを上げていきましょう!、という意味かもしれませんね。

ハイペースなマイナーバージョンアップ

Laravel9は、短いスパンで次々とマイナーバージョンアップを重ねていることにも注目が集まり、話題となりました。

  • マイナーバージョンアップで新機能がいくつも追加されています。
  • 意外と使えそうな機能もよくあるので、新機能を使いたくなったら上げなきゃいけないですね。

Laravel9の新機能や変更点

Symfony Mailer

Laravel標準のメーラーがSwift MailerからSymfony Mailerに変更されました。
そもそもSwift Mailerってメンテナンスが止まっているのでLaravelもこちらに乗り換えたようです。

  • 結構互換性の無いものもあるので、しっかり見て変更しましょう。
  • インターフェースも変わってしまったんですね。Classを呼んでるところだけ置き換えたらOKという感じでもないですね。しっかり置き換えないといけない。

Sending Emails with Mailer (Symfony Docs)


Flysystem 3.x

Storageファサードによって提供されており、ファイル操作系処理を強化するFlysystemがバージョンアップしました。

  • S3とかFTPなどを利用している場合はドライバのアップデートが必要です。
  • 挙動も変わっているんですよね。PutやWrite、Writestreamなどを使うとデフォルトでファイルを上書きするようになるので、注意しないといけないです。
  • 存在しないファイルを指定すると以前はNullが返ってきていましたが、例外が返ってくるようになりました。

File Storage Abstraction for PHP - Flysystem


Improved Eloquent Accessors / Mutators

これはEloquentのモデルについてです。

Laravel9 以前

<?php

public function getNameAttribute($value)
{
  return strtoupper($value);
}

public function setNameAttribute($value)
{
  $this->attributes['name'] = $value;
}

↑ モデルにアクセサーとミューテタにプレフィックス付きのメソッドを定義する必要がありました。

Laravel9

<?php

use Illuminate\Database\Eloquent\Casts\Attribute;

public function name(): Attribute
{
  return new Attribute(
    get: fn ($value) => strtoupper($value),
    set: fn ($value) => $value,
  );
}

プレフィックスなしのメソッドに戻り値の型を指定(Attribute)することで、アクセサーとミューテタが定義可能となりました。

ルーティング 9.x Laravel


Enum Eloquent Attribute Casting

PHP8.1以上で稼働させている場合のみ動作して、モデルに挿入する値をEnum型でキャスト可能にします。

<?php

use App\Enums\ServerStatus;

/**
 * The attributes that should be cast.
 *
 * @var array
 */
protected $casts = [
  'status' => ServerStatus::class,
];

Eloquent:ミューテタ/キャスト 9.x Laravel


Implicit Route Bindings With Enums

ルートパラメータをEnum型で指定することができます。
型に一致しないパラメータが指定されたら、404が返されます。

Enumの定義

<?php

enum Category: string
{
  case Fruits = 'fruits';
  case People = 'people';
}

ルーティングの記載

<?php

Route::get('/categories/{category}', function (Category $category) {
  return $category->value;
});
  • Enumが使えるようになったから、こういうところにも使っていこうっていうことですかね。
  • どこを見たら良いかわかりやすいですね。
  • 404にしてくれるのがありがたい。無理やり動かすのは流石につらいので。

ルーティング 9.x Laravel


Forced Scoping Of Route Bindings

親のモデルと子のモデルを使用してRoute model bindingを行いたい場合、子のモデルにはカスタムキーを使用する必要がありました。

Laravel9 以前

<?php

use App\Models\Post;
use App\Models\User;

Route::get('/users/{user}/posts/{post:slug}', function (User $user, Post $post) {
  return $post;
});

それが、scopeBindings()を使用することで、カスタムキーなしでも子のモデルに対してRoute model bindingを行えるようになりました。

Laravel9

<?php

use App\Models\Post;
use App\Models\User;

Route::get('/users/{user}/posts/{post}', function (User $user, Post $post) {
  return $post;
})->scopeBindings();
  • Route model bindingとは、例えばこのコードの場合、RouteパラメータのところにUserやPostやモデル名を指定しています。UserのところにID1が入ったとしたらID1のUserのモデルインスタンスを自動的に取ってきてくれるというものです。
  • 今まではカスタムキーで”post:slug”を定義する必要があったのですが、それがLaravel 9からScope Bindingを使えば不要となり、シンプルに書きやすくなったようですね。

ルーティング 9.x Laravel


Controller Route Groups

全てのルートに共通のコントローラをグループとして定義できるようになりました。

Laravel8

<?php

# 何度もController名を書かないといけない
use App\Http\Controllers\OrderController;
                    
Route::get('/orders/{id}', [OrderController::class, show]);
Route::post('/orders', [OrderController::class, store]);

Laravel9

<?php

use App\Http\Controllers\OrderController;

Route::controller(OrderController::class)->group(function () {
  Route::get('/orders/{id}', 'show');
  Route::post('/orders', 'store');
});

コントローラごとにグループ分けができるようになりました。
この変更にはこんな声がありました。

  • ヤンチャな実装する人だったら、まとまりを無視して変なところに定義を書いたりすることがありますが、Laravel9だとそこは強制されるのでヤンチャできなくなりますね。
  • 概念としてコントローラが上になったような気がして、個人的にはちょっと嫌だなって思いますね。コントローラがルートを決めたんじゃないかというニュアンスになるので。
  • ルートとコントローラが密結合になったんじゃないかという印象を持ちました。ここまでやるならそもそも定義書かなくてよくない?という感じもしますね。

ルーティング 9.x Laravel


Full Text Indexes / WhereClauses

指定した列に FULLTEXT INDEX を作成できます。※MySQLPostgreSQL

<?php

$table->text('bio')->fullText();

FULLTEXT INDEX がある列に対して、WHERE句を作成することもできます。

<?php

$users = DB::table('users')
  ->whereFullText('bio', 'web developer')
  ->get();
  • これすっごくありがたいです。どデカいテキストの部分一致検索みたいなやつは、巨大掲示板とかになってくると Elasticsearch にするとかでないと対応できなかったんです。PostgreSQLにしろMySQLにしろテーブルとかインデックスの型の定義がすごく独特で大変なんです。しかも標準SQLに定義されていない機能なので正直ダルいんですよ…。だから欲しかった人は本当に欲しかったものだと思います。
  • 今まではCreate IndexとかSQLを直書きしないと駄目ですよね。それを検索するときもwhereじゃなくてwhereRawとか使ってSQL直書きするしかなかったんですよ。それが公式にサポートされたから作れるようになったんですね。

データベース:クエリビルダ 9.x Laravel


Slot Name Shortcut

Blade関連ですね。
X-slotタグを短く書けるようになりました。

Laravel9 以前

<x-alert>
  <x-slot name="title">
    Server Error
  </x-slot>

</x-alert>

Laravel9

<x-slot:title>
  Server Error
</x-slot>

これはサッと読めるようになるので、どんどん使っていきたいですね。  

Bladeテンプレート 9.x Laravel


Checked / Selected Blade Directives

こちらもBlade関連。

@checked チェックボックスをONに指定できる

<?php

<input type="checkbox"
        name="active"
        value="active"
        @checked(old('active', $user->active)) />

@selected セレクトボックスにてデフォルトで選択されている項目を指定できる

<?php

<select name="version">
    @foreach ($product->versions as $version)
        <option value="{{ $version }}" @selected(old('version') == $version)>
            {{ $version }}
        </option>
    @endforeach
</select>
  • @checkedって書いていたらそこのチェックボックスをオンに出来ますよとか、@selectedにしたらデフォルトで選択されている項目を指定できます。今まで三項演算子で書いていたものがBladeで書けるようになって、痒いところに手が届くようになりました。

Bladeテンプレート 9.x Laravel


whereNot clause

クエリビルダでずっとサポートされていなかった、whereNotがようやく使えるようになりました。

  • whereNotは何回かリジェクトされて9.3でやっと取り込まれた経緯があるそうです。
  • できることなら肯定形で書きたいです。でもSQLの構文として存在するものはサポートしてほしい気はしますね。今までそれをあえて入れなかったのは、否定形を入れずに綺麗なものを目指すんだという強い意思があったのかもしれないですね。
  • SQLの構文としてはあるけど、Laravelには無いから今回取り入れたという感じですかね。あえて書きたいケースもありますし。他のすべてのメソッドにはNotがあるけれど、whereにだけ無いと。

データベース:クエリビルダ 9.x Laravel


Improved Ignition

開発中の例外発生時などに表示されるIgnitionが新しくなりました。
ダークテーマや「エディタで開く」を選べるようになりました。

リリースノート 9.x Laravel


Improved route:list CLI Output

route:listのCLIが見やすくなりました。

  • 最近CLIの見やすくなるアップデートが割と多いですね。
  • 本当に見やすくなりました。ただ一方でPHPUnit Printerに外部ライブラリを入れて綺麗にしていた人は一気に全部崩れたみたいです。なので外して公式にし直すというのがウチではありました。
  • 以前は色も何もついてなくて、”…”もついてなくて、縦バーで区切ってましたね。

リリースノート 9.x Laravel


アップデートの落とし穴

  • アップデートガイドのところでここのPHPファイルだけ開いて修正してね、ということです。ここだけ手作業ということで、ハマりそうですね。
app/Http/Middleware/TrustProxies.php の修正

変更前

use Fideveloper\Proxy\TrustProxies as Middleware

変更後

use Illuminate\Http\Middleware\TrustProxies as Middleware
$headersの修正

変更前

protected $headers = Request::HEADER_X_FORWARDED_ALL;

変更後

protected $headers =
  Request::HEADER_X_FORWARDED_FOR |
  Request::HEADER_X_FORWARDED_HOST |
  Request::HEADER_X_FORWARDED_POST |
  Request::HEADER_X_FORWARDED_PROTO |
  Request::HEADER_X_FORWARDED_AWS_ELB ;
  • Composerをアップデートしてもダメで、Bootstrapのキャッシュを消さなきゃいけないのでこの作業が必要になるようです。
  • ここはつまづきますね。「キャッシュ周りでアップデートしたのに何で古い方を読みにいってるの?」ってことが起こってました。

Upgrade Guide - Laravel - The PHP Framework For Web Artisans

編集後記

メジャーバージョンアップだけではなく、マイナーバージョンアップでも次々に機能追加がされたりとさらに開発が活発化している印象でした。
LTSがなくなったのは我々開発者としては痛いところですが、これは長期サポートのコストをLaravelの開発をどんどん前に進めることに充てるというアグレッシブな思想があるからかもしれませんね。

ここでは語りつくせない変更もまだまだあるので、リリースノートは要チェックです。
今後もLaravelの進化から目が離せません!

PHP TechCafe」では今後もPHPに関する様々なテーマのイベントを企画していきます。
皆さまのご参加をお待ちしております。
connpass.com


◆TECH PLAY
techplay.jp

◆connpass
rakus.connpass.com

Copyright © RAKUS Co., Ltd. All rights reserved.