This content originally appeared on Envato Tuts+ Tutorials and was authored by Sajal Soni
In this article, we're going to explore one of the most important and least discussed features of the Laravel web framework—exception handling. Laravel comes with a built-in exception handler that allows you to report and render exceptions easily and in a friendly manner.
In the first half of the article, we'll explore the default settings provided by the exception handler. In fact, we'll go through the default Handler class in the first place to understand how Laravel handles exceptions.
In the second half of the article, we'll go ahead and see how you could create a custom exception handler that allows you to catch custom exceptions.
Setting Up the Prerequisites
Before we go ahead and dive into the handler class straight away, let's have a look at a couple of important configuration parameters related to exceptions.
Go ahead and open the config/app.php file. Let's have a close look at the following snippet.
... /* |-------------------------------------------------------------------------- | Application Debug Mode |-------------------------------------------------------------------------- | | When your application is in debug mode, detailed error messages with | stack traces will be shown on every error that occurs within your | application. If disabled, a simple generic error page is shown. | */ 'debug' => (bool) env('APP_DEBUG', false), ... ...
As the name suggests, if it's set to TRUE
, it'll help you to debug errors that are generated by an application. The default value of this variable is set to a value of the APP_DEBUG
environment variable in the .env file.
In the development environment, you should set it to TRUE
so that you can easily trace errors and fix them. On the other hand, you want to switch it off in the production environment, and it'll display a generic error page in that case.
Logging Configuration File
In addition to displaying errors, Laravel allows you to log errors in the log file. Let's have a quick look at the options available for logging. Let's visit the config/logging.php file and have a close look at the following snippet.
<?php use Monolog\Handler\NullHandler; use Monolog\Handler\StreamHandler; use Monolog\Handler\SyslogUdpHandler; return [ /* |-------------------------------------------------------------------------- | Default Log Channel |-------------------------------------------------------------------------- | | This option defines the default log channel that gets used when writing | messages to the logs. The name specified in this option should match | one of the channels defined in the "channels" configuration array. | */ 'default' => env('LOG_CHANNEL', 'stack'), /* |-------------------------------------------------------------------------- | Log Channels |-------------------------------------------------------------------------- | | Here you may configure the log channels for your application. Out of | the box, Laravel uses the Monolog PHP logging library. This gives | you a variety of powerful log handlers / formatters to utilize. | | Available Drivers: "single", "daily", "slack", "syslog", | "errorlog", "monolog", | "custom", "stack" | */ 'channels' => [ 'stack' => [ 'driver' => 'stack', 'channels' => ['single'], 'ignore_exceptions' => false, ], 'single' => [ 'driver' => 'single', 'path' => storage_path('logs/laravel.log'), 'level' => 'debug', ], 'daily' => [ 'driver' => 'daily', 'path' => storage_path('logs/laravel.log'), 'level' => 'debug', 'days' => 14, ], 'slack' => [ 'driver' => 'slack', 'url' => env('LOG_SLACK_WEBHOOK_URL'), 'username' => 'Laravel Log', 'emoji' => ':boom:', 'level' => 'critical', ], 'papertrail' => [ 'driver' => 'monolog', 'level' => 'debug', 'handler' => SyslogUdpHandler::class, 'handler_with' => [ 'host' => env('PAPERTRAIL_URL'), 'port' => env('PAPERTRAIL_PORT'), ], ], 'stderr' => [ 'driver' => 'monolog', 'handler' => StreamHandler::class, 'formatter' => env('LOG_STDERR_FORMATTER'), 'with' => [ 'stream' => 'php://stderr', ], ], 'syslog' => [ 'driver' => 'syslog', 'level' => 'debug', ], 'errorlog' => [ 'driver' => 'errorlog', 'level' => 'debug', ], 'null' => [ 'driver' => 'monolog', 'handler' => NullHandler::class, ], 'emergency' => [ 'path' => storage_path('logs/laravel.log'), ], ], ];
Laravel logging is based on channels. Each channel provides a different way of writing log information. For example, the single
channel writes logs to the log file, and the slack
channel is used to send logs to Slack to notify your team. As Laravel uses the Monolog PHP library for logging, you should set the above options in the context of that library. By default, Laravel uses the stack
channel for logging messages.
The default log file is located at storage/logs/laravel.log, and it's sufficient in most cases. On the other hand, the level
attribute in the channel configuration is set to a value that indicates the severity of errors that'll be logged.
The Handler
Class
Next, let's have a look at the default Handler
class that comes with the default Laravel application. Go ahead and open the app/Exceptions/Handler.php file.
<?php namespace App\Exceptions; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; use Throwable; class Handler extends ExceptionHandler { /** * A list of the exception types that are not reported. * * @var array */ protected $dontReport = [ // ]; /** * A list of the inputs that are never flashed for validation exceptions. * * @var array */ protected $dontFlash = [ 'password', 'password_confirmation', ]; /** * Report or log an exception. * * @param \Throwable $exception * @return void * * @throws \Throwable */ public function report(Throwable $exception) { parent::report($exception); } /** * Render an exception into an HTTP response. * * @param \Illuminate\Http\Request $request * @param \Throwable $exception * @return \Symfony\Component\HttpFoundation\Response * * @throws \Throwable */ public function render($request, Throwable $exception) { return parent::render($request, $exception); } }
There are two important functions that the handler class is responsible for—reporting and rendering all errors.
Let's have a close look at the report
method.
/** * Report or log an exception. * * @param \Throwable $exception * @return void * * @throws \Throwable */ public function report(Throwable $exception) { parent::report($exception); }
The report
method is used to log errors to the log file. At the same time, it's also important to note the dontReport
property, which lists all types of exceptions that shouldn't be logged.
Next, let's bring in the render
method.
/** * Render an exception into an HTTP response. * * @param \Illuminate\Http\Request $request * @param \Throwable $exception * @return \Symfony\Component\HttpFoundation\Response * * @throws \Throwable */ public function render($request, Throwable $exception) { return parent::render($request, $exception); }
If the report
method is used to log or report errors, the render
method is used to render errors on a screen. In fact, this method handles what will be displayed to users when the exception occurs.
The render
method also allows you to customize a response for different types of exceptions, as we'll see in the next section.
Custom Exception Class
In this section, we'll create a custom exception class that handles exceptions of the CustomException
type. The idea behind creating custom exception classes is to easily manage custom exceptions and render custom responses at the same time.
Go ahead and create a file app/Exceptions/CustomException.php with the following contents.
<?php namespace App\Exceptions; use Exception; class CustomException extends Exception { /** * Report the exception. * * @return void */ public function report() { } /** * Render the exception into an HTTP response. * * @param \Illuminate\Http\Request * @return \Illuminate\Http\Response */ public function render($request) { return response()->view( 'errors.custom', array( 'exception' => $this ) ); } }
The important thing to note here is that the CustomException
class must extend the core Exception
class. For demonstration purposes, we'll only discuss the render
method, but of course you could also customize the report method.
As you can see, we're redirecting users to the errors.custom
error page in our case. In that way, you can implement custom error pages for specific types of exceptions.
Of course, we need to create an associated view file at resources/views/errors/custom.blade.php.
Exception details: <b>{{ $exception->getMessage() }}</b>
That's a pretty simple view file that displays an error message, but of course you could design it the way you want it to be.
We also need to make changes in the render method of the app/Exceptions/Handler.php file so that our custom exception class can be invoked. Let's replace the render
method with the following contents in the app/Exceptions/Handler.php file.
/** * Render an exception into an HTTP response. * * @param \Illuminate\Http\Request $request * @param \Throwable $exception * @return \Symfony\Component\HttpFoundation\Response * * @throws \Throwable */ public function render($request, Throwable $exception) { if ($exception instanceof \App\Exceptions\CustomException) { return $exception->render($request); } return parent::render($request, $exception); }
As you can see, we are checking the type of an exception in the render method in the first place. If the type of an exception is \App\Exceptions\CustomException
, we call the render
method of that class.
How to Test Our CustomException
Class?
So everything is in place now. Next, let's go ahead and create a controller file at app/Http/Controllers/ExceptionController.php so we can test our custom exception class.
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller; class ExceptionController extends Controller { public function index() { // something went wrong and you want to throw CustomException throw new \App\Exceptions\CustomException('Something Went Wrong.'); } }
Of course, you need to add an associated route in the routes/web.php as shown in the following snippet.
// Exception routes Route::get('exception/index', 'ExceptionController@index');
And with that in place, you can visit the https://your-laravel-site.com/exception/index URL to see if it works as expected. It should display the errors.custom
view as per our configuration.
So that's how to handle custom exceptions in Laravel.
Conclusion
Today, we went through the exception handling feature in Laravel. At the beginning of the article, we explored the basic configuration provided by Laravel in order to render and report exceptions. Further, we had a brief look at the default exception handler class.
In the second half of the article, we prepared a custom exception handler class that demonstrated how you could handle custom exceptions in your application.
This content originally appeared on Envato Tuts+ Tutorials and was authored by Sajal Soni
Sajal Soni | Sciencx (2017-12-18T18:03:03+00:00) Exception Handling in Laravel. Retrieved from https://www.scien.cx/2017/12/18/exception-handling-in-laravel/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.