When Laravel switched to a simpler exception page, the ability to display solutions for an exception was lost.

Our latest package, called spatie/laravel-error-solutions brings back that powerful feature. When installed, it will display solutions for most common exceptions.

Here’s how that looks it:

And yes, some solutions, like the one in the screenshot above, can be executed on the exception page too.

In this blog post, I’d like to tell you all about it!

Displaying and running solutions

Getting started with the package is quite easy. Just install it using Composer, and you’re done.

composer require spatie/laravel-error-solutions

When you now get an exception the package knows a solution for, it will display it on the exception page.

Here’s how that looks like when you slightly misspell a method name

For some solutions, the package will display a button that will automatically run the solution. Here’s how that looks when you forget to set the APP_KEY in your .env file.

When you click that button, an app key will be generated and saved in your .env file. Pretty sweet!

Another handy runnable solutions is when you an exception occurs when saving a model, and one of its attributes does not have a column in the database. Probably you should forgot to run migration. Well the package has a runnable solution for that common mistake as well.

Runnable solutions will only be available in local development environments. The package contains a dedicated class to determine when it’s save to run a solution.

AI-powered solutions

The package comes with a nice collection of solution for common exceptions. Of course, we can’t foresee each and every possible exception.

However, the package can send exceptions to Open AI to automatically suggest a solution. In many cases, the suggested solutions are quite useful, but keep in mind that the solution may not be 100% correct for your context.

To generate AI powered solutions, you must first install this optional dependency.

composer require openai-php/client

To send your errors to OpenAI, you must set ERROR_SOLUTIONS_OPEN_AI_KEY in your .env file. The value should be your OpenAI key.

These bits of info will be sent to Open AI:

the error message
the error class
the stack frame
other small bits of info of context surrounding your error

It will not send the request payload or any environment variables to avoid sending sensitive data to OpenAI.

Creating your own solutions

In addition to the built-in solution and AI solutions, you can define your own solutions for your particular exceptions.

First, you need to create a Solution class: a simple PHP class that implements the SpatieErrorSolutionsContractsSolution interface.

Here’s a simple example.

class MySolution implements Solution
{
public function getSolutionTitle(): string
{
returnMy custom solution‘;
}

public function getSolutionDescription(): string
{
returnMy custom solution description‘;
}

public function getDocumentationLinks(): array
{
return [
Spatie docs‘ => ‘https://spatie.be/docs‘,
];
}
}

Optionally, you can add “provided by” information to a solution by implementing these methods.

// in your solution class

public function solutionProvidedByName(): string
{
returnFlare‘;
}

public function solutionProvidedByLink(): string
{
returnhttps://flareapp.io‘;
}

You can add a solution to an exception directly. Let your exception implement the ProvidesSolution interface and let the getSolution method return your solution.

use Exception;
use SpatieErrorSolutionsContractsSolution;
use SpatieErrorSolutionsContractsProvidesSolution;

class ExceptionWithSolution extends Exception implements ProvidesSolution
{
public function __construct(string $message = ”)
{
parent::__construct($message ?? ‘My custom exception‘);
}

public function getSolution(): Solution
{
return YourSolution::class,
}
}

If you want to add solutions to exceptions that you can’t modify, you can use a solution provider. A solution provider is a class that implements the ProvidesSolution interface. It will determine if it can provide a solution for a given exception.

Here’s an example:

use SpatieErrorSolutionsContractsHasSolutionsForThrowable;
use SpatieErrorSolutionsContractsSolution;
use Throwable;

class YourSolutionProvider implements HasSolutionsForThrowable
{
public function canSolve(Throwable $throwable): bool
{
// return true if you can provide a solution for this exception
}

/**
* @param Throwable $throwable
*
* @return array<int, Solution>
*/

public function getSolutions(Throwable $throwable): array
{
// return an array of solutions
}
}

After you’ve created your solution provider, you can register it in the solution_providers key of the error-solutions.php config file:

// config/error-solutions.php

return [
solution_providers‘ => [
// other solution providers
YourSolutionProvider::class,
],
];

Alternatively, you can register your solution provider at runtime. Typically, this would be done in a service provider:

// app/Providers/YourServiceProvider.php

use SpatieErrorSolutionsErrorSolutionsServiceProvider;
use SpatieErrorSolutionsContractsSolutionProviderRepository;

public function register()
{
$repository = app(SolutionProviderRepository::class);

$repository->registerSolutionProviders([
YourSolutionProvider::class,
]);
}

Seeing solutions in production environments

Laravel’s error page displays sensitive information, and it should never be shown in production environments. If debug mode is enabled in production environments, you’re doing something wrong.

However, it is still possible to see solutions for production environments. At Spatie, we built Flare, an exception tracker built for Laravel apps. It displays all important information around an exception in a beautiful, easy-to-use UI.

When you use Flare as your exception tracker, solutions will also be generated and displayed. Here’s how that looks like.

You can try Flare using our free 10-day trial.

How the package works under the hood

Let’s take a look at how we manage to hook into Laravel’s error page.

The Laravel error page consists of a couple of Blade views that are registered using the laravel-exceptions-renderer view namespace.

In our service provider, we register our own view directory under the same namespace.

View::prependNamespace(‘laravel-exceptions-renderer‘, [
__DIR__.’/../resources/views‘,
]);

This means that Laravel will look in our view directory first when in tries to render the error page.

We render the solutions in the header part of the error page. In our views directory, we have a file header.blade.php that contains the same content as the file with the same name in the framework. So Laravel will use our header.blade.php file instead of the one that ships with the framework.

In our header.blade.php we’ve added one line near the end.

<x-laravel-exceptions-renderer::solution />

So in addition to the normal header, we also render the solution.blade.php file that ships with the package.

That solution.blade.php file, which is a bit too lengthy to inline in this blog post, contains everything regarding solutions: we call an action to determine the solutions, the styling of the solution, and the necessary HTML.

In closing

Our Laravel Error Solutions package can help you fix your exceptions faster by displaying a solution right next to the exception locally.

If you want this ability for your production environment, check out Flare.

Of course, this package isn’t the first we built. At Spatie, we have a big heart for open source. You’ll find a list of all of our packages here.

Want to support us? Consider buying one of our paid products, or subscribe to Mailcoach or Flare.

Categories: PHP