Issues (92)

src/Exceptions/Handler.php (5 issues)

1
<?php
2
3
namespace Nip\Http\Exceptions;
4
5
use Exception;
6
use Nip\Container\Container;
7
use Nip\Http\Response\ResponseFactory;
8
use Nip\Http\ServerMiddleware\Dispatcher;
9
use Psr\Http\Message\ResponseInterface;
10
use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer;
11
use Symfony\Component\HttpFoundation\JsonResponse;
12
use Symfony\Component\HttpFoundation\Request;
13
use Symfony\Component\HttpFoundation\Response;
14
use Symfony\Component\HttpKernel\Exception\HttpException;
15
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
16
use Throwable;
17
use Whoops\Handler\PrettyPageHandler;
18
use Whoops\Run as Whoops;
19
20
/**
21
 * Class Handler
22
 * @package Nip\Http\Exceptions
23
 */
24
class Handler
25
{
26
    /**
27
     * The container implementation.
28
     *
29
     * @var Container
30
     */
31
    protected $container;
32
33
    /**
34
     * Create a new exception handler instance.
35
     *
36
     * @param Container $container
37
     * @return void
38
     */
39 7
    public function __construct(Container $container)
40
    {
41 7
        $this->container = $container;
42 7
    }
43
44
    /**
45
     * @param $request
46
     * @param Exception $exception
47
     * @return ResponseInterface|JsonResponse|Response
48
     */
49
    public function render($request, Throwable $exception)
50
    {
51
        $exception = $this->prepareException($exception);
52
53
        return $request->expectsJson()
54
            ? $this->prepareJsonResponse($request, $exception)
55
            : $this->prepareResponse($request, $exception);
56
    }
57
58
    /**
59
     * Prepare exception for rendering.
60
     * @param Throwable $e
61
     * @return Throwable
62
     */
63
    protected function prepareException(Throwable $e)
64
    {
65
//        if ($e instanceof ModelNotFoundException) {
66
//            $e = new NotFoundHttpException($e->getMessage(), $e);
67
//        } elseif ($e instanceof AuthorizationException) {
68
//            $e = new AccessDeniedHttpException($e->getMessage(), $e);
69
//        } elseif ($e instanceof TokenMismatchException) {
70
//            $e = new HttpException(419, $e->getMessage(), $e);
71
//        } elseif ($e instanceof SuspiciousOperationException) {
72
//            $e = new NotFoundHttpException('Bad hostname provided.', $e);
73
//        }
74
75
        return $e;
76
    }
77
78
    /**
79
     * Prepare a JSON response for the given exception.
80
     *
81
     * @param Request $request
82
     * @param Throwable $e
83
     * @return JsonResponse
84
     */
85
    protected function prepareJsonResponse($request, Throwable $e)
0 ignored issues
show
The parameter $request is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

85
    protected function prepareJsonResponse(/** @scrutinizer ignore-unused */ $request, Throwable $e)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
86
    {
87
        return new JsonResponse(
88
            $this->convertExceptionToArray($e),
89
            $this->isHttpException($e) ? $e->getStatusCode() : 500,
0 ignored issues
show
The method getStatusCode() does not exist on Throwable. It seems like you code against a sub-type of Throwable such as Symfony\Component\HttpKe...\HttpExceptionInterface or Symfony\Component\HttpKe...Exception\HttpException. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

89
            $this->isHttpException($e) ? $e->/** @scrutinizer ignore-call */ getStatusCode() : 500,
Loading history...
90
            $this->isHttpException($e) ? $e->getHeaders() : [],
0 ignored issues
show
The method getHeaders() does not exist on Throwable. It seems like you code against a sub-type of Throwable such as Symfony\Component\HttpKe...\HttpExceptionInterface or Symfony\Component\HttpKe...Exception\HttpException. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

90
            $this->isHttpException($e) ? $e->/** @scrutinizer ignore-call */ getHeaders() : [],
Loading history...
91
            JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES
0 ignored issues
show
Nip\Http\Exceptions\JSON...\JSON_UNESCAPED_SLASHES of type integer is incompatible with the type boolean expected by parameter $json of Symfony\Component\HttpFo...Response::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

91
            /** @scrutinizer ignore-type */ JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES
Loading history...
92
        );
93
    }
94
95
    /**
96
     * Convert the given exception to an array.
97
     *
98
     * @param Throwable $e
99
     * @return array
100
     */
101
    protected function convertExceptionToArray(Throwable $e)
102
    {
103
        return $this->isDebug() ? [
104
            'message' => $e->getMessage(),
105
            'exception' => get_class($e),
106
            'file' => $e->getFile(),
107
            'line' => $e->getLine(),
108
//            'trace' => collect($e->getTrace())->map(function ($trace) {
109
//                return Arr::except($trace, ['args']);
110
//            })->all(),
111
        ] : [
112
            'message' => $this->isHttpException($e) ? $e->getMessage() : 'Server Error',
113
        ];
114
    }
115
116
    /**
117
     * Prepare a response for the given exception.
118
     *
119
     * @param Request $request
120
     * @param Throwable $exception
121
     * @return Response
122
     */
123
    protected function prepareResponse($request, Throwable $exception)
0 ignored issues
show
The parameter $request is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

123
    protected function prepareResponse(/** @scrutinizer ignore-unused */ $request, Throwable $exception)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
124
    {
125
        if (!$this->isHttpException($exception) && $this->isDebug()) {
126
            return $this->convertExceptionToResponse($exception);
127
        }
128
129
        if (!$this->isHttpException($exception)) {
130
            $exception = new HttpException(500, $exception->getMessage());
131
        }
132
133
        return $this->renderHttpException($exception);
134
    }
135
136
    /**
137
     * Create a Symfony response for the given exception.
138
     *
139
     * @param Throwable $e
140
     * @return Response
141
     */
142
    protected function convertExceptionToResponse(Throwable $e)
143
    {
144
        return ResponseFactory::make(
145
            $this->renderExceptionContent($e),
146
            $this->isHttpException($e) ? $e->getStatusCode() : 500,
147
            $this->isHttpException($e) ? $e->getHeaders() : []
148
        );
149
    }
150
151
    /**
152
     * Get the response content for the given exception.
153
     *
154
     * @param Throwable $exception
155
     * @return string
156
     */
157
    protected function renderExceptionContent(Throwable $exception)
158
    {
159
        try {
160
            return $this->isDebug() && class_exists(Whoops::class)
161
                ? $this->renderExceptionWithWhoops($exception)
162
                : $this->renderExceptionWithSymfony($exception, $this->isDebug());
163
        } catch (Exception $exception) {
164
            return $this->renderExceptionWithSymfony($exception, $this->isDebug());
165
        }
166
    }
167
168
    /**
169
     * @param Throwable $e
170
     * @return ResponseInterface
171
     */
172
    protected function renderExceptionWithWhoops(Throwable $e)
173
    {
174
        $whoops = new Whoops;
175
        $whoops->allowQuit(false);
176
        $whoops->writeToOutput(false);
177
        $whoops->pushHandler(new PrettyPageHandler());
178
179
        return ResponseFactory::make($whoops->handleException($e));
180
    }
181
182
    /**
183
     * Render an exception to a string using Symfony.
184
     *
185
     * @param Throwable $e
186
     * @param bool $debug
187
     * @return string
188
     */
189
    protected function renderExceptionWithSymfony(Throwable $e, $debug)
190
    {
191
        $renderer = new HtmlErrorRenderer($debug);
192
193
        return $renderer->render($e)->getAsString();
194
    }
195
196
    /**
197
     * Render the given HttpException.
198
     *
199
     * @param \Symfony\Component\HttpKernel\Exception\HttpExceptionInterface $e
200
     * @return Response
201
     */
202
    protected function renderHttpException(HttpExceptionInterface $e)
203
    {
204
//        $this->registerErrorViewPaths();
205
//
206
//        if (view()->exists($view = $this->getHttpExceptionView($e))) {
207
//            return response()->view($view, [
208
//                'errors' => new ViewErrorBag,
209
//                'exception' => $e,
210
//            ], $e->getStatusCode(), $e->getHeaders());
211
//        }
212
213
        return $this->convertExceptionToResponse($e);
214
    }
215
216
    /**
217
     * Determine if the given exception is an HTTP exception.
218
     *
219
     * @param Throwable $e
220
     * @return bool
221
     */
222
    protected function isHttpException(Throwable $e)
223
    {
224
        return $e instanceof HttpExceptionInterface;
225
    }
226
227
    /**
228
     * @return bool
229
     */
230 7
    public function isDebug()
231
    {
232 7
        $config = config('app.debug');
233 7
        return $config === true || $config === 'true' || $config === '1' || $config === 1;
234
    }
235
}
236