Customizing The “Not Found” Behavior of Laravel

2019-06-14 01:21发布

问题:

Here's the documentation: https://laravel.com/docs/5.2/routing#route-model-binding

The routes:

Route::group(['prefix' => 'u'], function () {
    Route::post('create', ['as' => 'createUser', 'uses' => 'UserController@create']);
    Route::get('{uuid}', ['as' => 'userDashboard', 'uses' => 'UserController@dashboard']);
});

The UserController.php:

public function dashboard(User $uuid)
{
    return View::make('user.dashboard');
}

Whenever the User isn't found in the database it throws these two exceptions:

2/2
NotFoundHttpException in Handler.php line 103:
No query results for model [App\User].

1/2
ModelNotFoundException in Builder.php line 303:
No query results for model [App\User].

How do I customize the error? I want to redirect to the createUser route. The documentation instructs to pass a Closure as a third argument but I don't know how to do that with my current code.

EDIT 1

This is what I've tried so far without success:

   Route::model('{uuid}', ['as' => 'userDashboard', 'uses' => 'UserController@dashboard'], function () {
        App::abort(403, 'Test.');
    });

   Route::get('{uuid}', ['as' => 'userDashboard', 'uses' => 'UserController@dashboard'], function () {
        App::abort(403, 'Test.');
    });

回答1:

This is actually very simple. As none of the answers really give a definite answer I am answering it myself.

In the file RouteServiceController.php's boot function add the following:

    $router->model('advertiser', 'App\Advertiser', function () {
        throw new AdvertiserNotFoundException;
    });

Then create a new empty class in App\Exceptions called (in this case) AdvertiserNotFoundException.php:

<?php

namespace App\Exceptions;

use Exception;

class AdvertiserNotFoundException extends Exception
{

}

The last thing to do is to catch the exception in the Handler.php's render function (App\Exception) like so:

public function render($request, Exception $e)
{
    switch ($e)
    {
        case ($e instanceof AdvertiserNotFoundException):
            //Implement your behavior here (redirect, etc...)
    }
    return parent::render($request, $e);
}

That's it! :)



回答2:

for a similar case i did, I took the parent Illuminate\Foundation\Exceptions\Handler isHttpException function and copied it to app/Exceptions/Handler.php and changed it's name to my isUserNotFoundException.

protected function isUserNotFoundException(Exception $e)
{
    return $e instanceof UserNotFoundException;
}

and than in the render function add

  if ($this->isUserNotFoundException($e))
       return redirect('path')->with('error',"Your error message goes here");

Following code must be placed in your RouteServiceProvider::boot method

$router->model('uuid', 'App\User', function () {
throw new UserNotFoundException;

});

and make sure to include this in your view file

and this forum post might help you

https://scotch.io/tutorials/creating-a-laravel-404-page-using-custom-exception-handlers


回答3:

To do so you need to check if the id exist in the model like so:

public function dashboard(User $uuid)
{
    if(User::find($uuid))
    {
        return View::make('user.dashboard');
    } else {
        redirect('xyz');
    }
}


回答4:

I think this tutorial will be helpful for you Laravel Model Binding



回答5:

You could add the exception and treat in in app/Exceptions/Handler.php

/**
 * Render an exception into an HTTP response.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Exception  $e
 * @return \Illuminate\Http\Response
 */
public function render($request, Exception $e)
{
    if (!env('APP_DEBUG')) {      
        if ($e instanceof \Illuminate\Database\Eloquent\ModelNotFoundException) {
            //treat error
            return response()->view('errors.404');
    }

    return parent::render($request, $e);
}

Edit 1: This piece of code is from a working project so if this doesn't work it must have an error somewhere else:

if ($e instanceof \Illuminate\Database\Eloquent\ModelNotFoundException) {
    $data= \App\Data::orderBy('order', 'asc')->get();                              
    return response()->view('errors.404', [
        'data' => $data                  
    ], 404);
}

Edit 2: You can use the above code and this tutorial in order to create a new Exception type in order to get your desired behavior. To my understanding at least. :)