🗡

Laravel トレイリングスラッシュを扱う方法まとめ

2024/03/18に公開

Laravel はトレイリングスラッシュなしがデフォルトのため、ありにするにはいくつかの設定が必要になります。

ネットには Apache、Laravel でそれぞれ情報が散らばっており、結局どれを設定すればいいんだっけ…? となることがあるので備忘録です。

また Apache へのアクセス時の挙動と合わせて、Laravel で自動生成される URL に対してもトレイリングスラッシュが付くようにします。

Web サーバー (Apache) 側の設定

public/.htaccess に以下の内容を追記してください。

# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]

# Send Requests To Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]

Laravel 側の設定

1. サービスの設定

app/Services/Route/UrlGenerator.php を新規作成し、Illuminate\Routing\UrlGenerator を継承して format() メソッドをオーバーライドします。
以下の内容を記述してください。

<?php

namespace App\Services\Route;

use Illuminate\Routing\UrlGenerator as BaseUrlGenerator;

class UrlGenerator extends BaseUrlGenerator
{
    /**
     * Create a new manager instance.
     *
     * @param Illuminate\Routing\UrlGenerator $url
     */
    public function __construct(BaseUrlGenerator $url)
    {
        parent::__construct($url->routes, $url->request);
    }

    /**
     * Format the given URL segments into a single URL.
     *
     * @param string $root
     * @param string $path
     * @return string
     */
    public function format($root, $path, $route = null)
    {
        $path = parent::format($root, $path, $route);

        $matches = null;
        preg_match("/([^\/]+?)?$/", $path, $matches);
        $last = $matches[0] ?? '';

        if (strpos($last, ".") === false) {
            return $path . "/";
        }
        return $path;
    }
}

2. サービスプロバイダーへの登録

app/Providers/AppServiceProvider.php に、1. で作成したサービスを登録します。
以下の内容を追記してください。

// 一部を抜粋
use App\Services\Route\UrlGenerator;

public function register(): void
{
    // トレイリングスラッシュ付与
    $url = $this->app['url'];
    $this->app->singleton('url', function () use ($url) {
        return new UrlGenerator($url);
    });
}
GitHubで編集を提案

Discussion