Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel 7 email exceptions broke after Symfony 5 update

I've upgraded to Laravel 7.1 and now with Symfony 5 these classes no longer exist:

use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\Debug\ExceptionHandler as SymfonyExceptionHandler;

I used them in my app\Exceptions\Handler.php file to send email notifications when exceptions re thrown and they worked well in Laravel 6, but broke when I upgrade from 6.x to 7.1.2 which also upgraded to Symfony 5.

I replaced the aforementioned classes with these:

use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer;
use Symfony\Component\ErrorHandler\Exception\FlattenException;

and then replaced this:

$e = FlattenException::create($exception);
$handler = new SymfonyExceptionHandler();
$html = $handler->getHtml($e);

with this:

$e = FlattenException::create($exception);
$handler = new HtmlErrorRenderer();
$content = $handler->getBody($e);

which works, but now instead of getting the debug content in the email like I used to, I instead get a more basic error message as it would be intended for the public.

You can see examples of the different formats here: https://symfony.com/doc/current/controller/error_pages.html

I'm sure there is something simple I'm missing, but I haven't yet figured out how to get it to send me the detailed exception data like I used to get prior to the upgrade.

Any suggestions?

like image 611
climbd Avatar asked Mar 14 '20 14:03

climbd


2 Answers

Below is the code I ended up using to get the results I wanted in the exception notification email. The primary piece I was missing earlier is that I wasn't passing a true value into the HtmlErrorRender class to raise the debug flag. The corrected line is shown here:

new HtmlErrorRenderer(true);

Here is the complete code I am using now for the app/Exceptions/Handler.php file

<?php

namespace App\Exceptions;

use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Log;
use Throwable;
use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer;
use Symfony\Component\ErrorHandler\Exception\FlattenException;

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 \Exception
     */
    public function report(Throwable $exception)
    {
        if ($this->shouldReport($exception)) {
            $this->sendEmail($exception); // sends an email
        }
        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)
    {
        if ($exception instanceof \Illuminate\Session\TokenMismatchException) {  //https://gist.github.com/jrmadsen67/bd0f9ad0ef1ed6bb594e
            return redirect()
                ->back()
                ->withInput($request->except('password'))
                ->with('errorMessage', 'This form has expired due to inactivity. Please try again.');
        }

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

    /**
     * Sends an email to the developer about the exception.
     *
     * @return void
     */
    public function sendEmail(Throwable $exception)
    {
        try {
            $e = FlattenException::create($exception);
            $handler = new HtmlErrorRenderer(true); // boolean, true raises debug flag...
            $css = $handler->getStylesheet();
            $content = $handler->getBody($e);

            \Mail::send('emails.exception', compact('css','content'), function ($message) {
                $message
                    ->to('[email protected]')
                    ->subject('Exception: ' . \Request::fullUrl())
                ;
            });
        } catch (Throwable $ex) {
            Log::error($ex);
        }
    }
}

The $css and $content are passed into the view at resources/views/emails/exception.blade.php. The code I have in that file is as follows:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <style>{!! $css ?? '' !!}</style>
    </head>
    <body>
        {!! $content ?? '' !!}
    </body>
</html>
like image 183
climbd Avatar answered Oct 20 '22 05:10

climbd


After testing the answer , i get some error "Parssing to Exception class", so if you are using Laravel 7, you need to use "createFromThrowable" instade of "create" to get compatible with the Throwable Object.

like image 26
Androi_Begin Avatar answered Oct 20 '22 03:10

Androi_Begin