Passed
Push — dev ( 7a440c...34e2c4 )
by Marcin
08:24
created

ResponseBuilder   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 528
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 29
Bugs 0 Features 0
Metric Value
eloc 118
c 29
b 0
f 0
dl 0
loc 528
ccs 98
cts 98
cp 1
rs 9.76
wmc 33

17 Methods

Rating   Name   Duplication   Size   Complexity  
A success() 0 4 1
A getClassesMapping() 0 26 6
A successWithCode() 0 4 1
A successWithHttpCode() 0 3 1
A buildResponse() 0 36 5
A errorWithMessage() 0 3 1
A errorWithMessageAndDataAndDebug() 0 6 1
A errorWithDataAndHttpCode() 0 4 1
A errorWithMessageAndData() 0 5 1
A errorWithData() 0 4 1
A buildSuccessResponse() 0 15 1
A getMessageForApiCode() 0 17 4
A make() 0 20 3
A buildErrorResponse() 0 27 3
A errorWithHttpCode() 0 3 1
A error() 0 4 1
A successWithMessage() 0 4 1
1
<?php
2
declare(strict_types=1);
3
4
namespace MarcinOrlowski\ResponseBuilder;
5
6
/**
7
 * Laravel API Response Builder
8
 *
9
 * @package   MarcinOrlowski\ResponseBuilder
10
 *
11
 * @author    Marcin Orlowski <mail (#) marcinOrlowski (.) com>
12
 * @copyright 2016-2019 Marcin Orlowski
13
 * @license   http://www.opensource.org/licenses/mit-license.php MIT
14
 * @link      https://github.com/MarcinOrlowski/laravel-api-response-builder
15
 */
16
17
use Illuminate\Support\Facades\Config;
18
use Illuminate\Support\Facades\Response;
19
use Symfony\Component\HttpFoundation\Response as HttpResponse;
20
21
22
/**
23
 * Builds standardized HttpResponse response object
24
 */
