Custom error pages in Laravel (for the same Exception)

Occasionally I can’t decide whether the question I’m asking about a piece of technology (in this case, Laravel) is so advanced as to no one understands it, or so simple that no one answers because they all assume I already know the answer. In either case, I didn’t get the answer to the following question:

I want to display a different template that’s dependent on the Model that’s not being found. I know I can create a resources/views/errors/404.blade.php template, but that would be used for ALL not founds. I want to use a different one if a ModelA isn’t found, and a different template if ModelB isn’t found.

Attempts & Confusion

The obvious place to look is in Laravel’s documentation, which has a fairly simple page on Errors & Logging (5.4). In there there’s a section about The render method, which says the following:

The render method is responsible for converting a given exception into an HTTP response that should be sent back to the browser. By default, the exception is passed to the base class which generates a response for you. However, you are free to check the exception type or return your own custom response:

/**
 * Render an exception into an HTTP response.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Exception  $exception
 * @return \Illuminate\Http\Response
 */
public function render($request, Exception $exception)  
{
    if ($exception instanceof CustomException) {
        return response()->view('errors.custom', [], 500);
    }

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

That’s cool, Laravel, but my exception is not going to be of the type CustomException, so this doesn’t help me much.

Further down there’s a section on HTTP Exceptions, and custom exception pages, but that talks about lumping ALL 404 errors into one template, which is specifically what I did not want to do.

Solution

In my frustration, after having tried unsuccessfully to get answers across two different Slack channels, I decided to just dd the contents of $request and $exception passed to the render method.

Turns out, all the data I needed was there. After following the exception classes up the chain and looking at available methods, this is the solution that I came up with:

    public function render($request, Exception $exception)
    {
        if (
            $exception instanceof ModelNotFoundException &&
            'ModelA' === $exception->getModel() &&
            view()->exists( 'errors.modela404' ) )
        {
            return response()->view( 'errors.modela404', [], 404 );
        }
        return parent::render($request, $exception);
    }

Of course the file at resources/views/errors/modela404.blade.php needs to exist :).