Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
23 / 23
100.00% covered (success)
100.00%
1 / 1
CRAP
100.00% covered (success)
100.00%
1 / 1
NewsController
100.00% covered (success)
100.00%
23 / 23
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 list
100.00% covered (success)
100.00%
23 / 23
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3/**
4 * The News Controller for the REST API
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 2023-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     2023-07-30
16 */
17
18declare(strict_types=1);
19
20namespace phpMyFAQ\Controller\Api;
21
22use OpenApi\Attributes as OA;
23use phpMyFAQ\News;
24use Symfony\Component\HttpFoundation\JsonResponse;
25use Symfony\Component\HttpFoundation\Request;
26use Symfony\Component\Routing\Attribute\Route;
27
28final class NewsController extends AbstractApiController
29{
30    #[OA\Get(path: '/api/v4.0/news', operationId: 'getNews', tags: ['Public Endpoints'])]
31    #[OA\Header(
32        header: 'Accept-Language',
33        description: 'The language code for the news.',
34        schema: new OA\Schema(type: 'string'),
35    )]
36    #[OA\Parameter(
37        name: 'page',
38        description: 'Page number for pagination (page-based)',
39        in: 'query',
40        required: false,
41        schema: new OA\Schema(type: 'integer', default: 1),
42    )]
43    #[OA\Parameter(
44        name: 'per_page',
45        description: 'Items per page (page-based, max 100)',
46        in: 'query',
47        required: false,
48        schema: new OA\Schema(type: 'integer', default: 25),
49    )]
50    #[OA\Parameter(
51        name: 'limit',
52        description: 'Number of items to return (offset-based, max 100)',
53        in: 'query',
54        required: false,
55        schema: new OA\Schema(type: 'integer', default: 25),
56    )]
57    #[OA\Parameter(
58        name: 'offset',
59        description: 'Starting offset (offset-based)',
60        in: 'query',
61        required: false,
62        schema: new OA\Schema(type: 'integer', default: 0),
63    )]
64    #[OA\Parameter(name: 'sort', description: 'Field to sort by', in: 'query', required: false, schema: new OA\Schema(
65        type: 'string',
66        default: 'datum',
67        enum: ['id', 'datum', 'header', 'author_name'],
68    ))]
69    #[OA\Parameter(
70        name: 'order',
71        description: 'Sort direction',
72        in: 'query',
73        required: false,
74        schema: new OA\Schema(type: 'string', default: 'desc', enum: ['asc', 'desc']),
75    )]
76    #[OA\Response(
77        response: 200,
78        description: 'Returns paginated news for the given language provided by "Accept-Language".',
79        content: new OA\JsonContent(example: [
80            'success' => true,
81            'data' => [[
82                'id' => 1,
83                'lang' => 'en',
84                'date' => '2019-08-23T20:43:00+0200',
85                'header' => 'Hallo, World!',
86                'content' => 'Hello, phpMyFAQ!',
87                'authorName' => 'phpMyFAQ User',
88                'authorEmail' => 'user@example.org',
89                'active' => true,
90                'allowComments' => true,
91                'link' => '',
92                'linkTitle' => '',
93                'target' => '',
94                'url' => 'https://www.example.org/news/1/de/hallo-phpmyfaq.html',
95            ]],
96            'meta' => [
97                'pagination' => [
98                    'total' => 50,
99                    'count' => 25,
100                    'per_page' => 25,
101                    'current_page' => 1,
102                    'total_pages' => 2,
103                    'links' => [
104                        'first' => '/api/v4.0/news?page=1&per_page=25',
105                        'last' => '/api/v4.0/news?page=2&per_page=25',
106                        'prev' => null,
107                        'next' => '/api/v4.0/news?page=2&per_page=25',
108                    ],
109                ],
110                'sorting' => [
111                    'field' => 'datum',
112                    'order' => 'desc',
113                ],
114            ],
115        ]),
116    )]
117    #[Route(path: 'v4.0/news', name: 'api.news.list', methods: ['GET'])]
118    public function list(Request $request): JsonResponse
119    {
120        // Get pagination and sorting parameters
121        $pagination = $this->getPaginationRequest($request);
122        $sort = $this->getSortRequest(
123            $request,
124            allowedFields: ['id', 'datum', 'header', 'author_name'],
125            defaultField: 'datum',
126            defaultOrder: 'desc',
127        );
128
129        $news = new News($this->configuration);
130
131        // Get paginated news data
132        $data = $news->getLatestDataPaginated(
133            active: true,
134            limit: $pagination->limit,
135            offset: $pagination->offset,
136            sortField: $sort->getField() ?? 'datum',
137            sortOrder: $sort->getOrderSql(),
138        );
139
140        // Get total count
141        $total = $news->countLatestData();
142
143        return $this->paginatedResponse(
144            $request,
145            data: $data,
146            total: $total,
147            pagination: $pagination,
148            options: new PaginatedResponseOptions(sort: $sort),
149        );
150    }
151}