Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I deliver an error page in Slim framework when an Exception is thrown outside of a route?

I'm trying to wrap my head around the order of operations for dealing with Exceptions thrown in a Slim framework app and the final page delivery. Basically, if I throw an Exception in a class I'd like Slim to deliver my pretty Twig 500 page, but I can't even get Slim to deliver its own normal error page when an exception is thrown outside of a route.

Given this database class constructor:

public function __construct(array $connection, \Slim\Slim $slim) {
  $this->slim = $slim;
  try {
    $this->db = new \PDO(...);
    $this->db->setAttribute(\PDO::ATTR_EMULATE_PREPARES, FALSE);
    $this->db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
 } catch (\PDOException $e) {
    // How can I kill further execution here and have Slim deliver a 500?
 }
}

If I run $this->slim->error(); I get Fatal error: Uncaught exception 'Slim\Exception\Stop'.

Ideally, I'd like to do something like:

  1. Log it via $this-slim->log->error("Unable to connect to database.");
  2. Stop attempting to execute further actions in my DB class (which would all fail and throw fatal exception)
  3. Deliver the page via a 500.twig template file.

Any help or direction would be much appreciated.

like image 242
Charlie Schliesser Avatar asked Jan 11 '23 16:01

Charlie Schliesser


1 Answers

You're running into grief because Slim's error handling hasn't been configured because your app never makes it all the way to \Slim\Slim::run().

Two things to do:

1) I recommend adding your database class (and other similar classes) into Slim's Dependency Injection container.

$app->container->singleton('db', function () use ($app) {
    return new Database($app);
});

That will allow lazy loading of your database connection. The class won't be created until you use it. At that point, and I'm assuming here, you will be in a route, \Slim\Slim::run() will have been called, and the Slim error handling will be in place.

2) Now that the exception isn't going to occur before your app is fully configured, you can use logging:

public function __construct(\Slim\Slim $app) {
    $this->slim = $app;

    try {
        $this->db = new \PDO('sqlite:/does/not/exist');
    } catch (\PDOException $p) {
        $this->slim->log->error('BAD THINGS');
        return $this->slim->error();
    }

    return $this;
}

along with Slim's custom error handling.

$app->error(function(\Exception $e) use ($app) {
    if ($e instanceof \PDOException) {
        return $app->render('500.twig', array(), 500);
    }
});
like image 105
Jeremy Kendall Avatar answered Jan 16 '23 20:01

Jeremy Kendall