Passed
Push — feature/optimize ( cf938e...7e8046 )
by Fu
03:43
created

Handler::parsePayloadException()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 2
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Modules\Core\Supports;
4
5
use Exception;
6
use Illuminate\Database\Eloquent\ModelNotFoundException;
7
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
8
use Modules\Core\Enums\StatusCodeEnum;
9
use Modules\Core\ErrorCodes\JWTErrorCode;
10
use Symfony\Component\HttpKernel\Exception\{
11
    HttpException, UnauthorizedHttpException
12
};
13
use Tymon\JWTAuth\Exceptions\{
14
    InvalidClaimException,
15
    JWTException,
16
    PayloadException,
17
    TokenBlacklistedException,
18
    TokenExpiredException,
19
    TokenInvalidException,
20
    UserNotDefinedException
21
};
22
23
class Handler extends ExceptionHandler
24
{
25
    const STATUS_CODE = 'status_code';
26
    const ERROR_CODE = 'error_code';
27
    const MESSAGE = 'message';
28
    const DEBUG = 'debug';
29
30
    /**
31
     * Render an exception into an HTTP response.
32
     *
33
     * @param \Illuminate\Http\Request $request
34
     * @param \Exception|HttpException $exception
35
     *
36
     * @return \Illuminate\Http\Response|\Symfony\Component\HttpFoundation\Response
37
     */
38
    public function render($request, Exception $exception)
39
    {
40
        if ($request->is('api/*') || $request->wantsJson()) {
41
            if ('web' !== config('core.api.error_format')) {
42
                $response = [];
43
                $exception = $this->parseUnauthorizedHttpException($exception);
44
45
                if ($exception instanceof ModelNotFoundException) {
46
                    $response = $this->parseModelNotFoundException($response, $exception);
47
                } elseif ($exception instanceof JWTException) {
48
                    $response = $this->parseJWTException($response, $exception);
49
                } else {
50
                    $response = $this->parseException($response, $exception, get_class($exception));
51
                }
52
53
                $response = $this->parseDebug($response, $exception);
54
55
                return $this->response(collect($response)->toArray());
56
            }
57
        }
58
59
        return parent::render($request, $exception);
60
    }
61
62
    protected function response(array $response)
63
    {
64
        return (new Response($response))->render();
65
    }
66
67
    protected function parseDebug(array $response, Exception $exception)
68
    {
69
        if (true === config('app.debug')) {
70
            $response['meta'][self::DEBUG]['file'] = $exception->getFile();
71
            $response['meta'][self::DEBUG]['line'] = $exception->getLine();
72
            $response['meta'][self::DEBUG]['trace'] = $exception->getTrace();
73
        }
74
75
        return $response;
76
    }
77
78
    protected function parseUnauthorizedHttpException(Exception $exception)
79
    {
80
        if ($exception instanceof UnauthorizedHttpException && method_exists($exception, 'getPrevious')) {
81
            $exception = $exception->getPrevious();
82
        }
83
84
        return $exception;
85
    }
86
87
    protected function parseModelNotFoundException(array $response, Exception $exception): array
88
    {
89
        $response['meta'][self::STATUS_CODE] = StatusCodeEnum::HTTP_NOT_FOUND;
90
        $response['meta'][self::MESSAGE] = $exception->getMessage();
91
92
        return $response;
93
    }
94
95
    protected function parseInvalidClaimException(array $response, Exception $exception)
96
    {
97
        if ($exception instanceof InvalidClaimException) {
98
            $response['meta'][self::ERROR_CODE] = JWTErrorCode::INVALID_CLAIM;
99
        }
100
101
        return $response;
102
    }
103
104
    protected function parsePayloadException(array $response, Exception $exception)
105
    {
106
        if ($exception instanceof PayloadException) {
107
            $response['meta'][self::ERROR_CODE] = JWTErrorCode::PAYLOAD;
108
        }
109
110
        return $response;
111
    }
112
113
    protected function parseTokenBlacklistedException(array $response, Exception $exception)
114
    {
115
        if ($exception instanceof TokenBlacklistedException) {
116
            $response['meta'][self::ERROR_CODE] = JWTErrorCode::TOKEN_BLACKLISTED;
117
        }
118
119
        return $response;
120
    }
121
122
    protected function parseTokenExpiredException(array $response, Exception $exception)
123
    {
124
        if ($exception instanceof TokenExpiredException) {
125
            if ('Token has expired and can no longer be refreshed' === $exception->getMessage()) {
126
                $response['meta'][self::ERROR_CODE] = JWTErrorCode::CAN_NOT_REFRESHED;
127
            } else {
128
                $response['meta'][self::ERROR_CODE] = JWTErrorCode::TOKEN_EXPIRED;
129
            }
130
        }
131
132
        return $response;
133
    }
134
135
    protected function parseTokenInvalidException(array $response, Exception $exception)
136
    {
137
        if ($exception instanceof TokenInvalidException) {
138
            $response['meta'][self::ERROR_CODE] = JWTErrorCode::TOKEN_INVALID;
139
        }
140
141
        return $response;
142
    }
143
144
    protected function parseUserNotDefinedException(array $response, Exception $exception)
145
    {
146
        if ($exception instanceof UserNotDefinedException) {
147
            $response['meta'][self::ERROR_CODE] = JWTErrorCode::USER_NOT_DEFINED;
148
        }
149
150
        return $response;
151
    }
152
153
    protected function parseJWTException(array $response, Exception $exception): array
154
    {
155
        $response['meta'][self::ERROR_CODE] = JWTErrorCode::DEFAULT;
156
        $response['meta'][self::STATUS_CODE] = StatusCodeEnum::HTTP_UNAUTHORIZED;
157
        $response['meta'][self::MESSAGE] = $exception->getMessage();
158
159
        $response = $this->parseInvalidClaimException($response, $exception);
160
        $response = $this->parsePayloadException($response, $exception);
161
        $response = $this->parseTokenBlacklistedException($response, $exception);
162
        $response = $this->parseTokenExpiredException($response, $exception);
163
        $response = $this->parseTokenInvalidException($response, $exception);
164
        $response = $this->parseUserNotDefinedException($response, $exception);
165
166
        return $response;
167
    }
168
169
    protected function parseException(array $response, Exception $exception, string $exceptionClass): array
170
    {
171
        if (method_exists($exception, 'getStatusCode')) {
172
            $response['meta'][self::STATUS_CODE] = $exception->getStatusCode();
173
        } else {
174
            $response['meta'][self::STATUS_CODE] = StatusCodeEnum::HTTP_INTERNAL_SERVER_ERROR;
175
        }
176
177
        if (method_exists($exception, 'getCode')) {
178
            $response['meta'][self::ERROR_CODE] = $exception->getCode();
179
        }
180
181
        if (null === $exception->getMessage()) {
182
            $response['meta'][self::MESSAGE] = class_basename($exceptionClass);
183
        } else {
184
            $response['meta'][self::MESSAGE] = $exception->getMessage();
185
        }
186
187
        return $response;
188
    }
189
}
190