From a38ce38a9eb15fed69b4e9b9600a28123f8ccf93 Mon Sep 17 00:00:00 2001
From: Jordan Pittman <jordan@cryptica.me>
Date: Sat, 3 Jun 2017 22:11:28 -0400
Subject: [PATCH 1/5] Refactor whoops setup

---
 .../Foundation/Exceptions/Handler.php         | 22 +++++++++++--------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php
index f82d43e687fb..3ea17f3121df 100644
--- a/src/Illuminate/Foundation/Exceptions/Handler.php
+++ b/src/Illuminate/Foundation/Exceptions/Handler.php
@@ -268,9 +268,11 @@ protected function convertExceptionToResponse(Exception $e)
      */
     protected function renderExceptionWithWhoops(Exception $e)
     {
-        return tap(
-            (new Whoops)->pushHandler($this->whoopsHandler())
-        )->handleException($e);
+        $whoops = tap(new Whoops, function ($whoops) {
+            $whoops->pushHandler($this->whoopsHandler());
+        });
+
+        return $whoops->handleException($e);
     }
 
     /**
@@ -280,13 +282,15 @@ protected function renderExceptionWithWhoops(Exception $e)
      */
     protected function whoopsHandler()
     {
-        $files = new Filesystem;
+        return tap(new PrettyPageHandler, function ($handler) {
+            $files = new Filesystem;
 
-        return tap(new PrettyPageHandler)->setApplicationPaths(
-            array_flip(array_except(
-                array_flip($files->directories(base_path())), [base_path('vendor')]
-            ))
-        );
+            $handler->setApplicationPaths(
+                array_flip(array_except(
+                    array_flip($files->directories(base_path())), [base_path('vendor')]
+                ))
+            );
+        });
     }
 
     /**

From 4feb715752d9d2e99c46a4e338145c36d9eac08f Mon Sep 17 00:00:00 2001
From: Jordan Pittman <jordan@cryptica.me>
Date: Sat, 3 Jun 2017 22:23:53 -0400
Subject: [PATCH 2/5] Return response from Whoops

Whoops will, by default, write directly to stdout and call exit. This prevents integration testing of whoops handled exceptions because phpunit will just stop.

The PrettyPageHandler is additionally setup to not return data in the CLI. Fix this by turning on unconditional handling.
---
 src/Illuminate/Foundation/Exceptions/Handler.php | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php
index 3ea17f3121df..21b435faf41d 100644
--- a/src/Illuminate/Foundation/Exceptions/Handler.php
+++ b/src/Illuminate/Foundation/Exceptions/Handler.php
@@ -270,6 +270,8 @@ protected function renderExceptionWithWhoops(Exception $e)
     {
         $whoops = tap(new Whoops, function ($whoops) {
             $whoops->pushHandler($this->whoopsHandler());
+            $whoops->writeToOutput(false);
+            $whoops->allowQuit(false);
         });
 
         return $whoops->handleException($e);
@@ -285,6 +287,7 @@ protected function whoopsHandler()
         return tap(new PrettyPageHandler, function ($handler) {
             $files = new Filesystem;
 
+            $handler->handleUnconditionally(true);
             $handler->setApplicationPaths(
                 array_flip(array_except(
                     array_flip($files->directories(base_path())), [base_path('vendor')]

From 9c2e34b1dc9848112a741fbd603cfde3f92a6435 Mon Sep 17 00:00:00 2001
From: Jordan Pittman <jordan@cryptica.me>
Date: Sat, 3 Jun 2017 22:27:02 -0400
Subject: [PATCH 3/5] Fix whitepage error when rendering non-http exceptions

---
 src/Illuminate/Foundation/Exceptions/Handler.php | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php
index 21b435faf41d..ad0e68c8c8a8 100644
--- a/src/Illuminate/Foundation/Exceptions/Handler.php
+++ b/src/Illuminate/Foundation/Exceptions/Handler.php
@@ -245,17 +245,20 @@ protected function prepareResponse($request, Exception $e)
      */
     protected function convertExceptionToResponse(Exception $e)
     {
+        $headers = $this->isHttpException($e) ? $e->getHeaders() : [];
+        $statusCode = $this->isHttpException($e) ? $e->getStatusCode() : 500;
+
         if (config('app.debug')) {
             return SymfonyResponse::create(
-                $this->renderExceptionWithWhoops($e), $e->getStatusCode(), $e->getHeaders()
+                $this->renderExceptionWithWhoops($e), $statusCode, $headers
             );
         } else {
             $e = FlattenException::create($e);
 
             return SymfonyResponse::create(
                 (new SymfonyExceptionHandler(false))->getHtml($e),
-                $e->getStatusCode(),
-                $e->getHeaders()
+                $statusCode,
+                $headers
             );
         }
     }

