PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 2.4.6
Booking for Appointments and Events Calendar – Amelia v2.4.6
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 4 weeks 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 4 weeks 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 1 week ago
Controller.php
393 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 $command->setPermissionService($this->permissionsService);
129 $command->setUserApplicationService($this->userApplicationService);
130
131 try {
132 /** @var CommandResult $commandResult */
133 $commandResult = $this->commandBus->handle($command);
134 } catch (CustomException $e) {
135 $response = $response->withHeader('Content-Type', 'application/json;charset=utf-8');
136 $response = $response->withStatus(self::STATUS_INTERNAL_SERVER_ERROR);
137
138 $response->getBody()->write(
139 json_encode(
140 [
141 'data' => [
142 'message' => $e->getMessage()
143 ]
144 ]
145 )
146 );
147
148 return $response;
149 } catch (AuthorizationException $e) {
150 $commandResult = new CommandResult();
151
152 $commandResult->setResult(CommandResult::RESULT_ERROR);
153 $commandResult->setData(
154 [
155 'reauthorize' => true,
156 ]
157 );
158 }
159
160 if ($commandResult->getResult() === CommandResult::RESULT_ERROR) {
161 if ($settingsService->getSetting('activation', 'responseErrorAsConflict')) {
162 $commandResult->setResult(CommandResult::RESULT_CONFLICT);
163 }
164 }
165
166 if ($commandResult->getUrl() !== null) {
167 $this->emitSuccessEvent($this->eventBus, $commandResult);
168
169 /** @var Response $response */
170 $response = $response->withHeader('Location', $commandResult->getUrl());
171 $response = $response->withStatus(self::STATUS_REDIRECT);
172
173 return $response;
174 }
175
176 if ($commandResult->hasAttachment() === false && $commandResult->getHtml() === null) {
177 $responseBody = [
178 'message' => $commandResult->getMessage(),
179 'data' => $commandResult->getData()
180 ];
181
182 $this->emitSuccessEvent($this->eventBus, $commandResult);
183
184 switch ($commandResult->getResult()) {
185 case (CommandResult::RESULT_SUCCESS):
186 $response = $response->withStatus(self::STATUS_OK);
187
188 break;
189 case (CommandResult::RESULT_CONFLICT):
190 $response = $response->withStatus(self::STATUS_CONFLICT);
191
192 break;
193 default:
194 $response = $response->withStatus(self::STATUS_INTERNAL_SERVER_ERROR);
195
196 break;
197 }
198
199 /** @var Response $response */
200 $response = $response->withHeader('Content-Type', 'application/json;charset=utf-8');
201
202 $response->getBody()->write(
203 $this->sendJustData ? $commandResult->getData() :
204 json_encode(
205 $commandResult->hasDataInResponse() ?
206 $responseBody : array_merge($responseBody, ['data' => []])
207 )
208 );
209 }
210
211 if (($html = $commandResult->getHtml()) !== null) {
212 /** @var Response $response */
213 $this->emitSuccessEvent($this->eventBus, $commandResult);
214
215 switch ($commandResult->getResult()) {
216 case (CommandResult::RESULT_SUCCESS):
217 $response = $response->withStatus(self::STATUS_OK);
218
219 break;
220 case (CommandResult::RESULT_CONFLICT):
221 $response = $response->withStatus(self::STATUS_CONFLICT);
222
223 break;
224 default:
225 $response = $response->withStatus(self::STATUS_INTERNAL_SERVER_ERROR);
226
227 break;
228 }
229
230 $response = $response->withHeader('Content-Type', 'text/html; charset=utf-8');
231 $response = $response->withHeader('Cache-Control', 'max-age=0');
232
233 $response->getBody()->write($html);
234 }
235
236 if (($file = $commandResult->getFile()) !== null) {
237 /** @var Response $response */
238 $response = $response->withHeader('Content-Type', $file['type']);
239 $response = $response->withHeader('Content-Disposition', 'inline; filename=' . '"' . $file['name'] . '"');
240 $response = $response->withHeader('Cache-Control', 'max-age=0');
241
242 if (array_key_exists('size', $file)) {
243 $response = $response->withHeader('Content-Length', $file['size']);
244 }
245
246 $response->getBody()->write($file['content']);
247 }
248
249 return $response;
250 }
251
252 /**
253 * @param Command $command
254 * @param $requestBody
255 */
256 protected function setCommandFields($command, $requestBody)
257 {
258 foreach ($this->allowedFields as $field) {
259 if (!isset($requestBody[$field])) {
260 continue;
261 }
262 $command->setField($field, $requestBody[$field]);
263 }
264 }
265
266 /**
267 * @param mixed $params
268 * @param array $keys
269 */
270 protected function setArrayParams(&$params, $keys = [])
271 {
272 $names = array_merge([
273 'customers',
274 'categories',
275 'services',
276 'packages',
277 'employees',
278 'providers',
279 'providerIds',
280 'locations',
281 'locationIds',
282 'ids',
283 'events',
284 'tag',
285 'dates',
286 'types',
287 'fields',
288 'statuses',
289 'stats',
290 'bookingTypes',
291 ], $keys);
292
293 foreach ($names as $name) {
294 if (!empty($params[$name])) {
295 $params[$name] = is_array($params[$name]) ? $params[$name] : explode(',', $params[$name]);
296 }
297 }
298
299 if (isset($params['dates'][0])) {
300 $params['dates'][0] = preg_match("/^\d{4}-\d{2}-\d{2}$/", $params['dates'][0]) ?
301 $params['dates'][0] : DateTimeService::getNowDate();
302 }
303
304 if (isset($params['dates'][1]) && $params['dates'][1]) {
305 $params['dates'][1] = preg_match("/^\d{4}-\d{2}-\d{2}$/", $params['dates'][1]) ?
306 $params['dates'][1] : DateTimeService::getNowDate();
307 }
308
309 if (isset($params['date'])) {
310 $params['date'] = preg_match("/^\d{4}-\d{2}-\d{2}$/", $params['date']) ?
311 $params['date'] : DateTimeService::getNowDate();
312 }
313 }
314
315 /**
316 * @param array $data
317 * @param string $field
318 * @param string $translationField
319 *
320 * @return void
321 */
322 private function filterField(&$data, $field, $translationField)
323 {
324 if (!empty($data[$field])) {
325 global $allowedposttags;
326
327 $data[$field] = wp_kses($data[$field], $allowedposttags);
328
329 if (!empty($data['translations']) && ($translations = json_decode($data['translations'], true)) !== null) {
330 if (!empty($translations[$translationField])) {
331 foreach ($translations[$translationField] as $lang => $translation) {
332 $translations[$translationField][$lang] = wp_kses(
333 $translations[$translationField][$lang],
334 $allowedposttags
335 );
336 }
337
338 $data['translations'] = json_encode($translations);
339 }
340 }
341 }
342 }
343
344 /**
345 * @param array $requestBody
346 *
347 * @return void
348 */
349 protected function filter(&$requestBody)
350 {
351 if (!current_user_can('unfiltered_html') && $requestBody) {
352 $this->filterField($requestBody, 'description', 'description');
353 $this->filterField($requestBody, 'label', 'name');
354
355 foreach (!empty($requestBody['extras']) ? $requestBody['extras'] : [] as $index => $extra) {
356 $this->filterField($requestBody['extras'][$index], 'description', 'description');
357 }
358 }
359 }
360
361 /**
362 * Helper to set HTML content on CommandResult as an inline file
363 * so the controller can respond with a text/html body.
364 *
365 * @param CommandResult $result
366 * @param string $html
367 * @param string $filename
368 *
369 * @return void
370 */
371 protected function setResultHtml(CommandResult $result, $html, $filename = 'content.html')
372 {
373 $result->setFile([
374 'type' => 'text/html; charset=utf-8',
375 'name' => $filename,
376 'size' => strlen($html),
377 'content' => $html,
378 ]);
379 }
380
381 /**
382 * @param mixed $default
383 *
384 * @return mixed
385 */
386 public static function getParam(Request $request, string $key, $default = null)
387 {
388 $params = $request->getQueryParams();
389
390 return array_key_exists($key, $params) ? $params[$key] : $default;
391 }
392 }
393