Laravel11以降から使い始めた人に必要そうな質問と回答一覧

2024/03/12に公開

Laravel11以降から使い始めた人に必要そうな質問と回答一覧

Laravel11ではアプリケーション構造が大幅に変わったのでこれまでの本や記事が一気に古びた。
初心者質問の定番だけど、古い本を見ながら最新のLaravelを使おうとしても使えない。

https://laravel.com/docs/11.x/releases

configファイルが少ない

あまり使われないconfigファイルが削除された。
Laravel11以降しか知らない人にはかなり分かりにくいのでしっかり理解が必要。

  • プロジェクトのconfigとフレームワーク内のconfigがマージされて使われるのでファイルがなくても設定は存在している。 https://github.com/laravel/framework/tree/11.x/config
  • マージする時はプロジェクト側のconfigが優先。
  • ほとんどの設定は.envで変更できるのでconfigファイルを変更することは少ない。

config/sanctum.phpはsanctumをインストールしたら追加される。
config/broadcasting.phpはブロードキャスト機能をインストールしたら追加される。

app/Http/Middlewareがなくてミドルウェアの設定を変更できない

bootstrap/app.phpでの設定に変わった。

Laravel10

TrustProxies.php

app/Http/Middleware/TrustProxies.php
protected $proxies = '*';

VerifyCsrfToken.php

app/Http/Middleware/VerifyCsrfToken.php
    protected $except = [
        'stripe/*',
        'http://example.com/foo/bar',
        'http://example.com/foo/*',
    ];

Laravel11

bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
    $middleware->trustProxies(at: '*')
               ->validateCsrfTokens(except: [
                   'stripe/*',
                   'http://example.com/foo/bar',
                   'http://example.com/foo/*',
               ]);
})

Laravel10で可能だった設定はすべてMiddlewareクラスに移動している。

app/Http/Kernel.phpがなくてミドルウェアを追加できない

bootstrap/app.phpでの追加に変わった。

Laravel10

app/Http/Kernel.php
    protected $middleware = [
        // ...
        \App\Http\Middleware\EnsureTokenIsValid::class,
    ];

Laravel11

bootstrap/app.php
use App\Http\Middleware\EnsureTokenIsValid;
 
->withMiddleware(function (Middleware $middleware) {
     $middleware->append(EnsureTokenIsValid::class);
})

https://laravel.com/docs/11.x/middleware

コントローラーで$this->validate()$this->authorize()が使えない

ベースコントローラーを継承しなくなったので代わりにRequestやGateを使う。

use App\Models\Post;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;

class PostController extends Controller
{
    public function update(Request $request, Post $post) {
        $validated = $request->validate([]);

        Gate::authorize('update', $post);

        if ($request->user()->cannot('update', $post)) {
            abort(403);
        }
    }
}

ValidatesRequestsAuthorizesRequestsを追加すれば引き続き使える。authorizeResource()を使いたい場合もAuthorizesRequestsを追加する方法を選ぶ。

use App\Models\Post;
use Illuminate\Http\Request;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Validation\ValidatesRequests;

class PostController extends Controller
{
    use AuthorizesRequests, ValidatesRequests;

    public function __construct()
    {
        $this->authorizeResource(Post::class, 'post');
    }

    public function update(Request $request, Post $post) {
        $validated = $this->validate([]);

        $this->authorize('update', $post);
    }
}

色々なコントローラーで使うならapp/Http/Controllers/Controller.phpに追加してLaravel10仕様に戻してもいい。

app/Http/Controllers/Controller.php
<?php

namespace App\Http\Controllers;

use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Validation\ValidatesRequests;

abstract class Controller
{
    use AuthorizesRequests, ValidatesRequests;
}

$this->middleware()がないのでコントローラー内でのミドルウェアの指定ができない

リリースノート・アップグレードガイドには書いてないけど使い方が大きく変わっている。

Laravel10

class UserController extends Controller
{
    /**
     * Instantiate a new controller instance.
     */
    public function __construct()
    {
        $this->middleware('auth');
        $this->middleware('log')->only('index');
        $this->middleware('subscribed')->except('store');
    }
}

Laravel11

namespace App\Http\Controllers;
 
use App\Http\Controllers\Controller;
use Illuminate\Routing\Controllers\HasMiddleware;
use Illuminate\Routing\Controllers\Middleware;
 
class UserController extends Controller implements HasMiddleware
{
    /**
     * Get the middleware that should be assigned to the controller.
     */
    public static function middleware(): array
    {
        return [
            'auth',
            new Middleware('log', only: ['index']),
            new Middleware('subscribed', except: ['store']),
        ];
    }
 
    // ...
}

元々コントローラー内でのミドルウェア指定は分かりにくいのでルーティングで指定したほうがいい。

routes/web.php
Route::get('user', UserController::class)->middleware(['auth']);

https://laravel.com/docs/11.x/controllers#controller-middleware

app/Http/Controllers/Controller.php をLaravel10仕様に戻してもいい

Laravel10からアップグレードしたLaravel11ではそのまま使えるので別に禁止されてない。コントローラー内での$this->middleware()が引き続き使える。

<?php

namespace App\Http\Controllers;

use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;

abstract class Controller extends BaseController
{
    use AuthorizesRequests, ValidatesRequests;
}

routes/api.phpがない

API関連の機能は必要な人だけ追加するように変わったので個別にインストールする。

php artisan install:api

Broadcasting routes/channels.phpがない

ブロードキャストもAPIと同じく個別にインストールする。

php artisan install:broadcasting

app/Console/Kernel.phpがなくてScheduleの設定ができない

routes/console.phpでの設定に変わった。

Laravel10

