Exceptions in Laravel 4

Update: Now the preliminary documentation is out for Laravel 4, it seems there is a simple way to throw 404 errors:

<?php

App::abort(404);  

You can then catch this error by registering a missing handler in app/start/global.php:

<?php  
App::missing(function($exception) {  
    return Response::make(
        View::make('errors/404')
    , 404);
});

However, read on through the original post below for examples on how to register custom Exceptions you can throw to improve your application's flow.


Original Post: Perhaps this will change before Laravel 4 is officially released, but I can't find any simple way to throw, for example, a 404 Not Found exception.

Here's a clean solution.

Create a new file inside app/ named exceptions.php. In here, we'll define any exceptions. For a small app I'm working on, I require a "Not Found" and "Not Allowed" exceptions:

<?php  
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class NotFoundException extends NotFoundHttpException {}  
class NotAllowedException extends Exception {}  

We now need to load require this file with Composer. Open up composer.json and under autoload.classmap, add in app/exceptions.php, like so:

{
  "require": {
    "illuminate/foundation": "1.2.*"
  },
  "autoload": {
    "classmap": [
      "app/exceptions.php",
      "app/controllers",
      "app/models",
      "app/database/migrations",
      "app/tests/TestCase.php"
    ]
  },
  "minimum-stability": "dev"
}

Don't forget to composer dumpautoload from the terminal.

Now you're free to throw your NotFoundException and NotAllowedException in your controllers.

<?php  
class JobsController extends BaseController {  
  public function show($id) {
    if ( ! $job = Job::find($id)) {
      throw new NotFoundException;
    }

    return View::make('jobs/show')->with('job', $job);
  }
}

Finally, we need to define error handlers for these exceptions. Inside app/start/global.php, add the following inside the "Application Error Handler" section:

<?php  
// ...

App::error(function(NotFoundException $exception, $code) {  
  return Response::make(View::make('errors/404'), 404);
});

App::error(function(NotAllowedException $exception, $code) {  
  return Redirect::to('/')
    ->with('error', 'You do not have permission to do that');
});

When a NotFoundException is thrown, we're displaying the view at app/views/errors/404. We're passing this through the Response class so that we can specify the HTTP Status Code as 404.

When a NotAllowedException is thrown, we're redirecting back to the home page, with an error message.

There's a debate over whether you should raise exceptions as part of your application flow. Personally, I'm a fan of it for this use-case.