Laravel 9 新功能 PHP 8.0 Symfony 6.0
Laravel PHP

Laravel 9 的新功能:最低要求 PHP 8.0,底層更新為 Symfony 6.0,開始使用 PHP 8.1 的 Enum,更多簡潔漂亮的寫法

https://laravel-news.com/laravel-9
今年 (2022) 二月 Laravel 9 發佈了。

從 Laravel 9 開始,major version 每一年更新一次。因為 Laravel 底層有使用 Symfony Framework 的元件,而且 Symfony 每年的 11 月會更新一次,所以 Laravel 目前是訂在隔年的二月更新 major version (這樣可以使用最新的 Symfony 版本)。像這次發布的 Laravel 9 底層是使用 Symfony 6.0。

以下列出 Laravel 9 的一些主要更新和新功能:

PHP 8.0 是 Laravel 9 最低的 PHP 版本要求

這是最根本的前提條件,檢查你的環境是不是 PHP 8.0 以上,才有辦法跑 Laravel 9。

route:list 指令顯示結果的重新設計

php artisan route:list

route:list 指令存在已久,如果 route 數量多而複雜,以前的顯示介面會有點混亂。Laravel 9 重新設計了 route:list 指令的顯示結果。

新的 test 指令選項,顯示測試覆蓋率

php artisan test --coverage

Laravel 的測試是基於 PHPUnit,Laravel 的測試功能存在已經非常久。上面指令會執行測試,並顯示每支程式的測試覆蓋率。

DB 預設使用 Anonymous Migration

Laravel 的 database migration,以前是要自己取 migration class name。但如果因需求變更,刪除再新增同一 DB table,或是多次修改同一 DB table,取 migration class name 就會變成一件麻煩事,migrate 起來的行為也不見得會跟你的邏輯順序相同。

Anonymous Migration 是 Laravel 8 後期推出的功能,Laravel 9 變成專案預設,以後再也不用取 migration class name 了。

新的 string functions

因為 Laravel 9 最低要求 PHP 8.0。PHP 8 新的 string functions: str_contains, str_starts_with, str_ends_with 也被引入,包裝成 Laravel 9 string functions: Str::contains, Str::startsWith, Str::endsWith

寄信件模組從 Swift Mailer 更新為 Symfony Mailer

Swift Mailer 為 Symfony Framework 的寄件元件,隨著 2021 年 11 月 Symfony 6.0 的推出,改為使用 Symfony Mailer,並停止維護 Swift Mailer。Laravel 9 也隨之改為使用 Symfony Mailer。

Eloquent Accessor / Mutator 有新的寫法

Laravel 8 以前的 Accessor / Mutator 寫法,官方文件的 sample code

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

Laravel 9 改成

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

用 PHP 8.1 的 enum 做 implicit route binding

https://laravel.com/docs/9.x/routing#implicit-enum-binding
官方文件的 sample code

// Category 為 enum
Route::get('/categories/{category}', function (Category $category) {
    return $category->value;
});

可以更漂亮的限制哪些參數是 route 可以允許的, 如果是不允許的參數, 直接 return 404.

用 Route::controller 將同一 controller 不同 route 更好的組織起來

Route::controller(YourController::class)->group(function () {
    …. // route 1
    …. // route 2
});

不用再重複寫 ControllerName,組織上,程式的簡潔度上都比較好。

用 PHP 8.1 的 enum 做 Eloquent Attribute Casting

官方文件的 sample code

protected $casts = [
    'status' => ServerStatus::class,
];

你的 $model->status 不管是存,還是取,都會直接 cast 成一個 enum object.

https://laravel.com/docs/9.x/eloquent-mutators
包含上方的 Accessor / Mutator,以及這邊的 Casting,他們都屬於同一份文件,Laravel 9 在這份文件做了不少更新。

Route parameter scoping

https://laravel.com/docs/9.x/routing#implicit-model-binding-scoping
官方文件的 sample code

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

如果是這種格式的 route,而且使用 custom key (:slug的部分)。Laravel 會自動 scope 該 user 底下的 posts.

Laravel 9 開始,如果沒使用 custom key,同樣也可以 scope child binding

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

這樣寫法好處是更漂亮、更簡潔的檢查第一、二個參數的 relation.

Full Text Index & query by whereFullText

Laravel 9 開始, 如果使用 MySQL 或 PostgreSQL,可以使用 fullText method 做整段的 index。官方文件的 sample code

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

當 query 時,如果有 full text index 的欄位,可以使用兩個 method:whereFullText、orWhereFullText。官方文件的 sample code

$users = DB::table('users')
           ->whereFullText('bio', 'web developer')
           ->get();

Bootstrap 5 Pagination Views

Laravel 9 原生支援 Bootstrap 5 Pagination。在 AppServiceProvider, boot method, call

Paginator::useBootstrapFive();

即可使用 Bootstrap 5 Pagination View。

重新設計的 debug page

Laravel debug page 使用的是 Spatie Ignition,也重新設計了。

2 個新的 helper functions: str & to_route

str() 就是之前的 Str::of(),可以做一些字串的操作。

https://laravel.com/docs/9.x/redirects#redirecting-named-routes
之前  Redirect to Named Route 的 sample code

return redirect()->route('profile', ['id' => 1]);

Laravel 9 新寫法的 sample code

return to_route('users.show', ['user' => 1]);

甚至可以指定 HTTP status code 和 response header

return to_route('users.show', ['user' => 1], 302, ['X-Framework' => 'Laravel']);

結論

這次 Laravel 9 主要是底層語言與模組的更新,程式的寫法上更加簡潔漂亮。另外,如果你的環境是 PHP 8.1 以上,PHP 8.1 enum 的用法也可以參考一下。這次 Laravel 的更新,可能對有軟體工程基礎,對 Laravel 又有經驗的讀者,會比較有參考價值。