Passed
Push — dev ( 67e3d9...b20acc )
by Marcin
02:23
created
src/ExceptionHandlerHelper.php 2 patches
Indentation   +223 added lines, -223 removed lines patch added patch discarded remove patch
@@ -27,228 +27,228 @@
 block discarded – undo
27 27
  */
28 28
 class ExceptionHandlerHelper
29 29
 {
30
-    /**
31
-     * Render an exception into valid API response.
32
-     *
33
-     * @param \Illuminate\Http\Request $request Request object
34
-     * @param \Exception               $ex      Exception
35
-     *
36
-     * @return HttpResponse
37
-     */
38
-    public static function render(/** @scrutinizer ignore-unused */ $request, Exception $ex): HttpResponse
39
-    {
40
-        $result = null;
41
-        $cfg = static::getExceptionHandlerConfig()['map'];
42
-
43
-        if ($ex instanceof HttpException) {
44
-            // Check if we have any exception configuration for this particular HTTP status code.
45
-            // This confing entry is guaranted to exist (at least 'default'). Enforced by tests.
46
-            $http_code = $ex->getStatusCode();
47
-            $ex_cfg = $cfg[ HttpException::class ][ $http_code ] ?? null;
48
-            $ex_cfg = $ex_cfg ?? $cfg[ HttpException::class ]['default'];
49
-            $result = self::processException($ex, /** @scrutinizer ignore-type */ $ex_cfg, $http_code);
50
-        } elseif ($ex instanceof ValidationException) {
51
-            // This entry is guaranted to exist. Enforced by tests.
52
-            $http_code = HttpResponse::HTTP_UNPROCESSABLE_ENTITY;
53
-            $result = self::processException($ex, $cfg[ HttpException::class ][ $http_code ], $http_code);
54
-        }
55
-
56
-        if ($result === null) {
57
-            // This entry is guaranted to exist. Enforced by tests.
58
-            $result = self::processException($ex, $cfg['default'], HttpResponse::HTTP_INTERNAL_SERVER_ERROR);
59
-        }
60
-
61
-        return $result;
62
-    }
63
-
64
-    /**
65
-     * Handles given exception and produces valid HTTP response object.
66
-     *
67
-     * @param \Exception $ex                 Exception to be handled.
68
-     * @param array      $ex_cfg             ExceptionHandler's config excerpt related to $ex exception type.
69
-     * @param int        $fallback_http_code HTTP code to be assigned to produced $ex related response in
70
-     *                                       case configuration array lacks own `http_code` value.
71
-     *
72
-     * @return \Symfony\Component\HttpFoundation\Response
73
-     */
74
-    protected static function processException(\Exception $ex, array $ex_cfg, int $fallback_http_code)
75
-    {
76
-        $api_code = $ex_cfg['api_code'];
77
-        $http_code = $ex_cfg['http_code'] ?? $fallback_http_code;
78
-        $msg_key = $ex_cfg['msg_key'] ?? null;
79
-        $msg_enforce = $ex_cfg['msg_enforce'] ?? false;
80
-
81
-        // No message key, let's get exception message and if there's nothing useful, fallback to built-in one.
82
-        $msg = $ex->getMessage();
83
-        $placeholders = [
84
-            'api_code' => $api_code,
85
-            'message'  => ($msg !== '') ? $msg : '???',
86
-        ];
87
-
88
-        // shall we enforce error message?
89
-        if ($msg_enforce) {
90
-            // yes, please.
91
-            if ($msg_key === null) {
92
-                // there's no msg_key configured for this exact code, so let's obtain our default message
93
-                $msg = ($msg_key === null) ? static::getErrorMessageForException($ex, $http_code, $placeholders)
94
-                    : Lang::get($msg_key, $placeholders);
95
-            }
96
-        } else {
97
-            // nothing enforced, handling pipeline: ex_message -> user_defined_msg -> http_ex -> default
98
-            if ($msg === '') {
99
-                $msg = ($msg_key === null) ? static::getErrorMessageForException($ex, $http_code, $placeholders)
100
-                    : Lang::get($msg_key, $placeholders);
101
-            }
102
-        }
103
-
104
-        // Lets' try to build the error response with what we have now
105
-        return static::error($ex, $api_code, $http_code, $msg);
106
-    }
107
-
108
-    /**
109
-     * Returns error message for given exception. If exception message is empty, then falls back to
110
-     * `default` handler either for HttpException (if $ex is instance of it), or generic `default`
111
-     * config.
112
-     *
113
-     * @param \Exception $ex
114
-     * @param int        $http_code
115
-     * @param array      $placeholders
116
-     *
117
-     * @return string
118
-     */
119
-    protected static function getErrorMessageForException(\Exception $ex, int $http_code, array $placeholders): string
120
-    {
121
-        // exception message is uselss, lets go deeper
122
-        if ($ex instanceof HttpException) {
123
-            $error_message = Lang::get("response-builder::builder.http_{$http_code}", $placeholders);
124
-        } else {
125
-            // Still got nothing? Fall back to built-in generic message for this type of exception.
126
-            $key = BaseApiCodes::getCodeMessageKey(($ex instanceof HttpException)
127
-                ? /** @scrutinizer ignore-deprecated */ BaseApiCodes::EX_HTTP_EXCEPTION()
128
-                : /** @scrutinizer ignore-deprecated */ BaseApiCodes::NO_ERROR_MESSAGE());
129
-            $error_message = Lang::get($key, $placeholders);
130
-        }
131
-
132
-        return $error_message;
133
-    }
134
-
135
-    /**
136
-     * Convert an authentication exception into an unauthenticated response.
137
-     *
138
-     * @param \Illuminate\Http\Request                 $request
139
-     * @param \Illuminate\Auth\AuthenticationException $exception
140
-     *
141
-     * @return HttpResponse
142
-     */
143
-    protected function unauthenticated(/** @scrutinizer ignore-unused */ $request,
144
-                                                                         AuthException $exception): HttpResponse
145
-    {
146
-        // This entry is guaranted to exist. Enforced by tests.
147
-        $http_code = HttpResponse::HTTP_UNAUTHORIZED;
148
-        $cfg = static::getExceptionHandlerConfig()['map'][ HttpException::class ][ $http_code ];
149
-
150
-        return static::processException($exception, $cfg, $http_code);
151
-    }
152
-
153
-    /**
154
-     * Process single error and produce valid API response.
155
-     *
156
-     * @param Exception $ex Exception to be handled.
157
-     * @param integer   $api_code
158
-     * @param integer   $http_code
159
-     *
160
-     * @return HttpResponse
161
-     */
162
-    protected static function error(Exception $ex,
163
-                                    int $api_code, int $http_code = null, string $error_message): HttpResponse
164
-    {
165
-        $ex_http_code = ($ex instanceof HttpException) ? $ex->getStatusCode() : $ex->getCode();
166
-        $http_code = $http_code ?? $ex_http_code;
167
-
168
-        // Check if we now have valid HTTP error code for this case or need to make one up.
169
-        // We cannot throw any exception if codes are invalid because we are in Exception Handler already.
170
-        if ($http_code < ResponseBuilder::ERROR_HTTP_CODE_MIN) {
171
-            // Not a valid code, let's try to get the exception status.
172
-            $http_code = $ex_http_code;
173
-        }
174
-        // Can it be considered a valid HTTP error code?
175
-        if ($http_code < ResponseBuilder::ERROR_HTTP_CODE_MIN) {
176
-            // We now handle uncaught exception, so we cannot throw another one if there's
177
-            // something wrong with the configuration, so we try to recover and use built-in
178
-            // codes instead.
179
-            // FIXME: We should log this event as (warning or error?)
180
-            $http_code = ResponseBuilder::DEFAULT_HTTP_CODE_ERROR;
181
-        }
182
-
183
-        // If we have trace data debugging enabled, let's gather some debug info and add to the response.
184
-        $debug_data = null;
185
-        if (Config::get(ResponseBuilder::CONF_KEY_DEBUG_EX_TRACE_ENABLED, false)) {
186
-            $debug_data = [
187
-                Config::get(ResponseBuilder::CONF_KEY_DEBUG_EX_TRACE_KEY, ResponseBuilder::KEY_TRACE) => [
188
-                    ResponseBuilder::KEY_CLASS => get_class($ex),
189
-                    ResponseBuilder::KEY_FILE  => $ex->getFile(),
190
-                    ResponseBuilder::KEY_LINE  => $ex->getLine(),
191
-                ],
192
-            ];
193
-        }
194
-
195
-        // If this is ValidationException, add all the messages from MessageBag to the data node.
196
-        $data = null;
197
-        if ($ex instanceof ValidationException) {
198
-            /** @var ValidationException $ex */
199
-            $data = [ResponseBuilder::KEY_MESSAGES => $ex->validator->errors()->messages()];
200
-        }
201
-
202
-        return ResponseBuilder::asError($api_code)
203
-            ->withMessage($error_message)
204
-            ->withHttpCode($http_code)
205
-            ->withData($data)
206
-            ->withDebugData($debug_data)
207
-            ->build();
208
-    }
209
-
210
-    /**
211
-     * Returns default (built-in) exception handler config array.
212
-     *
213
-     * @return array
214
-     */
215
-    protected static function getExceptionHandlerDefaultConfig(): array
216
-    {
217
-        return [
218
-            'map' => [
219
-                HttpException::class => [
220
-                    // used by unauthenticated() to obtain api and http code for the exception
221
-                    HttpResponse::HTTP_UNAUTHORIZED         => [
222
-                        'api_code' => /** @scrutinizer ignore-deprecated */ BaseApiCodes::EX_AUTHENTICATION_EXCEPTION(),
223
-                    ],
224
-                    // Required by ValidationException handler
225
-                    HttpResponse::HTTP_UNPROCESSABLE_ENTITY => [
226
-                        'api_code' => /** @scrutinizer ignore-deprecated */ BaseApiCodes::EX_VALIDATION_EXCEPTION(),
227
-                    ],
228
-                    // default handler is mandatory. `default` entry MUST have both `api_code` and `http_code` set.
229
-                    'default'                               => [
230
-                        'api_code'  => /** @scrutinizer ignore-deprecated */ BaseApiCodes::EX_HTTP_EXCEPTION(),
231
-                        'http_code' => HttpResponse::HTTP_BAD_REQUEST,
232
-                    ],
233
-                ],
234
-                // default handler is mandatory. `default` entry MUST have both `api_code` and `http_code` set.
235
-                'default'            => [
236
-                    'api_code'  => /** @scrutinizer ignore-deprecated */ BaseApiCodes::EX_UNCAUGHT_EXCEPTION(),
237
-                    'http_code' => HttpResponse::HTTP_INTERNAL_SERVER_ERROR,
238
-                ],
239
-            ],
240
-        ];
241
-    }
242
-
243
-    /**
244
-     * Returns ExceptionHandlerHelper configration array with user configuration merged into built-in defaults.
245
-     *
246
-     * @return array
247
-     */
248
-    protected static function getExceptionHandlerConfig(): array
249
-    {
250
-        return Util::mergeConfig(static::getExceptionHandlerDefaultConfig(),
251
-            \Config::get(ResponseBuilder::CONF_KEY_EXCEPTION_HANDLER, []));
252
-    }
30
+	/**
31
+	 * Render an exception into valid API response.
32
+	 *
33
+	 * @param \Illuminate\Http\Request $request Request object
34
+	 * @param \Exception               $ex      Exception
35
+	 *
36
+	 * @return HttpResponse
37
+	 */
38
+	public static function render(/** @scrutinizer ignore-unused */ $request, Exception $ex): HttpResponse
39
+	{
40
+		$result = null;
41
+		$cfg = static::getExceptionHandlerConfig()['map'];
42
+
43
+		if ($ex instanceof HttpException) {
44
+			// Check if we have any exception configuration for this particular HTTP status code.
45
+			// This confing entry is guaranted to exist (at least 'default'). Enforced by tests.
46
+			$http_code = $ex->getStatusCode();
47
+			$ex_cfg = $cfg[ HttpException::class ][ $http_code ] ?? null;
48
+			$ex_cfg = $ex_cfg ?? $cfg[ HttpException::class ]['default'];
49
+			$result = self::processException($ex, /** @scrutinizer ignore-type */ $ex_cfg, $http_code);
50
+		} elseif ($ex instanceof ValidationException) {
51
+			// This entry is guaranted to exist. Enforced by tests.
52
+			$http_code = HttpResponse::HTTP_UNPROCESSABLE_ENTITY;
53
+			$result = self::processException($ex, $cfg[ HttpException::class ][ $http_code ], $http_code);
54
+		}
55
+
56
+		if ($result === null) {
57
+			// This entry is guaranted to exist. Enforced by tests.
58
+			$result = self::processException($ex, $cfg['default'], HttpResponse::HTTP_INTERNAL_SERVER_ERROR);
59
+		}
60
+
61
+		return $result;
62
+	}
63
+
64
+	/**
65
+	 * Handles given exception and produces valid HTTP response object.
66
+	 *
67
+	 * @param \Exception $ex                 Exception to be handled.
68
+	 * @param array      $ex_cfg             ExceptionHandler's config excerpt related to $ex exception type.
69
+	 * @param int        $fallback_http_code HTTP code to be assigned to produced $ex related response in
70
+	 *                                       case configuration array lacks own `http_code` value.
71
+	 *
72
+	 * @return \Symfony\Component\HttpFoundation\Response
73
+	 */
74
+	protected static function processException(\Exception $ex, array $ex_cfg, int $fallback_http_code)
75
+	{
76
+		$api_code = $ex_cfg['api_code'];
77
+		$http_code = $ex_cfg['http_code'] ?? $fallback_http_code;
78
+		$msg_key = $ex_cfg['msg_key'] ?? null;
79
+		$msg_enforce = $ex_cfg['msg_enforce'] ?? false;
80
+
81
+		// No message key, let's get exception message and if there's nothing useful, fallback to built-in one.
82
+		$msg = $ex->getMessage();
83
+		$placeholders = [
84
+			'api_code' => $api_code,
85
+			'message'  => ($msg !== '') ? $msg : '???',
86
+		];
87
+
88
+		// shall we enforce error message?
89
+		if ($msg_enforce) {
90
+			// yes, please.
91
+			if ($msg_key === null) {
92
+				// there's no msg_key configured for this exact code, so let's obtain our default message
93
+				$msg = ($msg_key === null) ? static::getErrorMessageForException($ex, $http_code, $placeholders)
94
+					: Lang::get($msg_key, $placeholders);
95
+			}
96
+		} else {
97
+			// nothing enforced, handling pipeline: ex_message -> user_defined_msg -> http_ex -> default
98
+			if ($msg === '') {
99
+				$msg = ($msg_key === null) ? static::getErrorMessageForException($ex, $http_code, $placeholders)
100
+					: Lang::get($msg_key, $placeholders);
101
+			}
102
+		}
103
+
104
+		// Lets' try to build the error response with what we have now
105
+		return static::error($ex, $api_code, $http_code, $msg);
106
+	}
107
+
108
+	/**
109
+	 * Returns error message for given exception. If exception message is empty, then falls back to
110
+	 * `default` handler either for HttpException (if $ex is instance of it), or generic `default`
111
+	 * config.
112
+	 *
113
+	 * @param \Exception $ex
114
+	 * @param int        $http_code
115
+	 * @param array      $placeholders
116
+	 *
117
+	 * @return string
118
+	 */
119
+	protected static function getErrorMessageForException(\Exception $ex, int $http_code, array $placeholders): string
120
+	{
121
+		// exception message is uselss, lets go deeper
122
+		if ($ex instanceof HttpException) {
123
+			$error_message = Lang::get("response-builder::builder.http_{$http_code}", $placeholders);
124
+		} else {
125
+			// Still got nothing? Fall back to built-in generic message for this type of exception.
126
+			$key = BaseApiCodes::getCodeMessageKey(($ex instanceof HttpException)
127
+				? /** @scrutinizer ignore-deprecated */ BaseApiCodes::EX_HTTP_EXCEPTION()
128
+				: /** @scrutinizer ignore-deprecated */ BaseApiCodes::NO_ERROR_MESSAGE());
129
+			$error_message = Lang::get($key, $placeholders);
130
+		}
131
+
132
+		return $error_message;
133
+	}
134
+
135
+	/**
136
+	 * Convert an authentication exception into an unauthenticated response.
137
+	 *
138
+	 * @param \Illuminate\Http\Request                 $request
139
+	 * @param \Illuminate\Auth\AuthenticationException $exception
140
+	 *
141
+	 * @return HttpResponse
142
+	 */
143
+	protected function unauthenticated(/** @scrutinizer ignore-unused */ $request,
144
+																		 AuthException $exception): HttpResponse
145
+	{
146
+		// This entry is guaranted to exist. Enforced by tests.
147
+		$http_code = HttpResponse::HTTP_UNAUTHORIZED;
148
+		$cfg = static::getExceptionHandlerConfig()['map'][ HttpException::class ][ $http_code ];
149
+
150
+		return static::processException($exception, $cfg, $http_code);
151
+	}
152
+
153
+	/**
154
+	 * Process single error and produce valid API response.
155
+	 *
156
+	 * @param Exception $ex Exception to be handled.
157
+	 * @param integer   $api_code
158
+	 * @param integer   $http_code
159
+	 *
160
+	 * @return HttpResponse
161
+	 */
162
+	protected static function error(Exception $ex,
163
+									int $api_code, int $http_code = null, string $error_message): HttpResponse
164
+	{
165
+		$ex_http_code = ($ex instanceof HttpException) ? $ex->getStatusCode() : $ex->getCode();
166
+		$http_code = $http_code ?? $ex_http_code;
167
+
168
+		// Check if we now have valid HTTP error code for this case or need to make one up.
169
+		// We cannot throw any exception if codes are invalid because we are in Exception Handler already.
170
+		if ($http_code < ResponseBuilder::ERROR_HTTP_CODE_MIN) {
171
+			// Not a valid code, let's try to get the exception status.
172
+			$http_code = $ex_http_code;
173
+		}
174
+		// Can it be considered a valid HTTP error code?
175
+		if ($http_code < ResponseBuilder::ERROR_HTTP_CODE_MIN) {
176
+			// We now handle uncaught exception, so we cannot throw another one if there's
177
+			// something wrong with the configuration, so we try to recover and use built-in
178
+			// codes instead.
179
+			// FIXME: We should log this event as (warning or error?)
180
+			$http_code = ResponseBuilder::DEFAULT_HTTP_CODE_ERROR;
181
+		}
182
+
183
+		// If we have trace data debugging enabled, let's gather some debug info and add to the response.
184
+		$debug_data = null;
185
+		if (Config::get(ResponseBuilder::CONF_KEY_DEBUG_EX_TRACE_ENABLED, false)) {
186
+			$debug_data = [
187
+				Config::get(ResponseBuilder::CONF_KEY_DEBUG_EX_TRACE_KEY, ResponseBuilder::KEY_TRACE) => [
188
+					ResponseBuilder::KEY_CLASS => get_class($ex),
189
+					ResponseBuilder::KEY_FILE  => $ex->getFile(),
190
+					ResponseBuilder::KEY_LINE  => $ex->getLine(),
191
+				],
192
+			];
193
+		}
194
+
195
+		// If this is ValidationException, add all the messages from MessageBag to the data node.
196
+		$data = null;
197
+		if ($ex instanceof ValidationException) {
198
+			/** @var ValidationException $ex */
199
+			$data = [ResponseBuilder::KEY_MESSAGES => $ex->validator->errors()->messages()];
200
+		}
201
+
202
+		return ResponseBuilder::asError($api_code)
203
+			->withMessage($error_message)
204
+			->withHttpCode($http_code)
205
+			->withData($data)
206
+			->withDebugData($debug_data)
207
+			->build();
208
+	}
209
+
210
+	/**
211
+	 * Returns default (built-in) exception handler config array.
212
+	 *
213
+	 * @return array
214
+	 */
215
+	protected static function getExceptionHandlerDefaultConfig(): array
216
+	{
217
+		return [
218
+			'map' => [
219
+				HttpException::class => [
220
+					// used by unauthenticated() to obtain api and http code for the exception
221
+					HttpResponse::HTTP_UNAUTHORIZED         => [
222
+						'api_code' => /** @scrutinizer ignore-deprecated */ BaseApiCodes::EX_AUTHENTICATION_EXCEPTION(),
223
+					],
224
+					// Required by ValidationException handler
225
+					HttpResponse::HTTP_UNPROCESSABLE_ENTITY => [
226
+						'api_code' => /** @scrutinizer ignore-deprecated */ BaseApiCodes::EX_VALIDATION_EXCEPTION(),
227
+					],
228
+					// default handler is mandatory. `default` entry MUST have both `api_code` and `http_code` set.
229
+					'default'                               => [
230
+						'api_code'  => /** @scrutinizer ignore-deprecated */ BaseApiCodes::EX_HTTP_EXCEPTION(),
231
+						'http_code' => HttpResponse::HTTP_BAD_REQUEST,
232
+					],
233
+				],
234
+				// default handler is mandatory. `default` entry MUST have both `api_code` and `http_code` set.
235
+				'default'            => [
236
+					'api_code'  => /** @scrutinizer ignore-deprecated */ BaseApiCodes::EX_UNCAUGHT_EXCEPTION(),
237
+					'http_code' => HttpResponse::HTTP_INTERNAL_SERVER_ERROR,
238
+				],
239
+			],
240
+		];
241
+	}
242
+
243
+	/**
244
+	 * Returns ExceptionHandlerHelper configration array with user configuration merged into built-in defaults.
245
+	 *
246
+	 * @return array
247
+	 */
248
+	protected static function getExceptionHandlerConfig(): array
249
+	{
250
+		return Util::mergeConfig(static::getExceptionHandlerDefaultConfig(),
251
+			\Config::get(ResponseBuilder::CONF_KEY_EXCEPTION_HANDLER, []));
252
+	}
253 253
 
254 254
 }
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -44,13 +44,13 @@  discard block
 block discarded – undo