From 1b9d74dd03061163ddfc18c03130748cf012f415 Mon Sep 17 00:00:00 2001
From: Jordan Pittman <jordan@cryptica.me>
Date: Sat, 3 Jun 2017 22:33:36 -0400
Subject: [PATCH 4/5] Refactor symfony exception rendering

---
 .../Foundation/Exceptions/Handler.php         | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php
index ad0e68c8c8a8..e6945737a193 100644
--- a/src/Illuminate/Foundation/Exceptions/Handler.php
+++ b/src/Illuminate/Foundation/Exceptions/Handler.php
@@ -253,12 +253,8 @@ protected function convertExceptionToResponse(Exception $e)
                 $this->renderExceptionWithWhoops($e), $statusCode, $headers
             );
         } else {
-            $e = FlattenException::create($e);
-
             return SymfonyResponse::create(
-                (new SymfonyExceptionHandler(false))->getHtml($e),
-                $statusCode,
-                $headers
+                $this->renderExceptionWithSymfony($e), $statusCode, $headers
             );
         }
     }
@@ -280,6 +276,19 @@ protected function renderExceptionWithWhoops(Exception $e)
         return $whoops->handleException($e);
     }
 
+    /**
+     * Render an exception to a string using Symfony.
+     *
+     * @param  \Exception  $e
+     * @return string
+     */
+    protected function renderExceptionWithSymfony(Exception $e)
+    {
+        $e = FlattenException::create($e);
+
+        return (new SymfonyExceptionHandler(false))->getHtml($e);
+    }
+
     /**
      * Get the Whoops handler for the application.
      *

From f2cd3c3396590944db2d789bf496f875a2bff0aa Mon Sep 17 00:00:00 2001
From: Jordan Pittman <jordan@cryptica.me>
Date: Sat, 3 Jun 2017 22:38:16 -0400
Subject: [PATCH 5/5] Use Symfony as a last resort exception handler

This prevents white screens if something goes wrong with Whoops setup.
---
 .../Foundation/Exceptions/Handler.php         | 24 +++++++++++--------
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php
index e6945737a193..ed05afd54e84 100644
--- a/src/Illuminate/Foundation/Exceptions/Handler.php
+++ b/src/Illuminate/Foundation/Exceptions/Handler.php
@@ -248,15 +248,19 @@ protected function convertExceptionToResponse(Exception $e)
         $headers = $this->isHttpException($e) ? $e->getHeaders() : [];
         $statusCode = $this->isHttpException($e) ? $e->getStatusCode() : 500;
 
-        if (config('app.debug')) {
-            return SymfonyResponse::create(
-                $this->renderExceptionWithWhoops($e), $statusCode, $headers
-            );
-        } else {
-            return SymfonyResponse::create(
-                $this->renderExceptionWithSymfony($e), $statusCode, $headers
-            );
+        $showStackTraces = config('app.debug');
+
+        try {
+            $content = $showStackTraces
+                ? $this->renderExceptionWithWhoops($e)
+                : $this->renderExceptionWithSymfony($e, $showStackTraces);
+        } finally {
+            $content = $content ?? $this->renderExceptionWithSymfony($e, $showStackTraces);
         }
+
+        return SymfonyResponse::create(
+            $content, $statusCode, $headers
+        );
     }
 
     /**
@@ -282,11 +286,11 @@ protected function renderExceptionWithWhoops(Exception $e)
      * @param  \Exception  $e
      * @return string
      */
-    protected function renderExceptionWithSymfony(Exception $e)
+    protected function renderExceptionWithSymfony(Exception $e, $showStackTraces)
     {
         $e = FlattenException::create($e);
 
-        return (new SymfonyExceptionHandler(false))->getHtml($e);
+        return (new SymfonyExceptionHandler($showStackTraces))->getHtml($e);
     }
 
     /**