25
class ResponseBuilder
26
{
27
    /**
28
     * Default HTTP code to be used with success responses
29
     *
30
     * @var int
31
     */
32
    public const DEFAULT_HTTP_CODE_OK = HttpResponse::HTTP_OK;
33
34
    /**
35
     * Default HTTP code to be used with error responses
36
     *
37
     * @var int
38
     */
39
    public const DEFAULT_HTTP_CODE_ERROR = HttpResponse::HTTP_BAD_REQUEST;
40
41
    /**
42
     * Min allowed HTTP code for errorXXX()
43
     *
44
     * @var int
45
     */
46
    public const ERROR_HTTP_CODE_MIN = 400;
47
48
    /**
49
     * Max allowed HTTP code for errorXXX()
50
     *
51
     * @var int
52
     */
53
    public const ERROR_HTTP_CODE_MAX = 599;
54
55
    /**
56
     * Configuration keys
57
     */
58
    public const CONF_KEY_DEBUG_DEBUG_KEY        = 'response_builder.debug.debug_key';
59
    public const CONF_KEY_DEBUG_EX_TRACE_ENABLED = 'response_builder.debug.exception_handler.trace_enabled';
60
    public const CONF_KEY_DEBUG_EX_TRACE_KEY     = 'response_builder.debug.exception_handler.trace_key';
61
    public const CONF_KEY_MAP                    = 'response_builder.map';
62
    public const CONF_KEY_ENCODING_OPTIONS       = 'response_builder.encoding_options';
63
    public const CONF_KEY_CLASSES                = 'response_builder.classes';
64
    public const CONF_KEY_MIN_CODE               = 'response_builder.min_code';
65
    public const CONF_KEY_MAX_CODE               = 'response_builder.max_code';
66
    public const CONF_EXCEPTION_HANDLER_KEY      = 'response_builder.exception_handler';
67
68
    /**
69
     * Default keys to be used by exception handler while adding debug information
70
     */
71
    public const KEY_DEBUG   = 'debug';
72
    public const KEY_TRACE   = 'trace';
73
    public const KEY_CLASS   = 'class';
74
    public const KEY_FILE    = 'file';
75
    public const KEY_LINE    = 'line';
76
    public const KEY_KEY     = 'key';
77
    public const KEY_METHOD  = 'method';
78
    public const KEY_SUCCESS = 'success';
79
    public const KEY_CODE    = 'code';
80
    public const KEY_LOCALE  = 'locale';
81
    public const KEY_MESSAGE = 'message';
82
    public const KEY_DATA    = 'data';
83
84
    /**
85
     * Default key to be used by exception handler while processing ValidationException
86
     * to return all the error messages
87
     *
88
     * @var string
89
     */
90
    public const KEY_MESSAGES = 'messages';
91
92
    /**
93
     * Default JSON encoding options. Must be specified as final value (i.e. 271) and NOT
94
     * PHP expression i.e. `JSON_HEX_TAG|JSON_HEX_APOS|...` as such syntax is not yet supported
95
     * by PHP.
96
     *
97
     * 271 = JSON_HEX_TAG|JSON_HEX_APOS|JSON_HEX_AMP|JSON_HEX_QUOT|JSON_UNESCAPED_UNICODE
98
     *
99
     * @var int
100
     */
101
    public const DEFAULT_ENCODING_OPTIONS = 271;
102
103
    /**
104
     * Reads and validates "classes" config mapping
105
     *
106
     * @return array Classes mapping as specified in configuration or empty array if configuration found
107
     *
108
     * @throws \RuntimeException if "classes" mapping is technically invalid (i.e. not array etc).
109
     */
110 4
    protected static function getClassesMapping(): ?array
111
    {
112 4
        $classes = Config::get(self::CONF_KEY_CLASSES);
113
114 4
        if ($classes !== null) {
115 3
            if (!is_array($classes)) {
116 2
                throw new \RuntimeException(
117 2
                    sprintf('CONFIG: "classes" mapping must be an array (%s given)', gettype($classes)));
118
            }
119
120
            $mandatory_keys = [
121 1
                static::KEY_KEY,
122 1
                static::KEY_METHOD,
123
            ];
124 1
            foreach ($classes as $class_name => $class_config) {
125 1
                foreach ($mandatory_keys as $key_name) {
126 1
                    if (!array_key_exists($key_name, $class_config)) {
127 1
                        throw new \RuntimeException("CONFIG: Missing '{$key_name}' for '{$class_name}' class mapping");
128
                    }
129
                }
130
            }
131
        } else {
132 1
            $classes = [];
133
        }
134
135 1
        return $classes;
136
    }
137
138
    /**
139
     * Returns success
140
     *
141
     * @param object|array|null $data          Array of primitives and supported objects to be returned in 'data' node
142
     *                                         of the JSON response, single supported object or @null if there's no
143
     *                                         to be returned.
144
     * @param integer|null      $api_code      API code to be returned or @null to use value of BaseApiCodes::OK().
145
     * @param array|null        $placeholders  Placeholders passed to Lang::get() for message placeholders
146
     *                                         substitution or @null if none.
147
     * @param integer|null      $http_code     HTTP code to be used for HttpResponse sent or @null
148
     *                                         for default DEFAULT_HTTP_CODE_OK.
149
     * @param integer|null      $json_opts     See http://php.net/manual/en/function.json-encode.php for supported
150
     *                                         options or pass @null to use value from your config (or defaults).
151
     *
152
     * @return HttpResponse
153
     */
154 12
    public static function success($data = null, $api_code = null, array $placeholders = null,
155
                                   int $http_code = null, int $json_opts = null): HttpResponse
156
    {
157 12
        return static::buildSuccessResponse($data, $api_code, $placeholders, $http_code, $json_opts);
158
    }
159
160
    /**
161
     * Returns success
162
     *
163
     * @param integer|null $api_code      API code to be returned or @null to use value of BaseApiCodes::OK().
164
     * @param array|null   $placeholders  Placeholders passed to Lang::get() for message placeholders
165
     *                                    substitution or @null if none.
166
     * @param integer|null $http_code     HTTP code to be used for HttpResponse sent or @null
167
     *                                    for default DEFAULT_HTTP_CODE_OK.
168
     *
169
     * @return HttpResponse
170
     */
171 1
    public static function successWithCode(int $api_code = null, array $placeholders = null,
172
                                           int $http_code = null): HttpResponse
173
    {
174 1
        return static::success(null, $api_code, $placeholders, $http_code);
175
    }
176
177
    /**
178
     * Returns success with custom HTTP code
179
     *
180
     * @param integer|null $http_code HTTP return code to be set for this response. If @null is passed, falls back
181
     *                                to DEFAULT_HTTP_CODE_OK.
182
     *
183
     * @return HttpResponse
184
     */
185 4
    public static function successWithHttpCode(int $http_code = null): HttpResponse
186
    {
187 4
        return static::buildSuccessResponse(null, BaseApiCodes::OK(), [], $http_code);
188
    }
189
190
    /**
191
     * @param string            $message       Custom message to be returned as part of the response.
192
     * @param object|array|null $data          Array of primitives and supported objects to be returned in 'data' node
193
     *                                         of the JSON response, single supported object or @null if there's no
194
     *                                         to be returned.
195
     * @param integer|null      $http_code     HTTP code to be used for HttpResponse sent or @null
196
     *                                         for default DEFAULT_HTTP_CODE_OK.
197
     *
198
     * @return \Symfony\Component\HttpFoundation\Response
199
     */
200
    public static function successWithMessage(string $message, $data = null, int $api_code = null,
201
                                              int $http_code = null): HttpResponse
202
    {
203
        return static::buildSuccessResponse($data, $api_code, [], $http_code, null, $message);
204
    }
205
206 16
    /**
207
     * @param object|array|null $data          Array of primitives and supported objects to be returned in 'data' node.
208
     *                                         of the JSON response, single supported object or @null if there's no
209 16
     *                                         to be returned.
210 16
     * @param integer|null      $api_code      API code to be returned or @null to use value of BaseApiCodes::OK().
211
     * @param array|null        $placeholders  Placeholders passed to Lang::get() for message placeholders
212 16
     *                                         substitution or @null if none.
213 16
     * @param integer|null      $http_code     HTTP code to be used for HttpResponse sent or @null
214 16
     *                                         for default DEFAULT_HTTP_CODE_OK.
215
     * @param integer|null      $json_opts     See http://php.net/manual/en/function.json-encode.php for supported
216 14
     *                                         options or pass @null to use value from your config (or defaults).
217
     *
218
     * @return HttpResponse
219
     *
220
     * @throws \InvalidArgumentException Thrown when provided arguments are invalid.
221
     */
222
    protected static function buildSuccessResponse($data = null, int $api_code = null, array $placeholders = null,
223
                                                   int $http_code = null, int $json_opts = null,
224
                                                   $msg_or_api_code = null): HttpResponse
225
    {
226
        $http_code = $http_code ?? static::DEFAULT_HTTP_CODE_OK;
227
        $api_code = $api_code ?? BaseApiCodes::OK();
228
        $msg_or_api_code = $msg_or_api_code ?? $api_code;
229
230
        Validator::assertInt('api_code', $api_code);
231
        Validator::assertInt('http_code', $http_code);
232
        Validator::assertIntRange('http_code', $http_code, 200, 299);
233
        Validator::assertType('msg_or_api_code', $msg_or_api_code, [Validator::TYPE_STRING,
234
                                                                    Validator::TYPE_INTEGER]);
235
236 5
        return static::make(true, $api_code, $msg_or_api_code, $data, $http_code, $placeholders, null, $json_opts);
237
    }
238
239 5
    /**
240
     * Builds error Response object. Supports optional arguments passed to Lang::get() if associated error
241
     * message uses placeholders as well as return data payload
242
     *
243
     * @param integer           $api_code      Your API code to be returned with the response object.
244
     * @param array|null        $placeholders  Placeholders passed to Lang::get() for message placeholders
245
     *                                         substitution or @null if none.
246
     * @param object|array|null $data          Array of primitives and supported objects to be returned in 'data' node
247
     *                                         of the JSON response, single supported object or @null if there's no
248
     *                                         to be returned.
249
     * @param integer|null      $http_code     HTTP code to be used for HttpResponse sent or @null
250
     *                                         for default DEFAULT_HTTP_CODE_ERROR.
251
     * @param integer|null      $json_opts     See http://php.net/manual/en/function.json-encode.php for supported
252
     *                                         options or pass @null to use value from your config (or defaults).
253
     *
254 1
     * @return HttpResponse
255
     */
256
    public static function error(int $api_code, array $placeholders = null, $data = null, int $http_code = null,
257 1
                                 int $encoding_options = null): HttpResponse
258
    {
259
        return static::buildErrorResponse($data, $api_code, $http_code, $placeholders, $encoding_options);
260
    }
261
262
    /**
263
     * @param integer           $api_code      Your API code to be returned with the response object.
264
     * @param object|array|null $data          Array of primitives and supported objects to be returned in 'data' node
265
     *                                         of the JSON response, single supported object or @null if there's no
266
     *                                         to be returned.
267
     * @param array|null        $placeholders  Placeholders passed to Lang::get() for message placeholders
268
     *                                         substitution or @null if none.
269
     * @param integer|null      $json_opts     See http://php.net/manual/en/function.json-encode.php for supported
270
     *                                         options or pass @null to use value from your config (or defaults).
271
     *
272
     * @return HttpResponse
273
     */
274
    public static function errorWithData(int $api_code, $data, array $placeholders = null,
275 1
                                         int $json_opts = null): HttpResponse
276
    {
277
        return static::buildErrorResponse($data, $api_code, null, $placeholders, $json_opts);
278 1
    }
279
280
    /**
281
     * @param integer           $api_code      Your API code to be returned with the response object.
282
     * @param object|array|null $data          Array of primitives and supported objects to be returned in 'data' node
283
     *                                         of the JSON response, single supported object or @null if there's no
284
     *                                         to be returned.
285
     * @param integer           $http_code     HTTP code to be used for HttpResponse sent.
286
     * @param array|null        $placeholders  Placeholders passed to Lang::get() for message placeholders
287
     *                                         substitution or @null if none.
288
     * @param integer|null      $json_opts     See http://php.net/manual/en/function.json-encode.php for supported
289
     *                                         options or pass @null to use value from your config (or defaults).
290
     *
291
     * @return HttpResponse
292 1
     *
293
     * @throws \InvalidArgumentException if http_code is @null
294 1
     */
295
    public static function errorWithDataAndHttpCode(int $api_code, $data, int $http_code, array $placeholders = null,
296
                                                    int $json_opts = null): HttpResponse
297
    {
298
        return static::buildErrorResponse($data, $api_code, $http_code, $placeholders, $json_opts);
299
    }
300
301
    /**
302
     * @param integer    $api_code     Your API code to be returned with the response object.
303
     * @param integer    $http_code    HTTP code to be used for HttpResponse sent or @null
304
     *                                 for default DEFAULT_HTTP_CODE_ERROR.
305
     * @param array|null $placeholders Placeholders passed to Lang::get() for message placeholders
306
     *                                 substitution or @null if none.
307
     *
308
     * @return HttpResponse
309
     *
310 1
     * @throws \InvalidArgumentException if http_code is @null
311
     */
312
    public static function errorWithHttpCode(int $api_code, int $http_code, array $placeholders = null): HttpResponse
313 1
    {
314 1
        return static::buildErrorResponse(null, $api_code, $http_code, $placeholders);
315
    }
316
317
    /**
318
     * @param integer           $api_code  Your API code to be returned with the response object.
319
     * @param string            $message   Custom message to be returned as part of error response
320
     * @param object|array|null $data      Array of primitives and supported objects to be returned in 'data' node
321
     *                                     of the JSON response, single supported object or @null if there's no
322
     *                                     to be returned.
323
     * @param integer|null      $http_code Optional HTTP status code to be used for HttpResponse sent
324
     *                                     or @null for DEFAULT_HTTP_CODE_ERROR
325
     * @param integer|null      $json_opts See http://php.net/manual/en/function.json-encode.php for supported
326
     *                                     options or pass @null to use value from your config (or defaults).
327
     *
328
     * @return HttpResponse
329
     */
330
    public static function errorWithMessageAndData(int $api_code, string $message, $data,
331 6
                                                   int $http_code = null, int $json_opts = null): HttpResponse
332
    {
333
        return static::buildErrorResponse($data, $api_code, $http_code, null,
334
            $message, null, $json_opts);
335 6
    }
336 6
337
    /**
338
     * @param integer           $api_code   Your API code to be returned with the response object.
339
     * @param string            $message    custom message to be returned as part of error response
340
     * @param object|array|null $data       Array of primitives and supported objects to be returned in 'data' node
341
     *                                      of the JSON response, single supported object or @null if there's no
342
     *                                      to be returned.
343
     * @param integer|null      $http_code  HTTP code to be used for HttpResponse sent or @null
344
     *                                      for default DEFAULT_HTTP_CODE_ERROR.
345
     * @param integer|null      $json_opts  See http://php.net/manual/en/function.json-encode.php for supported
346
     *                                      options or pass @null to use value from your config (or defaults).
347 1
     * @param array|null        $debug_data optional debug data array to be added to returned JSON.
348
     *
349 1
     * @return HttpResponse
350
     */
351
    public static function errorWithMessageAndDataAndDebug(int $api_code, string $message, $data,
352
                                                           int $http_code = null, int $json_opts = null,
353
                                                           array $debug_data = null): HttpResponse
354
    {
355
        return static::buildErrorResponse($data, $api_code, $http_code, null,
356
            $message, null, $json_opts, $debug_data);
357
    }
358
359
    /**
360
     * @param integer      $api_code  Your API code to be returned with the response object.
361
     * @param string       $message   Custom message to be returned as part of error response
362
     * @param integer|null $http_code HTTP code to be used with final response sent or @null
363
     *                                for default DEFAULT_HTTP_CODE_ERROR.
364
     *
365
     * @return HttpResponse
366
     */
367
    public static function errorWithMessage(int $api_code, string $message, int $http_code = null): HttpResponse
368
    {
369
        return static::buildErrorResponse(null, $api_code, $http_code, null, $message);
370
    }
371
372
    /**
373
     * Builds error Response object. Supports optional arguments passed to Lang::get() if associated error message
374
     * uses placeholders as well as return data payload
375
     *
376 19
     * @param object|array|null $data          Array of primitives and supported objects to be returned in 'data' node
377
     *                                         of the JSON response, single supported object or @null if there's no
378
     *                                         to be returned.
379
     * @param integer           $api_code      Your API code to be returned with the response object.
380
     * @param integer|null      $http_code     HTTP code to be used for HttpResponse sent or @null
381
     *                                         for default DEFAULT_HTTP_CODE_ERROR.
382 19
     * @param array|null        $placeholders  Placeholders passed to Lang::get() for message placeholders
383 19
     *                                         substitution or @null if none.
384
     * @param string|null       $message       custom message to be returned as part of error response
385 19
     * @param array|null        $headers       optional HTTP headers to be returned in error response
386
     * @param integer|null      $json_opts     See http://php.net/manual/en/function.json-encode.php for supported
387 19
     *                                         options or pass @null to use value from your config (or defaults).
388 19
     * @param array|null        $debug_data    optional debug data array to be added to returned JSON.
389 17
     *
390
     * @return HttpResponse
391 19
     *
392 2
     * @throws \InvalidArgumentException Thrown if $code is not correct, outside the range, equals OK code etc.
393 2
     *
394
     * @noinspection MoreThanThreeArgumentsInspection
395
     */
396 17
    protected static function buildErrorResponse($data, int $api_code, int $http_code = null,
397 17
                                                 array $placeholders = null,
398
                                                 string $message = null, array $headers = null,
399 16
                                                 int $json_opts = null,
400
                                                 array $debug_data = null): HttpResponse
401 16
    {
402 16
        $http_code = $http_code ?? static::DEFAULT_HTTP_CODE_ERROR;
403
        $headers = $headers ?? [];
404
405
        Validator::assertInt('api_code', $api_code);
406
407
        $code_ok = BaseApiCodes::OK();
408
        if ($api_code !== $code_ok) {
409
            Validator::assertIntRange('api_code', $api_code, BaseApiCodes::getMinCode(), BaseApiCodes::getMaxCode());
410
        }
411
        if ($api_code === $code_ok) {
412
            throw new \InvalidArgumentException(
413
                "Error response cannot use api_code of value  {$code_ok} which is reserved for OK");
414
        }
415
416
        Validator::assertInt('http_code', $http_code);
417
        Validator::assertIntRange('http_code', $http_code, static::ERROR_HTTP_CODE_MIN, static::ERROR_HTTP_CODE_MAX);
418
419
        $msg_or_api_code = $message ?? $api_code;
420
421
        return static::make(false, $api_code, $msg_or_api_code, $data, $http_code,
422
            $placeholders, $headers, $json_opts, $debug_data);
423
    }
424
425
    /**
426 36
     * @param boolean           $success         @true if response reports successful operation, @false otherwise.
427
     * @param integer           $api_code        Your API code to be returned with the response object.
428
     * @param string|integer    $msg_or_api_code message string or valid API code to get message for
429
     * @param object|array|null $data            optional additional data to be included in response object
430 36
     * @param integer|null      $http_code       HTTP code for the HttpResponse or @null for either DEFAULT_HTTP_CODE_OK
431 36
     *                                           or DEFAULT_HTTP_CODE_ERROR depending on the $success.
432 36
     * @param array|null        $placeholders    Placeholders passed to Lang::get() for message placeholders
433
     *                                           substitution or @null if none.
434 36
     * @param array|null        $headers         Optional HTTP headers to be returned in the response.
435
     * @param integer|null      $json_opts       See http://php.net/manual/en/function.json-encode.php for supported
436 35
     *                                           options or pass @null to use value from your config (or defaults).
437 35
     * @param array|null        $debug_data      Optional debug data array to be added to returned JSON.
438 1
     *
439 1
     * @return HttpResponse
440 1
     *
441
     * @throws \InvalidArgumentException If $api_code is neither a string nor valid integer code.
442
     * @throws \InvalidArgumentException if $data is an object of class that is not configured in "classes" mapping.
443 34
     *
444 34
     * @noinspection MoreThanThreeArgumentsInspection
445 29
     */
446
    protected static function make(bool $success, int $api_code, $msg_or_api_code, $data = null,
447
                                   int $http_code = null, array $placeholders = null, array $headers = null,
448
                                   int $json_opts = null, array $debug_data = null): HttpResponse
449
    {
450
        $headers = $headers ?? [];
451
        $http_code = $http_code ?? ($success ? static::DEFAULT_HTTP_CODE_OK : static::DEFAULT_HTTP_CODE_ERROR);
452
        $json_opts = $json_opts ?? Config::get(self::CONF_KEY_ENCODING_OPTIONS, static::DEFAULT_ENCODING_OPTIONS);
453
454
        Validator::assertInt('encoding_options', $json_opts);
455
456
        Validator::assertInt('api_code', $api_code);
457
        if (!BaseApiCodes::isCodeValid($api_code)) {
458
            $min = BaseApiCodes::getMinCode();
459
            $max = BaseApiCodes::getMaxCode();
460 21
            throw new \InvalidArgumentException("API code value ({$api_code}) is out of allowed range {$min}-{$max}");
461
        }
462
463
        return Response::json(
464 21
            static::buildResponse($success, $api_code, $msg_or_api_code, $placeholders, $data, $debug_data),
465 21
            $http_code, $headers, $json_opts);
466
    }
467 2
468 2
    /**
469
     * If $msg_or_api_code is integer value, returns human readable message associated with that code (with
470
     * fallback to built-in default string if no api code mapping is set. If $msg_or_api_code is a string,
471 21
     * returns it unaltered.
472 21
     *
473 19
     * @param boolean    $success      @true if response reports successful operation, @false otherwise.
474
     * @param integer    $api_code     Your API code to be returned with the response object.
475
     * @param array|null $placeholders Placeholders passed to Lang::get() for message placeholders
476 21
     *                                 substitution or @null if none.
477
     *
478
     * @return string
479
     */
480
    protected static function getMessageForApiCode(bool $success, int $api_code, array $placeholders = null): string
481
    {
482
        // We got integer value here not a message string, so we need to check if we have the mapping for
483
        // this string already configured.
484
        $key = BaseApiCodes::getCodeMessageKey($api_code);
485
        if ($key === null) {
486
            // nope, let's get the default one instead, based of
487
            $fallback_code = $success ? BaseApiCodes::OK() : BaseApiCodes::NO_ERROR_MESSAGE();
488
            $key = BaseApiCodes::getCodeMessageKey($fallback_code);
489
        }
490
491
        $placeholders = $placeholders ?? [];
492
        if (!array_key_exists('api_code', $placeholders)) {
493
            $placeholders['api_code'] = $api_code;
494
        }
495
496
        return \Lang::get($key, $placeholders);
497 34
    }
498
499
    /**
500
     * Creates standardised API response array. This is final method called in the whole pipeline before we
501
     * return final JSON back to client. If you want to manipulate your response, this is the place to do that.
502 34
     * If you set APP_DEBUG to true, 'code_hex' field will be additionally added to reported JSON for easier
503
     * manual debugging.
504 34
     *
505 31
     * @param boolean           $success         @true if response reports successful operation, @false otherwise.
506
     * @param integer           $api_code        Your API code to be returned with the response object.
507 12
     * @param string|integer    $msg_or_api_code Message string or valid API code to get message for.
508
     * @param array|null        $placeholders    Placeholders passed to Lang::get() for message placeholders
509
     *                                           substitution or @null if none.
510
     * @param object|array|null $data            API response data if any
511 31
     * @param array|null        $debug_data      optional debug data array to be added to returned JSON.
512 21
     *
513
     * @return array response ready to be encoded as json and sent back to client
514 10
     *
515 8
     * @throws \RuntimeException in case of missing or invalid "classes" mapping configuration
516
     */
517
    protected static function buildResponse(bool $success, int $api_code,
518
                                            $msg_or_api_code, array $placeholders = null,
519
                                            $data = null, array $debug_data = null): array
520 29
    {
521 29
        // ensure $data is either @null, array or object of class with configured mapping.
522 29
        $converter = new Converter();
523 29
524 29
        $data = $converter->convert($data);
525
        if ($data !== null && !is_object($data)) {
526
            // ensure we get object in final JSON structure in data node
527 29
            $data = (object)$data;
528 2
        }
529 2
530
        // get human readable message for API code or use message string (if given instead of API code)
531
        if (is_int($msg_or_api_code)) {
532 29
            $message = self::getMessageForApiCode($success, $msg_or_api_code, $placeholders);
533
        } else {
534
            Validator::assertString('message', $msg_or_api_code);
535
            $message = $msg_or_api_code;
536
        }
537
538
        /** @noinspection PhpUndefinedClassInspection */
539
        $response = [
540
            static::KEY_SUCCESS => $success,
541
            static::KEY_CODE    => $api_code,
542
            static::KEY_LOCALE  => \App::getLocale(),
543
            static::KEY_MESSAGE => $message,
544
            static::KEY_DATA    => $data,
545
        ];
546
547
        if ($debug_data !== null) {
548
            $debug_key = Config::get(static::CONF_KEY_DEBUG_DEBUG_KEY, self::KEY_DEBUG);
549
            $response[ $debug_key ] = $debug_data;
550
        }
551
552
        return $response;
553
    }
554
555
}
556