PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 2.4
Booking for Appointments and Events Calendar – Amelia v2.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 6 months ago Booking 2 months ago Calendar 2 months ago Entities 4 years ago Google 3 months ago Import 4 years ago Notification 4 months ago Payment 2 months ago QrCode 7 months ago Settings 6 months ago Square 6 months ago Stash 4 years ago Stats 6 months ago Test 2 years ago User 2 months ago WhatsNew 6 months ago Controller.php 4 months ago
Controller.php
369 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 Slim\Http\Request;
17 use Slim\Http\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 = $response->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 $response = $response->write(
192 $this->sendJustData ? $commandResult->getData() :
193 json_encode(
194 $commandResult->hasDataInResponse() ?
195 $responseBody : array_merge($responseBody, ['data' => []])
196 )
197 );
198 }
199
200 if (($html = $commandResult->getHtml()) !== null) {
201 /** @var Response $response */
202 $this->emitSuccessEvent($this->eventBus, $commandResult);
203
204 switch ($commandResult->getResult()) {
205 case (CommandResult::RESULT_SUCCESS):
206 $response = $response->withStatus(self::STATUS_OK);
207
208 break;
209 case (CommandResult::RESULT_CONFLICT):
210 $response = $response->withStatus(self::STATUS_CONFLICT);
211
212 break;
213 default:
214 $response = $response->withStatus(self::STATUS_INTERNAL_SERVER_ERROR);
215
216 break;
217 }
218
219 $response = $response->withHeader('Content-Type', 'text/html; charset=utf-8');
220 $response = $response->withHeader('Cache-Control', 'max-age=0');
221 $response = $response->write($html);
222 }
223
224 if (($file = $commandResult->getFile()) !== null) {
225 /** @var Response $response */
226 $response = $response->withHeader('Content-Type', $file['type']);
227 $response = $response->withHeader('Content-Disposition', 'inline; filename=' . '"' . $file['name'] . '"');
228 $response = $response->withHeader('Cache-Control', 'max-age=0');
229
230 if (array_key_exists('size', $file)) {
231 $response = $response->withHeader('Content-Length', $file['size']);
232 }
233
234 $response = $response->write($file['content']);
235 }
236
237 return $response;
238 }
239
240 /**
241 * @param Command $command
242 * @param $requestBody
243 */
244 protected function setCommandFields($command, $requestBody)
245 {
246 foreach ($this->allowedFields as $field) {
247 if (!isset($requestBody[$field])) {
248 continue;
249 }
250 $command->setField($field, $requestBody[$field]);
251 }
252 }
253
254 /**
255 * @param mixed $params
256 * @param array $keys
257 */
258 protected function setArrayParams(&$params, $keys = [])
259 {
260 $names = array_merge([
261 'customers',
262 'categories',
263 'services',
264 'packages',
265 'employees',
266 'providers',
267 'providerIds',
268 'locations',
269 'locationIds',
270 'ids',
271 'events',
272 'tag',
273 'dates',
274 'types',
275 'fields',
276 'statuses',
277 'stats',
278 'bookingTypes',
279 ], $keys);
280
281 foreach ($names as $name) {
282 if (!empty($params[$name])) {
283 $params[$name] = is_array($params[$name]) ? $params[$name] : explode(',', $params[$name]);
284 }
285 }
286
287 if (isset($params['dates'][0])) {
288 $params['dates'][0] = preg_match("/^\d{4}-\d{2}-\d{2}$/", $params['dates'][0]) ?
289 $params['dates'][0] : DateTimeService::getNowDate();
290 }
291
292 if (isset($params['dates'][1]) && $params['dates'][1]) {
293 $params['dates'][1] = preg_match("/^\d{4}-\d{2}-\d{2}$/", $params['dates'][1]) ?
294 $params['dates'][1] : DateTimeService::getNowDate();
295 }
296
297 if (isset($params['date'])) {
298 $params['date'] = preg_match("/^\d{4}-\d{2}-\d{2}$/", $params['date']) ?
299 $params['date'] : DateTimeService::getNowDate();
300 }
301 }
302
303 /**
304 * @param array $data
305 * @param string $field
306 * @param string $translationField
307 *
308 * @return void
309 */
310 private function filterField(&$data, $field, $translationField)
311 {
312 if (!empty($data[$field])) {
313 global $allowedposttags;
314
315 $data[$field] = wp_kses($data[$field], $allowedposttags);
316
317 if (!empty($data['translations']) && ($translations = json_decode($data['translations'], true)) !== null) {
318 if (!empty($translations[$translationField])) {
319 foreach ($translations[$translationField] as $lang => $translation) {
320 $translations[$translationField][$lang] = wp_kses(
321 $translations[$translationField][$lang],
322 $allowedposttags
323 );
324 }
325
326 $data['translations'] = json_encode($translations);
327 }
328 }
329 }
330 }
331
332 /**
333 * @param array $requestBody
334 *
335 * @return void
336 */
337 protected function filter(&$requestBody)
338 {
339 if (!current_user_can('unfiltered_html') && $requestBody) {
340 $this->filterField($requestBody, 'description', 'description');
341 $this->filterField($requestBody, 'label', 'name');
342
343 foreach (!empty($requestBody['extras']) ? $requestBody['extras'] : [] as $index => $extra) {
344 $this->filterField($requestBody['extras'][$index], 'description', 'description');
345 }
346 }
347 }
348
349 /**
350 * Helper to set HTML content on CommandResult as an inline file
351 * so the controller can respond with a text/html body.
352 *
353 * @param CommandResult $result
354 * @param string $html
355 * @param string $filename
356 *
357 * @return void
358 */
359 protected function setResultHtml(CommandResult $result, $html, $filename = 'content.html')
360 {
361 $result->setFile([
362 'type' => 'text/html; charset=utf-8',
363 'name' => $filename,
364 'size' => strlen($html),
365 'content' => $html,
366 ]);
367 }
368 }
369