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

ResponseBuilder::make()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 3

Importance

Changes 11
Bugs 0 Features 0
Metric Value
cc 3
eloc 12
c 11
b 0
f 0
nc 4
nop 9
dl 0
loc 20
ccs 3
cts 3
cp 1
crap 3
rs 9.8666

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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