Laravelのコントローラにおいて、abort(404)のヘルパーをコールすることで簡単に予期しないアクセスを、Not Foundのエラーページの表示ができます。しかし、Not Foundページの代わりにリダイレクトして違うページに飛ばしたいときには、redirect()のヘルパーをabort()同様に好きな場所で使うことはできません。


そう書いても何を言っているかわからないと思いますので、まず、商品(Product)の情報を閲覧するコントローラを使って、abort()redirect()の紹介から。

abort()は以下のように単独でコードに配置します。

namespace App\Http\Controllers;

use App\Product;
use App\Http\Controllers\Controller;

class ProductController extends Controller
{
    public function show(Product $product)
    {
        if ($product->active_flag == 'N') { // 無効な商品なら、
    	    abort(404); // Not Foundページを表示
        }

        return view('user.product.show')->with(compact('product')); // 商品のページを表示
    }
}

しかし、redirect()は、以下のようにreturnが必要です。

...
class ProductController extends Controller
{
    public function show(Product $product)
    {
        if ($product->active_flag == 'N') { // 無効な商品なら、
    	    return redirect('home'); // ホームページにリダイレクト
        }

        return view('user.product.show')->with(compact('product')); // 商品のページを表示
    }
}

この違いは、abort()Http Exceptionthrowするのに対して、redirect()は、\Illuminate\Http\RedirectResponseのオブジェクトを返すからです。

さて、上のコントローラを変更して、以下のように条件文を新規のメソッドに移します。現在の条件は簡単だけれど将来はたいそう複雑になるぞ、という仮定です。

...
class ProductController extends Controller
{
    public function show(Product $product)
    {
        $this->checkProduct($product); // 条件文が複雑になるので新規の関数を作成

        return view('user.product.show')->with(compact('product')); // 商品のページを表示
    }

    private function checkProduct($product)
    {
        if ($product->active_flag == 'N') { // 無効な商品なら、
    	    return redirect('home'); // ホームページにリダイレクト
        }
    }
}

一見たわいもない変更ですが、これを実行すると、なんと無効である商品の表示ページが表示されます。ホームページにリダイレクトはされません。問題は、checkProduct()RedirectResponseを返すのに、コールした側でreturnが使用されていないからなのですね。

しかし、

...
class ProductController extends Controller
{
    public function show(Product $product)
    {
        return $this->checkProduct($product);

        return view('user.product.show')->with(compact('product')); // 商品のページを表示
...

こうすると、商品が有効なときもそこでリターンするために商品のページが表示されずに問題です。さてさて、どうしたらよいでしょう?

ということで、あれこれ調べていたら、abort()を使用してリダイレクトが可能なことがわかりました。以下のように、abort()の引数に404のようなHttpステータスのコードの代わりにredirect()を渡すことが可能なのです。以下が変更後のコードです。素晴らしい!

...
class ProductController extends Controller
{
    public function show(Product $product)
    {
        $this->checkProduct($product); // 条件文が複雑になるので新規の関数を作成

        return view('user.product.show')->with(compact('product')); // 商品のページを表示
    }

    private function checkProduct($product)
    {
        if ($product->active_flag == 'N') { // 無効な商品なら、
    	    abort(redirect('home')); // ホームページにリダイレクト
        }
    }
}

By khino