Handler::render()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
cc 4
eloc 7
nc 3
nop 2
dl 0
loc 14
ccs 0
cts 7
cp 0
crap 20
rs 9.2
c 0
b 0
f 0
1
<?php
2
3
namespace App\Exceptions;
4
5
use App\Jobs\SendBearyChat;
6
use App\Support\Http\ApiResponse;
7
use Exception;
8
use Illuminate\Auth\AuthenticationException;
9
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
10
use Illuminate\Foundation\Http\Exceptions\MaintenanceModeException;
11
use Illuminate\Validation\ValidationException;
12
use Symfony\Component\HttpKernel\Exception\HttpException;
13
14
class Handler extends ExceptionHandler
15
{
16
    /**
17
     * A list of the exception types that should not be reported.
18
     *
19
     * @var array
20
     */
21
    protected $dontReport = [
22
        \Illuminate\Auth\AuthenticationException::class,
23
        \Illuminate\Auth\Access\AuthorizationException::class,
24
        \Symfony\Component\HttpKernel\Exception\HttpException::class,
25
        \Illuminate\Database\Eloquent\ModelNotFoundException::class,
26
        \Illuminate\Session\TokenMismatchException::class,
27
        \Illuminate\Validation\ValidationException::class,
28
        ActionFailureException::class,
29
        InvalidInputException::class,
30
    ];
31
32
    /**
33
     * Report or log an exception.
34
     *
35
     * This is a great spot to send exceptions to Sentry, Bugsnag, etc.
36
     *
37
     * @param  \Exception  $exception
38
     * @return void
39
     */
40
    public function report(Exception $exception)
41
    {
42
        if ($this->shouldntReport($exception)) {
43
            return;
44
        }
45
46
        $requestInfo = $this->getRequestInfo($this->container['request']);
47
48
        $this->container['log']->error($exception, $requestInfo);
49
50
        $this->notifyException($exception, $requestInfo);
51
    }
52
53
    /**
54
     * Get the request info.
55
     *
56
     * @param  \Illuminate\Http\Request  $request
57
     * @return array
58
     */
59
    protected function getRequestInfo($request)
60
    {
61
        $info = [
62
            'IP' => $request->ips(),
63
            'UserAgent' => $request->server('HTTP_USER_AGENT'),
64
            'URL' => $request->fullUrl(),
65
        ];
66
67
        if (app()->runningInConsole()) {
68
            $info['Command'] = implode(' ', $request->server('argv', []));
69
        }
70
71
        return $info;
72
    }
73
74
    /**
75
     * Notify the exception.
76
     *
77
     * @param  \Exception  $exception
78
     * @param  array  $requestInfo
79
     */
80
    protected function notifyException(Exception $exception, $requestInfo = null)
81
    {
82
        if (app()->environment('production') && config('bearychat.clients.server')) {
83
            dispatch(
84
                (new SendBearyChat)
85
                ->client('server')
86
                ->text('New Exception!')
87
                ->notification('New Exception: '.get_class($exception))
88
                ->markdown(false)
89
                ->add(str_limit($exception, 1300), get_class($exception), null, '#a0a0a0')
90
                ->add(str_limit(string_value($requestInfo), 1300), 'Request Info', null, '#e67f0a')
91
            );
92
        }
93
    }
94
95
    /**
96
     * Render an exception into an HTTP response.
97
     *
98
     * @param  \Illuminate\Http\Request  $request
99
     * @param  \Exception  $exception
100
     * @return \Illuminate\Http\Response
101
     */
102
    public function render($request, Exception $exception)
103
    {
104
        if ($exception instanceof MaintenanceModeException) {
105
            return $this->createApiResponse('服务器维护中,请稍后重试。', 503);
106
        }
107
108
        if ($exception instanceof ActionFailureException ||
109
            $exception instanceof InvalidInputException
110
        ) {
111
            return $this->renderActionFailure($request, $exception);
112
        }
113
114
        return parent::render($request, $exception);
115
    }
116
117
    /**
118
     * Convert an authentication exception into an unauthenticated response.
119
     *
120
     * @param  \Illuminate\Http\Request  $request
121
     * @param  \Illuminate\Auth\AuthenticationException  $exception
122
     * @return \Illuminate\Http\Response
123
     */
124
    protected function unauthenticated($request, AuthenticationException $exception)
125
    {
126
        if ($request->expectsJson()) {
127
            return $this->createApiResponse('认证失败,请先登录。', 401);
128
        }
129
130
        return redirect()->guest('login');
131
    }
132
133
    /**
134
     * Create an API response.
135
     *
136
     * @param  mixed  $message
137
     * @param  int  $code
138
     * @return \App\Support\Http\ApiResponse
139
     */
140
    protected function createApiResponse($message = null, $code = null)
141
    {
142
        $response = new ApiResponse($message, $code);
143
144
        if (($successCode = $response::successCode()) === $response->getCode()) {
145
            $response->setCode(-1 * $successCode);
146
        }
147
148
        if (empty($response->getMessage())) {
149
            $response->setMessage('发生错误,操作失败!');
150
        }
151
152
        return $response;
153
    }
154
155
    /**
156
     * Create an API response for the given exception.
157
     *
158
     * @param  \Exception  $e
159
     * @return \App\Support\Http\ApiResponse
160
     */
161
    protected function convertExceptionToApiResponse(Exception $e)
162
    {
163
        return $this->createApiResponse($e->getMessage(), $e->getCode());
164
    }
165
166
    /**
167
     * Render the given exception of action failure.
168
     *
169
     * @param  \Illuminate\Http\Request  $request
170
     * @param  \Exception  $exception
171
     * @return \Symfony\Component\HttpFoundation\Response
172
     */
173
    protected function renderActionFailure($request, Exception $exception)
174
    {
175
        if ($request->expectsJson()) {
176
            return $this->convertExceptionToApiResponse($exception);
177
        }
178
179
        return redirect()->back()->withInput($request->input())->with('alert.error', $exception->getMessage());
180
    }
181
182
    /**
183
     * Render the given HttpException.
184
     *
185
     * @param  \Symfony\Component\HttpKernel\Exception\HttpException  $e
186
     * @return \Symfony\Component\HttpFoundation\Response
187
     */
188
    protected function renderHttpException(HttpException $e)
189
    {
190
        if ($this->container['request']->expectsJson()) {
191
            $status = $e->getStatusCode();
192
193
            if (401 === $status) {
194
                $message = '认证失败,请先登录';
195
            } elseif (403 === $status) {
196
                $message = '无权操作,拒绝访问';
197
            } elseif (404 === $status) {
198
                $message = '404 Not Found';
199
            } else {
200
                $message = "非法操作 [{$status}]";
201
            }
202
203
            return $this->createApiResponse($message, $status);
204
        }
205
206
        return parent::renderHttpException($e);
207
    }
208
209
    /**
210
     * Create a response object from the given validation exception.
211
     *
212
     * @param  \Illuminate\Validation\ValidationException  $e
213
     * @param  \Illuminate\Http\Request  $request
214
     * @return \Symfony\Component\HttpFoundation\Response
215
     */
216
    protected function convertValidationExceptionToResponse(ValidationException $e, $request)
217
    {
218
        if ($request->expectsJson()) {
219
            return $this->createApiResponse(implode("\n", array_flatten($e->validator->errors()->getMessages())), 422);
220
        }
221
222
        return parent::convertValidationExceptionToResponse($e, $request);
223
    }
224
225
    /**
226
     * Create a Symfony response for the given exception.
227
     *
228
     * @param  \Exception  $e
229
     * @return \Symfony\Component\HttpFoundation\Response
230
     */
231
    protected function convertExceptionToResponse(Exception $e)
232
    {
233
        if (! $this->container['config']['app.debug'] && $this->container['request']->expectsJson()) {
234
            return $this->createApiResponse(['__error' => $e->getMessage()], $e->getCode());
235
        }
236
237
        return parent::convertExceptionToResponse($e);
238
    }
239
}
240