🎻

[Symfony] 1つのコントローラアクションに複数のURLを割り当てる

2020/05/14に公開

要件

  • Shop の一覧画面がもともとあり、都道府県で検索できる機能も付いている
  • そのURLは /shop で、検索クエリは /shop?prefecture=aichi のようにURLパラメータで渡される
  • この、都道府県での検索結果の画面47パターンそれぞれに、 /shop/prefecture/aichi のような個別のURLを追加で割り当てたい

これを実現する方法を説明します。

解法

結論としては、ルーティングの記述をちょっと工夫するだけで簡単に実現できます。

このケースなら具体的には以下のようなコードになるでしょう。

class ShopController extends AbstractController
{
    /**
     * @Route("/shop/{prefecture?}", name="shop_index", requirements={"prefecture"="prefecture/[^/]+"})
     */
    public function index(Request $request, ?string $prefecture)
    {
        $prefecture = str_replace('prefecture/', '', $prefecture);

        if ($prefecture) {
            $request->query->set('prefecture', $prefecture);
        }

        // ...
    }
}

まず、ルーティングパラメータ {prefecture}? でnullableにすることで、「 / 以降に続きがあってもなくてもいい」状態にしています。(参考

これで、もともとの /shop というURLでも問題なくアクセスできる状態を保てます。

さらに、requirementsオプション を使って {prefecture} のパターンを正規表現で規定しています。これをしておかないと、 /shop/{id}/shop/{id}/edit などの他のURLも全部この index アクションにマッチしてしまうことになるので気をつけましょう。

あとは、ルーティングパラメータで受け取った都道府県名を表す文字列を prefecture クエリパラメータにセットしてあげることで、 /shop?prefecture=aichi のようなURLでアクセスしたときと同じ結果を返せるようにして完了です。

参考になれば幸いです🙂

GitHubで編集を提案

Discussion