Laravelで画面遷移後に元のページへリダイレクトさせてみる（ミドルウェア使用）

# はじめに
Laravelでデータ登録などを行った際に、元々見ていたページ（URL）にリダイレクトさせたいと思い調べたところ、意外と簡単だったので、忘れないようにメモ書きです。

**初学者でも、5分あれば実装できます！！**

## 使用環境
- PHP8
- Laravel10（以下の3種類で実装できます）
    - Middleware
    - Http / Karnel.php
    - Controller

# 簡単4ステップ! 実装手順
### ⑴ 専用のMiddlewareを作成する
※「SaveLastVisitedUrl」を好きな名前に置き換える（大文字から始める）
```command:bash
% php artisan make:middleware SaveLastVisitedUrl
```


### ⑵ Middlewareにコードを書く

```php:Middleware / SaveLastVisitedUrl.php
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class SaveLastVisitedUrl
{
    public function handle(Request $request, Closure $next)
    {
        // headerの中にある 「referer」 が前ページのURLを持っているため取得する
        $referer = $request->headers->get('referer');

        // 前のURLが存在し、同じホスト内のURLであることを確認してからセッションに保存
        if ($referer && parse_url($referer, PHP_URL_HOST) === $request->getHost()) {
            $request->session()->put('previous_url', $referer);
        }

        return $next($request);
    }
}
```
Controllerに直接書かず、ミドルウェアに書く利点は、アプリケーション全体でひとつ前のページが取得できるようになること。sessionに保存してあるため、好きなタイミングで取得することが可能になる。


### ⑶ Http / Karnelにミドルウェアを追加する

```php:Http / Karnel.php
// $middlewareGroups 内の web の中に作成したミドルウェアを登録する
protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\SaveLastVisitedUrl::class,
    ],
]
```
ここまでで使用する準備が完了！
あとはControllerなどで使用するだけ。


### ⑷ 使い方
#### Contorollerでの受け取り方について
```php:ContentContoroller.php 
// 例えば削除後のリダイレクトに、保存したURLを使いたい場合の例
public function destroy(Request $request)
{
    // - 必要な処理を記述 - 

    // ミドルウェアが保存してくれてるsessionからURLを取得する
    $previousUrl = $request->session()->get('previous_url');
    if ($previousUrl) {
        // セッションから前のURLを削除（次回のリクエストで同じURLにリダイレクトしないように）
        $request->session()->forget('previous_url');
        return redirect($previousUrl);
    }
    return redirect(route('content.index'));
}
```

#### bladeでの受け取り方について
以下のようにすればbladeで使うこともできます。
```php:ContentContoroller.php 
// 例えば削除後のリダイレクトに、保存したURLを使いたい場合の例
public function create(Request $request)
{
    // - 必要な処理を記述 - 

    // ミドルウェアが保存してくれてるsessionからURLを取得する
    $previousUrl = $request->session()->get('previous_url');  
    return view('content.create',compact('previousUrl'));
}
```
```php:create.blade.php 
<button type="submit" @if($previousUrl) onclick="location.href='{{ url($previousUrl) }}'" @else onclick="location.href='{{ url('/') }}'" @endif>戻る</button>
```

このようにすれば、簡単に元々見ていた画面へのリダイレクトが可能になります！
$requestを利用した、テーブルの絞り込み等を実装している場合にはとても役に立つのではないかと思います。


## 注意点
:::note warn
**注意**
今回のコードは、**ひとつ前のURLを取得**して変数に格納しています。
そのため、storeメソッドやupdateメソッドのように

 　　【元の画面 → create → store → 元の画面に戻る】
  
 **2回以上のリダイレクト**が発生する場合は、一度createメソッドで変数を取得してstoreメソッドに元の画面のURLを渡す必要があります。
:::

#### 2回以上のリダイレクトを挟む場合の書き方
```php:ContentContoroller.php 
// 例えば削除後のリダイレクトに、保存したURLを使いたい場合の例
public function create(Request $request)
{
    // - 必要な処理を記述 - 

    // セッションから前のURLを取得
    $previousUrl = $request->session()->get('previous_url');
    // セッションに'two_previous_url'を追加する
    $request->session()->put('two_previous_url', $previousUrl);
    
    return view('content.edit', compact('必要に応じて書く'));
}

public function store(Request $request)
{
    // - 必要な処理を記述 - 

    // セッションに含まれるtwo_previous_urlのURLを取得
    $previousUrl = $request->session()->get('two_previous_url');
    if ($previousUrl) {
        $request->session()->forget('two_previous_url');
        return redirect($previousUrl);
    }
    return redirect()->route('content.index');
}
```

このようにすることで、2つ前のURL、3つ前のURL…と取得していくことが可能になります。
取得したいURLがいくつ前のページなのか把握できる時は、この方法で問題ないかと思います。

## あとがき
今回はヘッダーに含まれる「referer」を、ミドルウェアやコントローラを用いて、セッションに直接保存をかける方法で実装を行いました。

他にもCookieを使用した方法や、$requestに直接保存する方法などもあるようなので、プロジェクトの規模や方向性に適するものを選ぶ必要があるのではないかと感じます。

ただ小規模な個人開発や学習段階では、これぐらいの実装で十分なのではないでしょうか☺️

　　　
進捗があり次第、更新しますね。

それではまたいつか！