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