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 / RestApiReadService.php

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

178 lines 6.2 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 * Reads and shapes REST API list/stat/test data without owning route wiring.
9 */
10 final class ABJ_404_Solution_RestApiReadService {
11
12 /** @var ABJ_404_Solution_ViewReadServiceInterface */
13 private $viewRead;
14 /** @var ABJ_404_Solution_RedirectsRepositoryInterface */
15 private $redirectsRepo;
16 /** @var ABJ_404_Solution_LogsRepositoryInterface */
17 private $logsRepo;
18 /** @var ABJ_404_Solution_StatsRepositoryInterface */
19 private $statsRepo;
20 /** @var ABJ_404_Solution_DatabaseQueryInterface */
21 private $dbCore;
22 /** @var ABJ_404_Solution_PluginLogic */
23 private $logic;
24 /** @var ABJ_404_Solution_RestApiResponsePresenter */
25 private $presenter;
26
27 /**
28 * @param ABJ_404_Solution_ViewReadServiceInterface $viewRead
29 * @param ABJ_404_Solution_RedirectsRepositoryInterface $redirectsRepo
30 * @param ABJ_404_Solution_LogsRepositoryInterface $logsRepo
31 * @param ABJ_404_Solution_DatabaseQueryInterface $dbCore
32 * @param ABJ_404_Solution_PluginLogic $logic
33 */
34 public function __construct(
35 $viewRead,
36 $redirectsRepo,
37 $logsRepo,
38 ABJ_404_Solution_StatsRepositoryInterface $statsRepo,
39 $dbCore,
40 $logic,
41 ABJ_404_Solution_RestApiResponsePresenter $presenter
42 ) {
43 $this->viewRead = $viewRead;
44 $this->redirectsRepo = $redirectsRepo;
45 $this->logsRepo = $logsRepo;
46 $this->statsRepo = $statsRepo;
47 $this->dbCore = $dbCore;
48 $this->logic = $logic;
49 $this->presenter = $presenter;
50 }
51
52 /**
53 * @param array{page: int, per_page: int, status_filter: string, filter_text: string} $input
54 * @return \WP_REST_Response
55 */
56 public function redirects(array $input): \WP_REST_Response {
57 $tableOptions = array(
58 'orderby' => 'url',
59 'order' => 'ASC',
60 'paged' => $input['page'],
61 'perpage' => $input['per_page'],
62 'filter' => $input['status_filter'],
63 'logsid' => 0,
64 'sub' => 'abj404_redirects',
65 );
66
67 $rows = $this->viewRead->getRedirectsForView('abj404_redirects', $tableOptions);
68 $total = $this->viewRead->getRedirectsForViewCount('abj404_redirects', $tableOptions);
69
70 return $this->presenter->paginated(is_array($rows) ? $rows : array(), intval($total), $input['page'], $input['per_page']);
71 }
72
73 /**
74 * @param array{page: int, per_page: int} $input
75 * @return \WP_REST_Response
76 */
77 public function captured(array $input): \WP_REST_Response {
78 $types = array(ABJ404_STATUS_CAPTURED, ABJ404_STATUS_IGNORED, ABJ404_STATUS_LATER);
79 $total = $this->viewRead->getRecordCount($types, 0);
80
81 $redirectsTable = $this->dbCore->doTableNameReplacements('{wp_abj404_redirects}');
82 $statusIn = implode(', ', array_map('absint', $types));
83 $limitStart = ($input['page'] - 1) * $input['per_page'];
84
85 $queryResult = $this->dbCore->queryAndGetResults(
86 "SELECT id, url, status, type, final_dest, code, timestamp, disabled
87 FROM `{$redirectsTable}`
88 WHERE status IN ({$statusIn}) AND disabled = 0
89 ORDER BY url ASC
90 LIMIT %d, %d",
91 ['query_params' => [$limitStart, $input['per_page']]]
92 );
93 $rows = is_array($queryResult['rows'] ?? null) ? $queryResult['rows'] : array();
94
95 return $this->presenter->paginated($rows, intval($total), $input['page'], $input['per_page']);
96 }
97
98 /**
99 * @return \WP_REST_Response|\WP_Error
100 */
101 public function stats() {
102 try {
103 $snapshot = $this->statsRepo->getStatsDashboardSnapshot(true);
104 $data = is_array($snapshot['data']) ? $snapshot['data'] : array();
105 return $this->presenter->stats($data);
106 } catch (\Throwable $e) {
107 return $this->presenter->statsError($e);
108 }
109 }
110
111 /**
112 * @param array{page: int, per_page: int} $input
113 * @return \WP_REST_Response
114 */
115 public function logs(array $input): \WP_REST_Response {
116 $tableOptions = array(
117 'orderby' => 'timestamp',
118 'order' => 'DESC',
119 'paged' => $input['page'],
120 'perpage' => $input['per_page'],
121 'logsid' => 0,
122 'filter' => '',
123 );
124
125 $rows = $this->logsRepo->getLogRecords($tableOptions);
126 $total = $this->viewRead->getLogsCount(0);
127
128 return $this->presenter->paginated(is_array($rows) ? $rows : array(), intval($total), $input['page'], $input['per_page']);
129 }
130
131 /**
132 * @param array{url: string} $input
133 * @return \WP_REST_Response
134 */
135 public function testRedirect(array $input): \WP_REST_Response {
136 $normalizedUrl = $this->logic->urlNormalization()->normalizeToRelativePath($input['url']);
137 if (!is_string($normalizedUrl) || $normalizedUrl === '') {
138 $normalizedUrl = $input['url'];
139 }
140
141 $redirect = $this->redirectsRepo->getExistingRedirectForURL($normalizedUrl);
142
143 if (!is_array($redirect) || empty($redirect) || !isset($redirect['id']) || !is_scalar($redirect['id']) || intval($redirect['id']) === 0) {
144 $matchedRegex = $this->findMatchedRegexRedirect($normalizedUrl);
145 if ($matchedRegex !== null) {
146 return $this->presenter->testRegexMatch($normalizedUrl, $matchedRegex);
147 }
148
149 return $this->presenter->testNoMatch($normalizedUrl);
150 }
151
152 return $this->presenter->testStoredMatch($normalizedUrl, $redirect);
153 }
154
155 /**
156 * @return array<string, mixed>|null
157 */
158 private function findMatchedRegexRedirect(string $normalizedUrl) {
159 $regexRedirects = $this->viewRead->getRedirectsWithRegEx();
160 if (!is_iterable($regexRedirects)) {
161 return null;
162 }
163
164 foreach ($regexRedirects as $rr) {
165 if (!is_array($rr) || empty($rr['url'])) {
166 continue;
167 }
168 $pattern = is_string($rr['url']) ? $rr['url'] : '';
169 $delimited = '{' . $pattern . '}';
170 if ($pattern !== '' && @preg_match($delimited, $normalizedUrl) === 1) {
171 return $rr;
172 }
173 }
174
175 return null;
176 }
177 }
178