Handling Laravel's ModelNotFoundException (Nonexistent records)

  • March 29, 2016

Welcome to the incredibly popular Easy Laravel 5 companion blog. To celebrate the new edition's release (updated for Laravel 5.5!) use the discount code easteregg to receive 20% off the book or book/video package! » Buy the book

Laravel's find() method works great in a perfect world, but what happens if the user attempts to access a record that doesn't exist, such as /lists/23245? The find method would return a null value, meaning any attempts to retrieve a property of a non-object within the view would result in a view exception. Logically you'll want to avoid this sort of mishap, and can do so using the findOrFail method instead:

$list = Todolist::findOrFail($id);

If the desired record is not found, an exception of type ModelNotFoundException will be thrown. One easy way to handle this exception is by catching it directly within the action:

public function show($id)
{

    try {

      $list = Todolist::findOrFail($id);
      return view('lists.show')->with('list', $list);

    } catch(ModelNotFoundException $e) {

        return \Redirect::route('lists.index')
                  ->withMessage('Record not found');

    }

}

After modifying the action, test the changes out out by accessing some record you know to not exist, such as /lists/42. The non-existent ID will be passed to findOrFail, presumably not be found, and redirect the user to the Lists controller with an accompanying error message.

If you'd prefer to configure your application to automatically respond to any ModelNotFound exceptions with a standard 404 page, modify the app/Exceptions/Handler.php's render() method to look like this:

public function render($request, Exception $e)
{

    if ($e instanceof \Illuminate\Database\Eloquent\ModelNotFoundException) 
    {
        abort(404);
    }

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

}

That abort() function will result in a view named 404.blade.php being rendered. This view doesn't yet exist, but as you know by now creating it is easy enough. Just make sure you place it in resources/views/errors, because this is Laravel's default location for storing these error-oriented views.