app/Console/Kernel.php
    protected function schedule(Schedule $schedule): void
    {
        $schedule->command('inspire')->hourly();
    }

Laravel11

routes/console.php
use Illuminate\Support\Facades\Schedule;

Schedule::command('inspire')->hourly();

Laravel11.1でbootstrap/app.phpでの指定も可能になった。せっかくスリム化したのにタスクスケジュールの設定方法が2つに増えた。

bootstrap/app.php
use Illuminate\Console\Scheduling\Schedule;

->withSchedule(function (Schedule $schedule) {
    $schedule->command('inspire')->hourly();
})

https://laravel.com/docs/11.x/scheduling

イベントとリスナーの登録方法が分からない

イベントと「handle()にイベントを指定したリスナー」を作れば自動的に登録されるので手動登録は不要。

php artisan make:event PodcastProcessed

php artisan make:listener SendPodcastNotification --event=PodcastProcessed
use App\Events\PodcastProcessed;
 
class SendPodcastNotification
{
    /**
     * Handle the given event.
     */
    public function handle(PodcastProcessed $event): void
    {
        // ...
    }
}

本番環境ではキャッシュを忘れない。

php artisan event:cache

よくある間違いで開発環境でcacheコマンドを実行してはいけない。clearコマンドで戻せるけど最初から一度も実行しなければ何も問題は起きない。

php artisan event:clear

https://laravel.com/docs/11.x/events

config/app.phpへのサービスプロバイダー追加方法が分からない

bootstrap/providers.phpへの追加に変わった。

Laravel10

config/app.php
    'providers' => ServiceProvider::defaultProviders()->merge([
        // ...

        App\Providers\AppServiceProvider::class,
        App\Providers\FooServiceProvider::class,
    ])->toArray(),

Laravel11

bootstrap/providers.php
<?php

return [
    App\Providers\AppServiceProvider::class,
    App\Providers\FooServiceProvider::class,
];

Laravel用のcomposerパッケージならServiceProviderの自動検出に対応しているのでbootstrap/providers.phpへの手動追加は不要。

プロジェクト独自のServiceProviderをmakeコマンドで作った場合もbootstrap/providers.phpは自動更新されるので手動追加は不要。

php artisan make:provider FooServiceProvider

https://laravel.com/docs/11.x/providers

RouteServiceProvider::HOMEがない

消えたままなので使わずルート名などで指定。

return to_route('home');
return redirect('/home');

app/Exceptions/Handler.phpがない

bootstrap/app.phpでの設定に変わった。

bootstrap/app.php
->withExceptions(function (Exceptions $exceptions) {
    $exceptions->dontReport(MissedFlightException::class);
 
    $exceptions->report(function (InvalidOrderException $e) {
        // ...
    });
})

Laravel10でもこの辺りを変更することはほとんどなかったので覚えなくていい。

ルーティングをもっとカスタマイズしたい

Laravel10

RouteServiceProviderでルートファイルを追加できた。

        $this->routes(function () {
            Route::middleware('api')
                ->prefix('api')
                ->group(base_path('routes/api.php'));

            Route::middleware('web')
                ->group(base_path('routes/web.php'));

            Route::middleware('web')
                ->group(base_path('routes/foo.php'));
        });

Laravel11

web.phpとは別のルートファイルを追加するならthen

bootstrap/app.php
use Illuminate\Support\Facades\Route;
 
->withRouting(
    web: __DIR__.'/../routes/web.php',
    commands: __DIR__.'/../routes/console.php',
    health: '/up',
    then: function () {
        Route::middleware('web')
            ->group(base_path('routes/foo.php'));
    },
)

Laravel10と同じように全部自分で定義したいならusing

bootstrap/app.php
use Illuminate\Support\Facades\Route;
 
->withRouting(
    commands: __DIR__.'/../routes/console.php',
    using: function () {
        Route::middleware('api')
            ->prefix('api')
            ->group(base_path('routes/api.php'));
 
        Route::middleware('web')
            ->group(base_path('routes/web.php'));

        Route::middleware('web')
            ->group(base_path('routes/foo.php'));
    },
)

LaravelデフォルトのServiceProviderを置き換えたい

一部のサードパーティパッケージはデフォルトのServiceProviderをパッケージのServiceProviderに置き換えて使うように指示してくる。(こんなパッケージは使わない方がいい)

config/app.phpからprovidersは消えているけどフレームワーク内のconfig/app.phpには残っている。「configはマージして使われる」のでプロジェクト側のconfig/app.phpprovidersを追加すればいい。

config/app.php
use Illuminate\Support\ServiceProvider;

    'providers' => ServiceProvider::defaultProviders()->replace([
        Illuminate\Foo\FooServiceProvider::class => Bar\BarServiceProvider::class,
    ])->toArray(),

途中参加したプロジェクトでの判別方法

bootstrap/app.phpの中身を確認。

  • return Application::configure(...ならLaravel11以降に新しく作られたプロジェクト、もしくはLaravel10からのアップグレード時にLaravel11の仕様に合わせてスリム化したプロジェクト。Laravel11以降のドキュメントだけ見ればいい。
  • Laravel10と同じbootstrap/app.phpならLaravel10からのアップグレード時にスリム化してない。公式にはスリム化しない方が推奨なのでこれも多くなるはず。現在使ってるバージョンがなんだろうとドキュメントは最新版とLaravel10版を参照する。

2つの使い方が混在するのでしばらくは混乱するかもしれない。

リリース後に何度も聞かれてる質問を見つけたら追加するかも

質問があればteratailへ。
https://teratail.com/
英語ならLaracasts Forum。
https://laracasts.com/discuss

Discussion