PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 2.4.7
Booking for Appointments and Events Calendar – Amelia v2.4.7
2.4.9 2.4.8 2.4.7 2.4.6 2.4.5 2.4.4 2.4.3 2.4.2 2.4.1 2.4 trunk 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.15 1.2.16 1.2.17 1.2.18 1.2.19 1.2.2 1.2.20 1.2.21 1.2.22 1.2.23 1.2.24 1.2.25 1.2.26 1.2.27 1.2.28 1.2.29 1.2.3 1.2.30 1.2.31 1.2.32 1.2.33 1.2.34 1.2.35 1.2.36 1.2.37 1.2.38 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 2.0 2.0.1 2.0.2 2.1 2.1.1 2.1.2 2.1.3 2.2 2.2.1 2.3
ameliabooking / src / Application / Controller / Controller.php
ameliabooking / src / Application / Controller Last commit date
Bookable 2 months ago Booking 1 month ago Calendar 2 months ago Entities 2 months ago Google 2 months ago Import 2 months ago Mobile 2 months ago Notification 2 months ago Payment 2 months ago QrCode 2 months ago Settings 1 month ago Square 2 months ago Stash 2 months ago Stats 2 months ago Test 2 months ago User 2 months ago WhatsNew 2 months ago Controller.php 2 weeks ago
Controller.php
397 lines
1 <?php
2
3 namespace AmeliaBooking\Application\Controller;
4
5 use AmeliaBooking\Application\Commands\Command;
6 use AmeliaBooking\Application\Services\User\UserApplicationService;
7 use AmeliaBooking\Domain\Services\DateTime\DateTimeService;
8 use AmeliaBooking\Domain\Services\Permissions\PermissionsService;
9 use AmeliaBooking\Domain\Services\Settings\SettingsService;
10 use AmeliaBooking\Domain\Common\Exceptions\AuthorizationException;
11 use AmeliaBooking\Infrastructure\Common\Container;
12 use AmeliaBooking\Domain\Events\DomainEventBus;
13 use AmeliaBooking\Application\Commands\CommandResult;
14 use AmeliaBooking\Infrastructure\WP\SettingsService\SettingsStorage;
15 use AmeliaBooking\Domain\Common\Exceptions\CustomException;
16 use League\Tactician\CommandBus;
17 use AmeliaVendor\Psr\Http\Message\ServerRequestInterface as Request;
18 use AmeliaVendor\Psr\Http\Message\ResponseInterface as Response;
19
20 /**
21 * Class Controller
22 *
23 * @package AmeliaBooking\Application\Controller
24 */
25 abstract class Controller
26 {
27 public const STATUS_OK = 200;
28 public const STATUS_REDIRECT = 302;
29 public const STATUS_FORBIDDEN = 403;
30 public const STATUS_NOT_FOUNT = 404;
31 public const STATUS_CONFLICT = 409;
32 public const STATUS_INTERNAL_SERVER_ERROR = 500;
33
34 /**
35 * @var CommandBus
36 */
37 protected $commandBus;
38 /**
39 * @var DomainEventBus
40 */
41 protected $eventBus;
42
43 /**
44 * @var PermissionsService
45 */
46 protected $permissionsService;
47 protected $allowedFields = [
48 'ameliaNonce',
49 'wpAmeliaNonce',
50 ];
51
52 protected $sendJustData = false;
53 /**
54 * @var UserApplicationService
55 */
56 private $userApplicationService;
57
58 /**
59 * Base Controller constructor.
60 *
61 * @param Container $container
62 * @param bool $fromApi
63 */
64 public function __construct(Container $container, $fromApi = false)
65 {
66 $this->commandBus = $container->getCommandBus();
67 $this->eventBus = $container->getEventBus();
68 $this->permissionsService = $fromApi ? $container->getApiPermissionsService() : $container->getPermissionsService();
69 $this->userApplicationService = $fromApi ? $container->getApiUserApplicationService() : $container->getUserApplicationService();
70 }
71
72 /**
73 * @param Request $request
74 * @param $args
75 *
76 * @return mixed
77 */
78 abstract protected function instantiateCommand(Request $request, $args);
79
80 /**
81 * Emit a success domain event, do nothing by default
82 *
83 * @param DomainEventBus $eventBus
84 *
85 * @param CommandResult $result
86 *
87 * @return void
88 */
89 protected function emitSuccessEvent(DomainEventBus $eventBus, CommandResult $result)
90 {
91 }
92
93 /**
94 * Emit a failure domain event, do nothing by default
95 *
96 * @param DomainEventBus $eventBus
97 *
98 * @param CommandResult $data
99 *
100 * @return null
101 */
102 protected function emitFailureEvent(DomainEventBus $eventBus, CommandResult $data)
103 {
104 return null;
105 }
106
107 /**
108 * @param Request $request
109 * @param Response $response
110 * @param $args
111 *
112 * @return Response
113 * @throws \InvalidArgumentException
114 * @throws \RuntimeException
115 */
116 public function __invoke(Request $request, Response $response, $args, $validApiCall = false)
117 {
118 /** @var Command $command */
119 $command = $this->instantiateCommand($request, $args);
120
121 /** @var SettingsService $settingsService */
122 $settingsService = new SettingsService(new SettingsStorage());
123
124 if (!$validApiCall && !$command->validateNonce($request)) {
125 return $response->withStatus(self::STATUS_FORBIDDEN);
126 }
127
128 if (!$validApiCall && !$command->validateCron($request)) {
129 return $response->withStatus(self::STATUS_FORBIDDEN);
130 }
131
132 $command->setPermissionService($this->permissionsService);
133 $command->setUserApplicationService($this->userApplicationService);
134
135 try {
136 /** @var CommandResult $commandResult */
137 $commandResult = $this->commandBus->handle($command);
138 } catch (CustomException $e) {
139 $response = $response->withHeader('Content-Type', 'application/json;charset=utf-8');
140 $response = $response->withStatus(self::STATUS_INTERNAL_SERVER_ERROR);
141
142 $response->getBody()->write(
143 json_encode(
144 [
145 'data' => [
146 'message' => $e->getMessage()
147 ]
148 ]
149 )
150 );
151
152 return $response;
153 } catch (AuthorizationException $e) {
154 $commandResult = new CommandResult();
155
156 $commandResult->setResult(CommandResult::RESULT_ERROR);
157 $commandResult->setData(
158 [
159 'reauthorize' => true,
160 ]
161 );
162 }
163
164 if ($commandResult->getResult() === CommandResult::RESULT_ERROR) {
165 if ($settingsService->getSetting('activation', 'responseErrorAsConflict')) {
166 $commandResult->setResult(CommandResult::RESULT_CONFLICT);
167 }
168 }
169
170 if ($commandResult->getUrl() !== null) {
171 $this->emitSuccessEvent($this->eventBus, $commandResult);
172
173 /** @var Response $response */
174 $response = $response->withHeader('Location', $commandResult->getUrl());
175 $response = $response->withStatus(self::STATUS_REDIRECT);
176
177 return $response;
178 }
179
180 if ($commandResult->hasAttachment() === false && $commandResult->getHtml() === null) {
181 $responseBody = [
182 'message' => $commandResult->getMessage(),
183 'data' => $commandResult->getData()
184 ];
185
186 $this->emitSuccessEvent($this->eventBus, $commandResult);
187
188 switch ($commandResult->getResult()) {
189 case (CommandResult::RESULT_SUCCESS):
190 $response = $response->withStatus(self::STATUS_OK);
191
192 break;
193 case (CommandResult::RESULT_CONFLICT):
194 $response = $response->withStatus(self::STATUS_CONFLICT);
195
196 break;
197 default:
198 $response = $response->withStatus(self::STATUS_INTERNAL_SERVER_ERROR);
199
200 break;
201 }
202
203 /** @var Response $response */
204 $response = $response->withHeader('Content-Type', 'application/json;charset=utf-8');
205
206 $response->getBody()->write(
207 $this->sendJustData ? $commandResult->getData() :
208 json_encode(
209 $commandResult->hasDataInResponse() ?
210 $responseBody : array_merge($responseBody, ['data' => []])
211 )
212 );
213 }
214
215 if (($html = $commandResult->getHtml()) !== null) {
216 /** @var Response $response */
217 $this->emitSuccessEvent($this->eventBus, $commandResult);
218
219 switch ($commandResult->getResult()) {
220 case (CommandResult::RESULT_SUCCESS):
221 $response = $response->withStatus(self::STATUS_OK);
222
223 break;
224 case (CommandResult::RESULT_CONFLICT):
225 $response = $response->withStatus(self::STATUS_CONFLICT);
226
227 break;
228 default:
229 $response = $response->withStatus(self::STATUS_INTERNAL_SERVER_ERROR);
230
231 break;
232 }
233
234 $response = $response->withHeader('Content-Type', 'text/html; charset=utf-8');
235 $response = $response->withHeader('Cache-Control', 'max-age=0');
236
237 $response->getBody()->write($html);
238 }
239
240 if (($file = $commandResult->getFile()) !== null) {
241 /** @var Response $response */
242 $response = $response->withHeader('Content-Type', $file['type']);
243 $response = $response->withHeader('Content-Disposition', 'inline; filename=' . '"' . $file['name'] . '"');
244 $response = $response->withHeader('Cache-Control', 'max-age=0');
245
246 if (array_key_exists('size', $file)) {
247 $response = $response->withHeader('Content-Length', $file['size']);
248 }
249
250 $response->getBody()->write($file['content']);
251 }
252
253 return $response;
254 }
255
256 /**
257 * @param Command $command
258 * @param $requestBody
259 */
260 protected function setCommandFields($command, $requestBody)
261 {
262 foreach ($this->allowedFields as $field) {
263 if (!isset($requestBody[$field])) {
264 continue;
265 }
266 $command->setField($field, $requestBody[$field]);
267 }
268 }
269
270 /**
271 * @param mixed $params
272 * @param array $keys
273 */
274 protected function setArrayParams(&$params, $keys = [])
275 {
276 $names = array_merge([
277 'customers',
278 'categories',
279 'services',
280 'packages',
281 'employees',
282 'providers',
283 'providerIds',
284 'locations',
285 'locationIds',
286 'ids',
287 'events',
288 'tag',
289 'dates',
290 'types',
291 'fields',
292 'statuses',
293 'stats',
294 'bookingTypes',
295 ], $keys);
296
297 foreach ($names as $name) {
298 if (!empty($params[$name])) {
299 $params[$name] = is_array($params[$name]) ? $params[$name] : explode(',', $params[$name]);
300 }
301 }
302
303 if (isset($params['dates'][0])) {
304 $params['dates'][0] = preg_match("/^\d{4}-\d{2}-\d{2}$/", $params['dates'][0]) ?
305 $params['dates'][0] : DateTimeService::getNowDate();
306 }
307
308 if (isset($params['dates'][1]) && $params['dates'][1]) {
309 $params['dates'][1] = preg_match("/^\d{4}-\d{2}-\d{2}$/", $params['dates'][1]) ?
310 $params['dates'][1] : DateTimeService::getNowDate();
311 }
312
313 if (isset($params['date'])) {
314 $params['date'] = preg_match("/^\d{4}-\d{2}-\d{2}$/", $params['date']) ?
315 $params['date'] : DateTimeService::getNowDate();
316 }
317 }
318
319 /**
320 * @param array $data
321 * @param string $field
322 * @param string $translationField
323 *
324 * @return void
325 */
326 private function filterField(&$data, $field, $translationField)
327 {
328 if (!empty($data[$field])) {
329 global $allowedposttags;
330
331 $data[$field] = wp_kses($data[$field], $allowedposttags);
332
333 if (!empty($data['translations']) && ($translations = json_decode($data['translations'], true)) !== null) {
334 if (!empty($translations[$translationField])) {
335 foreach ($translations[$translationField] as $lang => $translation) {
336 $translations[$translationField][$lang] = wp_kses(
337 $translations[$translationField][$lang],
338 $allowedposttags
339 );
340 }
341
342 $data['translations'] = json_encode($translations);
343 }
344 }
345 }
346 }
347
348 /**
349 * @param array $requestBody
350 *
351 * @return void
352 */
353 protected function filter(&$requestBody)
354 {
355 if (!current_user_can('unfiltered_html') && $requestBody) {
356 $this->filterField($requestBody, 'description', 'description');
357 $this->filterField($requestBody, 'label', 'name');
358
359 foreach (!empty($requestBody['extras']) ? $requestBody['extras'] : [] as $index => $extra) {
360 $this->filterField($requestBody['extras'][$index], 'description', 'description');
361 }
362 }
363 }
364
365 /**
366 * Helper to set HTML content on CommandResult as an inline file
367 * so the controller can respond with a text/html body.
368 *
369 * @param CommandResult $result
370 * @param string $html
371 * @param string $filename
372 *
373 * @return void
374 */
375 protected function setResultHtml(CommandResult $result, $html, $filename = 'content.html')
376 {
377 $result->setFile([
378 'type' => 'text/html; charset=utf-8',
379 'name' => $filename,
380 'size' => strlen($html),
381 'content' => $html,
382 ]);
383 }
384
385 /**
386 * @param mixed $default
387 *
388 * @return mixed
389 */
390 public static function getParam(Request $request, string $key, $default = null)
391 {
392 $params = $request->getQueryParams();
393
394 return array_key_exists($key, $params) ? $params[$key] : $default;
395 }
396 }
397