44 44
             // Check if we have any exception configuration for this particular HTTP status code.
45 45
             // This confing entry is guaranted to exist (at least 'default'). Enforced by tests.
46 46
             $http_code = $ex->getStatusCode();
47
-            $ex_cfg = $cfg[ HttpException::class ][ $http_code ] ?? null;
48
-            $ex_cfg = $ex_cfg ?? $cfg[ HttpException::class ]['default'];
47
+            $ex_cfg = $cfg[HttpException::class][$http_code] ?? null;
48
+            $ex_cfg = $ex_cfg ?? $cfg[HttpException::class]['default'];
49 49
             $result = self::processException($ex, /** @scrutinizer ignore-type */ $ex_cfg, $http_code);
50 50
         } elseif ($ex instanceof ValidationException) {
51 51
             // This entry is guaranted to exist. Enforced by tests.
52 52
             $http_code = HttpResponse::HTTP_UNPROCESSABLE_ENTITY;
53
-            $result = self::processException($ex, $cfg[ HttpException::class ][ $http_code ], $http_code);
53
+            $result = self::processException($ex, $cfg[HttpException::class][$http_code], $http_code);
54 54
         }
55 55
 
56 56
         if ($result === null) {
@@ -145,7 +145,7 @@  discard block
 block discarded – undo
145 145
     {
146 146
         // This entry is guaranted to exist. Enforced by tests.
147 147
         $http_code = HttpResponse::HTTP_UNAUTHORIZED;
148
-        $cfg = static::getExceptionHandlerConfig()['map'][ HttpException::class ][ $http_code ];
148
+        $cfg = static::getExceptionHandlerConfig()['map'][HttpException::class][$http_code];
149 149
 
150 150
         return static::processException($exception, $cfg, $http_code);
151 151
     }
Please login to merge, or discard this patch.