18

I'm starting out in Laravel and want to discover more about using error handling especially the ModelNotFoundException object.

<?php
 class MenuController extends BaseController {

    function f() {
          try {
                $menus = Menu::where('parent_id', '>', 100)->firstOrFail();
            } catch (ModelNotFoundException $e) {
                $message = 'Invalid parent_id.';
                return Redirect::to('error')->with('message', $message);
            }
        return $menus;
    }
  }
?>

In my model:

<?php
 use Illuminate\Database\Eloquent\ModelNotFoundException;  

 class Menu extends Eloquent {
    protected $table = 'categories'; 
}

?>

Of course for my example there are no records in 'categories' that have a parent_id > 100 this is my unit test. So I'm expecting to do something with ModelNotFoundException.

If I run http://example.co.uk/f in my browser I receive:

Illuminate \ Database \ Eloquent \ ModelNotFoundException
No query results for model [Menu].

the laravel error page - which is expected, but how do I redirect to my route 'error' with the pre-defined message? i.e.

<?php
// error.blade.php

{{ $message }}
?>

If you could give me an example.

cookie
  • 2,546
  • 7
  • 29
  • 55

4 Answers4

15

In Laravel by default there is an error handler declared in app/start/global.php which looks something like this:

App::error(function(Exception $exception, $code) {
    Log::error($exception);
});

This handler basically catches every error if there are no other specific handler were declared. To declare a specific (only for one type of error) you may use something like following in your global.php file:

App::error(function(Illuminate\Database\Eloquent\ModelNotFoundException $exception) {

    // Log the error
    Log::error($exception);

    // Redirect to error route with any message
    return Redirect::to('error')->with('message', $exception->getMessage());
});

it's better to declare an error handler globally so you don't have to deal with it in every model/controller. To declare any specific error handler, remember to declare it after (bottom of it) the default error handler because error handlers propagates from most to specific to generic.

Read more about Errors & Logging.

The Alpha
  • 143,660
  • 29
  • 287
  • 307
  • 1
    I think he should return a Response::view with a 404 header, instead of redirecting to a different page – andrewtweber Jan 31 '15 at 17:29
  • but sometimes you know your controller will only fail at some point. And at that point, you want them to return to where user was before (or to a particular url), or just send a customized AJAX error to browser. – Raynal Gobel Jun 01 '15 at 07:42
  • 1
    I agree with this answer. But, I'm wondering if a global error handler is really better than local ones. Because I think (and here I'm thinking more on the user experience) that a message related with the action that the user was doing is better than a generic message. I'm looking for a way to do it using global handlers but until now I haven't found it – Victor Leal Apr 24 '16 at 17:54
12

Just use namespace

try {
    $menus = Menu::where('parent_id', '>', 100)->firstOrFail();
}catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
    $message = 'Invalid parent_id.';
    return Redirect::to('error')->with('message', $message);
}

Or refer it to an external name with an alias

use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException;
Razor
  • 9,577
  • 3
  • 36
  • 51
4

When you use the render() function in Laravel 8.x and higher versions, you will encounter 500 Internal Server Error. This is because with Laravel 8.x errors are checked within the register() function (Please check this link)

I'm leaving a working example here:

namespace App\Exceptions;

use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Throwable;

class Handler extends ExceptionHandler
{
    public function register()
    {

        $this->renderable(function (ModelNotFoundException $e, $request) {
            return response()->json(['status' => 'failed', 'message' => 'Model not found'], 404);
        });
        $this->renderable(function (NotFoundHttpException $e, $request) {
            return response()->json(['status' => 'failed', 'message' => 'Data not found'], 404);
        });
    }
}
Mehmet Bütün
  • 749
  • 9
  • 19
  • unfortunately ModelNotFoundException renderable not working in Laravel 9. we need to do it as like https://stackoverflow.com/a/75492554/14344959 this answer – Harsh Patel Feb 18 '23 at 10:05
1

Try this

  try {

      $user = User::findOrFail($request->input('user_id'));

    } catch (ModelNotFoundException $exception) {

       return back()->withError($exception->getMessage())->withInput();
    }

And to show error, use this code in your blade file.

 @if (session('error'))
   <div class="alert alert-danger">{{ session('error') }}</div>
 @endif

And of course use this top of your controller

use Illuminate\Database\Eloquent\ModelNotFoundException;  
Mahedi Hasan Durjoy
  • 1,031
  • 13
  • 17