【Laravel】Laravel11.xでのマルチドメインの設定方法

小中規模のプロジェクトではサービス側のシステムと管理画面側のシステムを同じプロジェクト内に作成すると場合があると思います。
その場合、Laravel10以前では```app/Providers/RouteServiceProvider.php```の```boot()```メソッドでドメイン別の制御を行うのが通例だったと思いますが、その```RouteServiceProvider```は11から削除されたました。
その為、Laravel11でドメイン別でルートを制御する実装方法の解説です。
Webサーバーのバーチャルホストの設定は割愛します。
### Laravel10以前で```routes/admin.php```にルートを繋ぐサンプル
```php:app/Providers/RouteServiceProvider.php
    public function boot(): void
    {
        # 省略
        $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('admin')
                ->name('admin.')
                ->domain(config('app.admin_url'))
                ->group(base_path('routes/admin.php'));
        });
    }
}

```
# Laravel11.x以降
管理画面用(別ドメイン用)の環境変数を```ADMIN_URL```として追加します。
### 環境変数の追加
```php:.env.example
APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_TIMEZONE=UTC
APP_URL=http://localhost
# 管理画面のドメインを追加
ADMIN_URL=http://admin.localhost

# 省略
```
```php:config/app.php
<?php

return [
    # 省略
        
    'url' => env('APP_URL', 'http://localhost'),
    'admin_url' => env('ADMIN_URL', 'http://admin.localhost'), # 追加
    
    # 省略
];
```
環境変数を変更したのでキャッシュされている情報の削除
```shell:composer
    php artisan config:clear
```

### 管理画面用のルーティングファイルを追加
```routes/```ディレクトリ内に```web.php```と```console.php```のみある状態から、そこに```admin.php```を新規作成します。
```shell:shell
    touch routes/admin.php
```

```php:routes/admin.php
<?php

use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    # デバッグ用に
    dd('test');
});
```
###  ルーティングの設定
Laravel10以前の方法と同様の形で実装する場合は```using```引数のクロージャー内に定義することでドメイン別制御をできます。
Routeクラスの```domain()```メソッドでドメイン基準で切り分けが可能になります。
```php:bootstrap/app.php
<?php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use Illuminate\Support\Facades\Route;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        # web引数はusingで指定し直すので再定義するので削除して大丈夫です。
        # web: __DIR__.'/../routes/web.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
        using: function () {
            # サービス側のルートの設定
            Route::domain(config('app.url'))
                ->middleware('web')
                ->group(base_path('routes/web.php'));
            # 管理画面のルートの設定
            Route::domain(config('app.admin_url'))
                ->name('admin.')
                ->middleware('web')
                ->group(base_path('routes/admin.php')); # 作成したルーティングファイルの指定
        },
    )
    ->withMiddleware(function (Middleware $middleware) {
        //
    })
    ->withExceptions(function (Exceptions $exceptions) {
        //
    })->create();


```
これでルーティング自体の設定は終わりです。
サービス側のルートの設定は```web: __DIR__.'/../routes/web.php'```を残して再定義しなくても大丈夫です。今回は例としてLaravel10風にしているだけです。
環境変数で指定した```http://admin.localhost```にアクセスして```test```と表示されれば成功です。

### 名前付きルートの呼び出し
サービス側で使用する```UserController```と管理画面で使用する```UserController```があると仮定します。
```php:routes/web.php
use App\Http\Controllers\UserController;

Route::controller(UserController::class)->as('users.')->prefix('users')->group(function () {
    Route::get('/', 'index')->name('index');
    Route::get('/create', 'create')->name('create');
});
```
```php:routes/admin.php
use App\Http\Controllers\Admin\UserController;

Route::controller(UserController::class)->as('users.')->prefix('users')->group(function () {
    Route::get('/', 'index')->name('index');
    Route::get('/create', 'create')->name('create');
});
```
外部クラスでルートを呼び出す際は下記のように呼び出します。
```php
    # サービス側ルート
    route('users.index'); # http://localhost/users
    route('users.create'); # http://localhost/users/create
    
    # 管理画面側ルート
    route('admin.users.index'); # http://admin.localhost/users
    route('admin.users.create'); # http://admin.localhost/users/create

```
ルーティング内容がほぼ同じなのに、管理画面用ルートを```admin.```で指定して呼び出せるのは```bootstrap/app.php```で```->name('admin.')```と設定しているからです。
このようにしてルートを切り分けることができます。

### 別ドメイン用に別Middlewareグループを適用する場合
管理画面にだけは別でMiddlewareグループを構成してアタッチしたい場合は以下のようにすることできます。
Laravel10以前まで存在していた```app/Http/Kernel.php```で行う設置もここでするようになっています。
```php:bootstrap/app.php
return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
        using: function () {
            Route::domain(config('app.url'))
                ->middleware('web')
                ->group(base_path('routes/web.php'));

            Route::domain(config('app.admin_url'))
                ->name('admin.')
                ->middleware('admin') # webグループからadminグループに変更
                ->group(base_path('routes/admin.php'));
        },
    )
    ->withMiddleware(function (Middleware $middleware) {
        # adminグループの作成
        $middleware->appendToGroup('admin', [
            # 管理画面用に適用したいMiddlewareを追加
            \Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
        ]);
    })
    ->withExceptions(function (Exceptions $exceptions) {
        //
    })->create();
```