Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
91.18% covered (success)
91.18%
31 / 34
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
Handler
91.18% covered (success)
91.18%
31 / 34
66.67% covered (warning)
66.67%
2 / 3
14.13
0.00% covered (danger)
0.00%
0 / 1
 register
n/a
0 / 0
n/a
0 / 0
1
 render
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
3
 handleApiV2Exception
89.29% covered (warning)
89.29%
25 / 28
0.00% covered (danger)
0.00%
0 / 1
9.10
 getReponse
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace App\Exceptions;
4
5use App\Enums\ApiError;
6use App\Enums\ApiStatus;
7use App\Exceptions\Api\V2\ApiErrorException;
8use App\Http\Resources\Api\V2\ApiResponse as V2ApiResponse;
9use App\Lib\Helper;
10use Illuminate\Auth\Access\AuthorizationException;
11use Illuminate\Auth\AuthenticationException;
12use Illuminate\Database\Eloquent\ModelNotFoundException;
13use Illuminate\Http\Exceptions\ThrottleRequestsException;
14use Illuminate\Http\JsonResponse;
15use Illuminate\Http\Request;
16use Illuminate\Validation\ValidationException;
17use Kwaadpepper\ExceptionHandler\Exceptions\ExceptionHandler;
18use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
19
20class Handler extends ExceptionHandler
21{
22    /**
23     * A list of the exception types that are not reported.
24     *
25     * @var array
26     */
27    protected $dontReport = [
28        ApiErrorException::class,
29        RedirectTo::class
30    ];
31
32    /**
33     * A list of the inputs that are never flashed for validation exceptions.
34     *
35     * @var array
36     */
37    protected $dontFlash = [
38        'password',
39        'password_confirmation',
40    ];
41
42    /**
43     * Register the exception handling callbacks for the application.
44     *
45     * @return void
46     */
47    public function register()
48    {
49    }
50
51    /**
52     * Render an exception into an HTTP response.
53     *
54     * @param  mixed      $request
55     * @param  \Throwable $e
56     * @return \Symfony\Component\HttpFoundation\Response
57     */
58    public function render($request, \Throwable $e)
59    {
60        if (Helper::isRequestForApiV2($request) and $request->isJson()) {
61            return $this->handleApiV2Exception($request, $e);
62        } //end if
63        // @codeCoverageIgnoreStart
64        return parent::render($request, $e);
65        // @codeCoverageIgnoreEnd
66    }
67
68    /**
69     * Generate a json response for any apiV2 error case
70     *
71     * @param Request    $request
72     * @param \Throwable $e
73     * @return JsonResponse
74     */
75    private function handleApiV2Exception(Request $request, \Throwable $e): JsonResponse
76    {
77        switch (get_class($e)) {
78            case AuthenticationException::class:
79                /** @var AuthenticationException $e */
80                return $this->getReponse(
81                    $request,
82                    401,
83                    ApiError::apiAuthFailed()->value,
84                    sprintf('%s, %s', ApiError::apiAuthFailed()->label, $e->getMessage())
85                );
86            case MethodNotAllowedHttpException::class:
87                /** @var MethodNotAllowedHttpException $e */
88                return $this->getReponse(
89                    $request,
90                    $e->getStatusCode(),
91                    ApiError::methodNotAllowed()->value,
92                    sprintf('%s, %s', ApiError::methodNotAllowed()->label, $e->getMessage())
93                );
94            case ValidationException::class:
95                /** @var ValidationException $e */
96                return $this->getReponse(
97                    $request,
98                    $e->status,
99                    ApiError::validationFailed()->value,
100                    sprintf(ApiError::validationFailed()->label, $e->getMessage()),
101                    ['errors' => $e->errors()]
102                );
103            case ModelNotFoundException::class:
104                /** @var ModelNotFoundException $e */
105                return $this->getReponse(
106                    $request,
107                    404,
108                    ApiError::modelNotFound()->value,
109                    sprintf(
110                        ApiError::modelNotFound()->label,
111                        \array_slice(explode('\\', $e->getModel()), -1)[0]
112                    )
113                );
114            case ApiErrorException::class:
115                /** @var ApiErrorException $e */
116                return $this->getReponse(
117                    $request,
118                    $e->getStatusCode(),
119                    $e->getCode(),
120                    $e->getMessage()
121                );
122            case ThrottleRequestsException::class:
123                /** @var ThrottleRequestsException $e */
124                return $this->getReponse(
125                    $request,
126                    429,
127                    ApiError::throttleRequestsException()->value,
128                    ApiError::throttleRequestsException()->label
129                );
130            case AuthorizationException::class:
131                /** @var AuthorizationException $e */
132                return $this->getReponse(
133                    $request,
134                    403,
135                    ApiError::authorizationException()->value,
136                    ApiError::authorizationException()->label
137                );
138        } //end switch
139        // @codeCoverageIgnoreStart
140        if (config('app.env') === 'testing') {
141            // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Found
142            print_r((string)$e);
143        }
144        return $this->getReponse($request, 500, \intval($e->getCode()), $e->getMessage());
145        // @codeCoverageIgnoreEnd
146    }
147
148    /**
149     * Generate an ApiV2 json response
150     *
151     * @param Request $request
152     * @param integer $httpCode
153     * @param integer $apiCode
154     * @param string  $message
155     * @param array   $data
156     * @return JsonResponse
157     */
158    private static function getReponse(
159        Request $request,
160        int $httpCode,
161        int $apiCode,
162        string $message,
163        array $data = []
164    ): JsonResponse {
165        return (new V2ApiResponse(
166            (object)array_merge($data, ['message' => $message, 'code' => $apiCode]),
167            ApiStatus::KO()
168        ))->toResponse($request)->setStatusCode($httpCode);
169    }
170}