Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
26 / 26
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
ApiResponse
100.00% covered (success)
100.00%
26 / 26
100.00% covered (success)
100.00%
3 / 3
11
100.00% covered (success)
100.00%
1 / 1
 success
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
 error
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
2
 buildMetadata
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
7
1<?php
2
3/**
4 * API Response Envelope
5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public License,
7 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
8 * obtain one at https://mozilla.org/MPL/2.0/.
9 *
10 * @package   phpMyFAQ
11 * @author    Thorsten Rinne <thorsten@phpmyfaq.de>
12 * @copyright 2026 phpMyFAQ Team
13 * @license   https://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
14 * @link      https://www.phpmyfaq.de
15 * @since     2026-01-11
16 */
17
18declare(strict_types=1);
19
20namespace phpMyFAQ\Api\Response;
21
22use phpMyFAQ\Api\Filtering\FilterRequest;
23use phpMyFAQ\Api\Pagination\PaginationMetadata;
24use phpMyFAQ\Api\Sorting\SortRequest;
25
26/**
27 * Class ApiResponse
28 *
29 * Provides a standardized response envelope for API responses including
30 * success/error status, data payload, and metadata (pagination, sorting, filtering).
31 */
32class ApiResponse
33{
34    /**
35     * Creates a successful API response with data and optional metadata
36     *
37     * @param array|object $data The response data
38     * @param PaginationMetadata|null $pagination Optional pagination metadata
39     * @param SortRequest|null $sort Optional sorting information
40     * @param FilterRequest|null $filters Optional filtering information
41     * @return array Standardized response array
42     */
43    public static function success(
44        array|object $data,
45        ?PaginationMetadata $pagination = null,
46        ?SortRequest $sort = null,
47        ?FilterRequest $filters = null,
48    ): array {
49        $response = [
50            'success' => true,
51            'data' => $data,
52        ];
53
54        // Build metadata if any is present
55        $meta = self::buildMetadata($pagination, $sort, $filters);
56        if ($meta !== null) {
57            $response['meta'] = $meta;
58        }
59
60        return $response;
61    }
62
63    /**
64     * Creates an error API response
65     *
66     * @param string $message Error message
67     * @param string $code Error code
68     * @param array|null $details Optional error details
69     * @return array Standardized error response array
70     */
71    public static function error(string $message, string $code = 'ERROR', ?array $details = null): array
72    {
73        $response = [
74            'success' => false,
75            'error' => [
76                'code' => $code,
77                'message' => $message,
78            ],
79        ];
80
81        if ($details !== null) {
82            $response['error']['details'] = $details;
83        }
84
85        return $response;
86    }
87
88    /**
89     * Builds the metadata section of the response
90     *
91     * @param PaginationMetadata|null $pagination Pagination metadata
92     * @param SortRequest|null $sort Sort information
93     * @param FilterRequest|null $filters Filter information
94     * @return array|null Metadata array or null if no metadata
95     */
96    private static function buildMetadata(
97        ?PaginationMetadata $pagination,
98        ?SortRequest $sort,
99        ?FilterRequest $filters,
100    ): ?array {
101        $meta = [];
102
103        if ($pagination !== null) {
104            $meta['pagination'] = $pagination->toArray();
105        }
106
107        if ($sort !== null && $sort->hasSort()) {
108            $meta['sorting'] = $sort->toArray();
109        }
110
111        if ($filters !== null && $filters->hasFilters()) {
112            $meta['filters'] = $filters->toArray();
113        }
114
115        return $meta === [] ? null : $meta;
116    }
117}