6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Laravel】return back() で何が起きてるか調べてみた

Posted at

#はじめに
バリデーションに失敗した場合など直前のページにリダイレクトする場合があるが、
そのときに使用するreturn back()について何が起こっているかを調べてみた。

example.php
Route::post('user/profile', function () {
    // リクエストのバリデート処理…

    return back(); // これが何をしているのか調べたい
});

#バージョン
PHP 7.4.20
Laravel 6.18.43

#前提知識
return back()のback()の正体はグローバルに定義されたヘルパ関数である。

無効なフォームが送信された場合など、まれにユーザーを直前のページへリダイレクトする必要が起きます。グローバルなbackヘルパ関数を使用することで行なえます。この機能はセッションを利用しているため、back関数を呼び出すルートがwebミドルウェアグループを使用しているか、全セッションミドルウェアを確実に適用してください。

参考:Laravel 6.x HTTPリダイレクト

#backヘルパの中身を見る

backヘルパ関数は以下にあった。
\laravel\vendor\laravel\framework\src\Illuminate\Foundation\helpers.php

helpers.php
if (! function_exists('back')) {
    /**
     * Create a new redirect response to the previous location.
     *
     * @param  int  $status
     * @param  array  $headers
     * @param  mixed  $fallback
     * @return \Illuminate\Http\RedirectResponse
     */
    function back($status = 302, $headers = [], $fallback = false)
    {
        return app('redirect')->back($status, $headers, $fallback);
    }
}

独自にbackというメソッドを定義していなければ、backメソッドを呼んだ時にbackヘルパが呼ばれる。
return back()ではapp('redirect')->back(302, [], false)を返している。

#app('redirect')->back(302, [], false)が何をしてるのか見る

app()自体もback同様にヘルパ関数であり、インスタンスを生成する。

app関数は、サービスコンテナのインスタンスを返します。
コンテナにより依存解決する、クラス名かインターフェイス名を渡すこともできます。

参考:Laravel 6.x ヘルパ

クラス名かインターフェイス名を渡すということだが、ここでは'redirect'という文字列を渡している。
\Illuminate\Foundation\Application.phpを見ると、'redirect'というエイリアスで[\Illuminate\Routing\Redirector::class]が登録されている。

Application.php
    public function registerCoreContainerAliases()
    {
        foreach ([
           // 他もいっぱいあるけど、多いので'redirect'以外は省略
           // ~~~
            'redirect'             => [\Illuminate\Routing\Redirector::class],
           // ~~~
           // 他もいっぱいあるけど、多いので'redirect'以外は省略
        ] as $key => $aliases) {
            foreach ($aliases as $alias) {
                $this->alias($key, $alias);
            }
        }
    }

したがってapp('redirect')->back(302, [], false)
Redirectorクラスのインスタンスを生成し、そのインスタンスのbackメソッドを(302, [], false)という引数で呼び出しているということになる。

#Redirectorクラスのback(302, [], false)が何をしてるのか見る

backメソッドでは同クラス内にあるcreateRedirectメソッドを呼んでいる。

Redirector.php
    public function back($status = 302, $headers = [], $fallback = false)
    {
        return $this->createRedirect($this->generator->previous($fallback), $status, $headers);
    }

#createRedirect($this->generator->previous($fallback), $status, $headers)が何をしてるのか見る

createRedirectメソッドの中ではtap関数にRedirectResoponseクラスのインスタンスとクロージャを渡している。

Redirector.php
    protected function createRedirect($path, $status, $headers)
    {
        return tap(new RedirectResponse($path, $status, $headers), function ($redirect) {
            if (isset($this->session)) {
                $redirect->setSession($this->session);
            }

            $redirect->setRequest($this->generator->getRequest());
        });
    }

tap関数はこれまたヘルパであり、第二引数のクロージャに第一引数を渡す(使うと見た目がすっきりする...らしい)。

第一引数はRedirectResponseクラスのインスタンスであり、コンストラクタとしてback関数から受け取った引数を渡す。

引数
$path generatorで作成された遷移直前のページのURI
$status HTTPレスポンスコード302(リダイレクト)
$headers HTTPレスポンスに設定するヘッダ

第二引数のクロージャではRedirectResponseクラスのインスタンスを受け取る。
Redirectorインスタンスにsessionが設定済の場合はRedirectorインスタンスが保持するsession変数をsessionに格納する。
その後setRequestメソッドで、生成したRedirectResponseインスタンスの$requestにgeneratorクラスのgetRequestメソッドで取得したrequestをセットする。

tap関数の戻り値は第一引数で受け取ったインスタンスになるので、
createRedirectで作成したRedirectResponseインスタンスが最終的なreturn back();の戻り値となり、リダイレクトが行われる。

#結論
return back()の戻り値は、直前のページのURI・レスポンスコード302を保持したRedirectResponseクラスのインスタンスである。

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?