Laravel8を試したら即効でエラー「Target class [〇〇〇Controller] does not exist.」が表示された


はじめに

最近になってLaravel8がリリースされたと聞いて、とりあえず動かしてみようと思ったら開始早々にエラーが発生しました。

web.phpPostControllerを呼び出す処理を書いたのに上記エラーが発生。Laravel6ではちゃんと呼び出せたのに
そのときのweb.phpはこちら。

web.php
<?php
use Illuminate\Support\Facades\Route;
Route::get('/', 'PostController@index');

原因調査したら、どうやらLaravel8の変更点の一つであるRouteServiceProvider.phpファイルからデフォルトの名前空間を削除」したのが大きく関係していると判明!Laravel7.xのプロジェクトからLaravel8.xに移行した場合は、この変更点の影響は受けない。Laravel8で作成した新規プロジェクトは変更点を考慮する必要があるそうです。

RouteServiceProvider.phpの変化

Laravel7までは、RouteServiceProvider.phpには次のコードが含まれていました。
(ファイルはapp/Providers配下に格納されています)

RouteServiceProvider.php
protected $namespace = 'App\Http\Controllers';

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

webミドルウェアとApp\Http\Controllersの名前空間を使用して、routes/web.phpにルートをロードするよう指示しています。

web.php
// Laravelは、App\Http\Controllers\PostControllerを検索します
Route::get('/', 'PostController@index');

Laravel8では、$namespace変数が削除され、Route宣言が次のように変更されました。

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

App\Http\Controllersの名前空間を使用していないです。

web.php
// Laravelは、App\Http\Controllers内でコントローラーを検索しません
Route::get('/', 'PostController@index');

このあと、どう修正すればよいのか解決方法を3つご紹介します。

解決方法

  • RouteServiceProvider.phpで名前空間を手動で追加する
  • web.phpで完全な名前空間を使用する
  • web.phpでアクション構文を使用する

RouteServiceProvider.phpで名前空間を手動で追加する

Laravel7.x以前と同じ方法です。

RouteServiceProvider.php
protected $namespace = 'App\Http\Controllers'; //追加
public function boot()
    {
        $this->configureRateLimiting();

        $this->routes(function () {
            Route::middleware('web')
                ->namespace($this->namespace) //追加
                ->group(base_path('routes/web.php'));

            Route::prefix('api')
                ->middleware('api')
                ->namespace($this->namespace) //追加
                ->group(base_path('routes/api.php'));
        });
    }

web.phpで完全な名前空間を使用する

コントローラーの名前の前に名前空間を追加します。
例として、app/Http/Controllersフォルダ内のPostControllerを呼び出したいときは、次の通り記載します。

web.php
Route::get('/', 'App\Http\Controllers\PostController@index');

web.phpでアクション構文を使用する

web.php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;
Route::get('/', [PostController::class, 'index']);

配列で使用したいクラスとメソッドを指定します。
具体的に配列内の値は
PostsController :: class -> App \ Http \ Controllers \ PostsControllerを返している
index -> PostController.phpのindexメソッドを呼び出している

終わりに

Laravel開発で初めて遭遇したエラーでしたので勉強になりました。
ただ、Laravel8の新機能・変更点を理解してから使用してみようと思いました。理解せず使用すると痛い目に遭いますね

参考

How to fix ‘Target class does not exist’ in Laravel 8