PluginProbe
404 Solution / trunk
404 Solution vtrunk
4.3.5 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 4.2.0 4.1.19 4.1.18 4.1.17 4.1.16 4.1.15 4.1.13 4.1.12 4.1.11 4.1.10 4.1.9 4.1.8 4.1.7 4.1.6 4.1.5 4.1.4 4.1.3 trunk 2.30.0 All 109 releases
404-solution / includes / rest / RestApiController.php

RestApiController.php in 404 Solution trunk, at includes/rest/RestApiController.php

329 lines 12.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('ABSPATH')) {
4 exit;
5 }
6
7 /**
8 * REST API route adapter for the abj404/v1 namespace.
9 *
10 * Registers routes and delegates request parsing, mutations, reads, and
11 * response shaping to focused collaborators.
12 */
13 class ABJ_404_Solution_RestApiController {
14
15 const NAMESPACE = 'abj404/v1';
16
17 /** @var object */
18 private $logic;
19
20 /** @var ABJ_404_Solution_RestApiRequestParser */
21 private $requestParser;
22
23 /** @var ABJ_404_Solution_RestApiReadService */
24 private $readService;
25
26 /** @var ABJ_404_Solution_RestApiRedirectMutationService */
27 private $mutationService;
28
29 /**
30 * @param ABJ_404_Solution_DataAccess|ABJ_404_Solution_PluginLogic $daoOrLogic Legacy: DataAccess + PluginLogic. New: just PluginLogic.
31 * @param ABJ_404_Solution_PluginLogic|null $logic
32 * @param ABJ_404_Solution_StatsRepositoryInterface|null $statsRepository
33 */
34 public function __construct($daoOrLogic, $logic = null, $statsRepository = null) {
35 $presenter = new ABJ_404_Solution_RestApiResponsePresenter();
36 $this->requestParser = new ABJ_404_Solution_RestApiRequestParser();
37
38 if ($logic !== null && $daoOrLogic instanceof ABJ_404_Solution_DataAccess) {
39 $dao = $daoOrLogic;
40 $this->logic = $logic;
41 $viewRead = $dao->getViewReadService();
42 $redirectsRepo = $dao->getRedirectsRepo();
43 $logsRepo = $dao->getLogsRepo();
44 $statsRepo = $this->resolveStatsRepository($statsRepository, $dao);
45 $dbCore = $dao->getDbCore();
46 } else {
47 $logicService = abj_service('plugin_logic');
48 $this->logic = $daoOrLogic instanceof ABJ_404_Solution_PluginLogic
49 ? $daoOrLogic
50 : $logicService;
51 $fallbackDao = abj_service('data_access');
52 $viewReadService = abj_service('view_read_service');
53 $viewRead = $viewReadService instanceof ABJ_404_Solution_ViewReadServiceInterface ? $viewReadService : $fallbackDao->getViewReadService();
54 $redirectsService = abj_service('redirects_repository');
55 $redirectsRepo = $redirectsService instanceof ABJ_404_Solution_RedirectsRepositoryInterface ? $redirectsService : $fallbackDao->getRedirectsRepo();
56 $logsService = abj_service('logs_repository');
57 $logsRepo = $logsService instanceof ABJ_404_Solution_LogsRepositoryInterface ? $logsService : $fallbackDao->getLogsRepo();
58 $statsRepo = $this->resolveStatsRepository($statsRepository, null);
59 $dbCoreService = abj_service('db_core');
60 $dbCore = $dbCoreService instanceof ABJ_404_Solution_DatabaseQueryInterface ? $dbCoreService : $fallbackDao->getDbCore();
61 }
62
63 $this->readService = new ABJ_404_Solution_RestApiReadService(
64 $viewRead,
65 $redirectsRepo,
66 $logsRepo,
67 $statsRepo,
68 $dbCore,
69 $this->logic,
70 $presenter
71 );
72 $this->mutationService = new ABJ_404_Solution_RestApiRedirectMutationService(
73 $redirectsRepo,
74 $presenter
75 );
76 }
77
78 /**
79 * @param ABJ_404_Solution_StatsRepositoryInterface|null $provided
80 * @param mixed $legacyDao
81 * @return ABJ_404_Solution_StatsRepositoryInterface
82 */
83 private function resolveStatsRepository($provided, $legacyDao): ABJ_404_Solution_StatsRepositoryInterface {
84 if ($provided instanceof ABJ_404_Solution_StatsRepositoryInterface) {
85 return $provided;
86 }
87
88 $service = class_exists('ABJ_404_Solution_ServiceContainer')
89 ? ABJ_404_Solution_ServiceContainer::safeGet('stats_repository')
90 : null;
91 if ($service instanceof ABJ_404_Solution_StatsRepositoryInterface) {
92 return $service;
93 }
94
95 return ABJ_404_Solution_StatsRepositoryResolver::resolve(__CLASS__);
96 }
97
98 /** @return void */
99 public function register() {
100 add_action('rest_api_init', array($this, 'registerRoutes'));
101 add_filter('rest_index_data', array($this, 'hideNamespaceFromIndex'));
102 }
103
104 /**
105 * Remove this plugin's namespace from the publicly-enumerable namespace list.
106 *
107 * @param array<string,mixed> $data
108 * @return array<string,mixed>
109 */
110 public function hideNamespaceFromIndex($data) {
111 if (is_array($data) && isset($data['namespaces']) && is_array($data['namespaces'])) {
112 $data['namespaces'] = array_values(
113 array_filter($data['namespaces'], function ($ns) {
114 return $ns !== self::NAMESPACE;
115 })
116 );
117 }
118 return $data;
119 }
120
121 /** @return void */
122 public function registerRoutes() {
123 register_rest_route(self::NAMESPACE, '/redirects', array(
124 array(
125 'methods' => 'GET',
126 'callback' => array($this, 'getRedirects'),
127 'permission_callback' => array($this, 'permissionCheck'),
128 'args' => array(
129 'page' => array('type' => 'integer', 'default' => 1, 'minimum' => 1),
130 'per_page' => array('type' => 'integer', 'default' => 20, 'minimum' => 1, 'maximum' => 100),
131 'status' => array('type' => 'string', 'default' => ''),
132 'filter' => array('type' => 'string', 'default' => ''),
133 ),
134 ),
135 array(
136 'methods' => 'POST',
137 'callback' => array($this, 'createRedirect'),
138 'permission_callback' => array($this, 'permissionCheck'),
139 'args' => array(
140 'from' => array('type' => 'string', 'required' => true),
141 'to' => array('type' => 'string', 'required' => true),
142 'code' => array('type' => 'integer', 'default' => 301),
143 'regex' => array('type' => 'boolean', 'default' => false),
144 ),
145 ),
146 ));
147
148 register_rest_route(self::NAMESPACE, '/redirects/(?P<id>\d+)', array(
149 array(
150 'methods' => 'PUT',
151 'callback' => array($this, 'updateRedirect'),
152 'permission_callback' => array($this, 'permissionCheck'),
153 'args' => array(
154 'id' => array('type' => 'integer', 'required' => true),
155 'from' => array('type' => 'string'),
156 'to' => array('type' => 'string'),
157 'code' => array('type' => 'integer'),
158 'regex' => array('type' => 'boolean'),
159 ),
160 ),
161 array(
162 'methods' => 'DELETE',
163 'callback' => array($this, 'deleteRedirect'),
164 'permission_callback' => array($this, 'permissionCheck'),
165 'args' => array(
166 'id' => array('type' => 'integer', 'required' => true),
167 ),
168 ),
169 ));
170
171 register_rest_route(self::NAMESPACE, '/captured', array(
172 'methods' => 'GET',
173 'callback' => array($this, 'getCaptured'),
174 'permission_callback' => array($this, 'permissionCheck'),
175 'args' => array(
176 'page' => array('type' => 'integer', 'default' => 1, 'minimum' => 1),
177 'per_page' => array('type' => 'integer', 'default' => 20, 'minimum' => 1, 'maximum' => 100),
178 ),
179 ));
180
181 register_rest_route(self::NAMESPACE, '/captured/(?P<id>\d+)/redirect', array(
182 'methods' => 'POST',
183 'callback' => array($this, 'createRedirectFromCaptured'),
184 'permission_callback' => array($this, 'permissionCheck'),
185 'args' => array(
186 'id' => array('type' => 'integer', 'required' => true),
187 'to' => array('type' => 'string', 'required' => true),
188 'code' => array('type' => 'integer', 'default' => 301),
189 ),
190 ));
191
192 register_rest_route(self::NAMESPACE, '/stats', array(
193 'methods' => 'GET',
194 'callback' => array($this, 'getStats'),
195 'permission_callback' => array($this, 'permissionCheck'),
196 ));
197
198 register_rest_route(self::NAMESPACE, '/logs', array(
199 'methods' => 'GET',
200 'callback' => array($this, 'getLogs'),
201 'permission_callback' => array($this, 'permissionCheck'),
202 'args' => array(
203 'page' => array('type' => 'integer', 'default' => 1, 'minimum' => 1),
204 'per_page' => array('type' => 'integer', 'default' => 20, 'minimum' => 1, 'maximum' => 100),
205 ),
206 ));
207
208 register_rest_route(self::NAMESPACE, '/test', array(
209 'methods' => 'POST',
210 'callback' => array($this, 'testRedirect'),
211 'permission_callback' => array($this, 'permissionCheck'),
212 'args' => array(
213 'url' => array('type' => 'string', 'required' => true),
214 ),
215 ));
216 }
217
218 /**
219 * @param \WP_REST_Request $request
220 * @return bool
221 */
222 public function permissionCheck($request) {
223 return ABJ_404_Solution_PluginAdminAccessPolicy::currentUserCanAccessPluginAdmin();
224 }
225
226 /**
227 * @param \WP_REST_Request $request
228 * @return \WP_REST_Response|\WP_Error
229 */
230 public function getRedirects($request) {
231 $input = $this->requestParser->redirectsList($request);
232 if ($input instanceof \WP_Error) {
233 return $input;
234 }
235
236 return $this->readService->redirects($input);
237 }
238
239 /**
240 * @param \WP_REST_Request $request
241 * @return \WP_REST_Response|\WP_Error
242 */
243 public function createRedirect($request) {
244 $input = $this->requestParser->createRedirect($request);
245 if ($input instanceof \WP_Error) {
246 return $input;
247 }
248
249 return $this->mutationService->create($input);
250 }
251
252 /**
253 * @param \WP_REST_Request $request
254 * @return \WP_REST_Response|\WP_Error
255 */
256 public function updateRedirect($request) {
257 $input = $this->requestParser->updateRedirect($request);
258 if ($input instanceof \WP_Error) {
259 return $input;
260 }
261
262 return $this->mutationService->update($input);
263 }
264
265 /**
266 * @param \WP_REST_Request $request
267 * @return \WP_REST_Response|\WP_Error
268 */
269 public function deleteRedirect($request) {
270 $input = $this->requestParser->redirectId($request);
271 if ($input instanceof \WP_Error) {
272 return $input;
273 }
274
275 return $this->mutationService->trash($input);
276 }
277
278 /**
279 * @param \WP_REST_Request $request
280 * @return \WP_REST_Response
281 */
282 public function getCaptured($request) {
283 return $this->readService->captured($this->requestParser->pagination($request));
284 }
285
286 /**
287 * @param \WP_REST_Request $request
288 * @return \WP_REST_Response|\WP_Error
289 */
290 public function createRedirectFromCaptured($request) {
291 $input = $this->requestParser->capturedRedirect($request);
292 if ($input instanceof \WP_Error) {
293 return $input;
294 }
295
296 return $this->mutationService->promoteCaptured($input);
297 }
298
299 /**
300 * @param \WP_REST_Request $request
301 * @return \WP_REST_Response|\WP_Error
302 */
303 public function getStats($request) {
304 return $this->readService->stats();
305 }
306
307 /**
308 * @param \WP_REST_Request $request
309 * @return \WP_REST_Response
310 */
311 public function getLogs($request) {
312 return $this->readService->logs($this->requestParser->pagination($request));
313 }
314
315 /**
316 * @param \WP_REST_Request $request
317 * @return \WP_REST_Response|\WP_Error
318 */
319 public function testRedirect($request) {
320 $input = $this->requestParser->testRedirect($request);
321 if ($input instanceof \WP_Error) {
322 return $input;
323 }
324
325 return $this->readService->testRedirect($input);
326 }
327
328 }
329