PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 1.2.20
Booking for Appointments and Events Calendar – Amelia v1.2.20
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 / Infrastructure / Repository / Bookable / Service / ServiceRepository.php
ameliabooking / src / Infrastructure / Repository / Bookable / Service Last commit date
CategoryRepository.php 2 years ago ExtraRepository.php 5 years ago PackageCustomerRepository.php 1 year ago PackageCustomerServiceRepository.php 1 year ago PackageRepository.php 2 years ago PackageServiceLocationRepository.php 5 years ago PackageServiceProviderRepository.php 5 years ago PackageServiceRepository.php 2 years ago ProviderServiceRepository.php 1 year ago ResourceEntitiesRepository.php 2 years ago ResourceRepository.php 2 years ago ServiceRepository.php 2 years ago
ServiceRepository.php
1027 lines
1 <?php
2 /**
3 * @copyright © TMS-Plugins. All rights reserved.
4 * @licence See LICENCE.md for license details.
5 */
6
7 namespace AmeliaBooking\Infrastructure\Repository\Bookable\Service;
8
9 use AmeliaBooking\Domain\Collection\Collection;
10 use AmeliaBooking\Domain\Common\Exceptions\InvalidArgumentException;
11 use AmeliaBooking\Domain\Services\DateTime\DateTimeService;
12 use AmeliaBooking\Infrastructure\Connection;
13 use AmeliaBooking\Domain\Entity\Bookable\Service\Service;
14 use AmeliaBooking\Domain\Factory\Bookable\Service\ServiceFactory;
15 use AmeliaBooking\Infrastructure\Licence;
16 use AmeliaBooking\Infrastructure\Repository\AbstractRepository;
17 use AmeliaBooking\Domain\Repository\Bookable\Service\ServiceRepositoryInterface;
18 use AmeliaBooking\Infrastructure\Common\Exceptions\QueryExecutionException;
19 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Booking\AppointmentsTable;
20
21 /**
22 * Class ServiceRepository
23 *
24 * @package AmeliaBooking\Infrastructure\Repository\Service
25 */
26 class ServiceRepository extends AbstractRepository implements ServiceRepositoryInterface
27 {
28
29 const FACTORY = ServiceFactory::class;
30
31 /** @var string */
32 protected $providerServicesTable;
33
34 /** @var string */
35 protected $extrasTable;
36
37 /** @var string */
38 protected $serviceViewsTable;
39
40 /** @var string */
41 protected $galleriesTable;
42
43 /**
44 * @param Connection $connection
45 * @param string $table
46 * @param string $providerServicesTable
47 * @param string $extrasTable
48 * @param string $serviceViewsTable
49 * @param string $galleriesTable
50 */
51 public function __construct(
52 Connection $connection,
53 $table,
54 $providerServicesTable,
55 $extrasTable,
56 $serviceViewsTable,
57 $galleriesTable
58 ) {
59 parent::__construct($connection, $table);
60 $this->providerServicesTable = $providerServicesTable;
61 $this->extrasTable = $extrasTable;
62 $this->serviceViewsTable = $serviceViewsTable;
63 $this->galleriesTable = $galleriesTable;
64 }
65
66 /**
67 * @return Collection
68 * @throws QueryExecutionException
69 */
70 public function getAllArrayIndexedById()
71 {
72 try {
73 $statement = $this->connection->query("SELECT
74 s.id AS service_id,
75 s.name AS service_name,
76 s.description AS service_description,
77 s.color AS service_color,
78 s.price AS service_price,
79 s.customPricing AS service_customPricing,
80 s.limitPerCustomer AS service_limitPerCustomer,
81 s.status AS service_status,
82 s.categoryId AS service_categoryId,
83 s.maxCapacity AS service_maxCapacity,
84 s.maxExtraPeople AS service_maxExtraPeople,
85 s.minCapacity AS service_minCapacity,
86 s.duration AS service_duration,
87 s.timeBefore AS service_timeBefore,
88 s.timeAfter AS service_timeAfter,
89 s.bringingAnyone as service_bringingAnyone,
90 s.pictureFullPath AS service_picture_full,
91 s.pictureThumbPath AS service_picture_thumb,
92 s.position AS service_position,
93 s.show AS service_show,
94 s.aggregatedPrice AS service_aggregatedPrice,
95 s.settings AS service_settings,
96 s.recurringCycle AS service_recurringCycle,
97 s.recurringSub AS service_recurringSub,
98 s.recurringPayment AS service_recurringPayment,
99 s.translations AS service_translations,
100 s.deposit AS service_deposit,
101 s.depositPayment AS service_depositPayment,
102 s.depositPerPerson AS service_depositPerPerson,
103 s.fullPayment AS service_fullPayment,
104 s.mandatoryExtra AS service_mandatoryExtra,
105 s.minSelectedExtras AS service_minSelectedExtras,
106
107 e.id AS extra_id,
108 e.name AS extra_name,
109 e.price AS extra_price,
110 e.maxQuantity AS extra_maxQuantity,
111 e.duration AS extra_duration,
112 e.position AS extra_position,
113 e.aggregatedPrice AS extra_aggregatedPrice,
114 e.description AS extra_description,
115 e.translations AS extra_translations,
116
117 g.id AS gallery_id,
118 g.pictureFullPath AS gallery_picture_full,
119 g.pictureThumbPath AS gallery_picture_thumb,
120 g.position AS gallery_position
121 FROM {$this->table} s
122 LEFT JOIN {$this->extrasTable} e ON e.serviceId = s.id
123 LEFT JOIN {$this->galleriesTable} g ON g.entityId = s.id AND g.entityType = 'service'
124 ORDER BY s.position, s.name ASC, e.position ASC, g.position ASC");
125 $rows = $statement->fetchAll();
126 } catch (\Exception $e) {
127 throw new QueryExecutionException('Unable to get data from ' . __CLASS__, $e->getCode(), $e);
128 }
129
130 /** @var Collection $services */
131 $services = call_user_func([static::FACTORY, 'createCollection'], $rows);
132
133 /** @var Service $service */
134 foreach ($services->getItems() as $service) {
135 if ($service->getSettings() && json_decode($service->getSettings()->getValue(), true) === null) {
136 $service->setSettings(null);
137 }
138 }
139
140 return $services;
141 }
142
143 /**
144 * @param Service $entity
145 *
146 * @return bool
147 * @throws QueryExecutionException
148 */
149 public function add($entity)
150 {
151 $data = $entity->toArray();
152
153 $params = [
154 ':name' => $data['name'],
155 ':description' => $data['description'],
156 ':color' => $data['color'],
157 ':price' => $data['price'],
158 ':status' => $data['status'],
159 ':categoryId' => $data['categoryId'],
160 ':minCapacity' => $data['minCapacity'],
161 ':maxCapacity' => $data['maxCapacity'],
162 ':maxExtraPeople' => $data['maxExtraPeople'],
163 ':duration' => $data['duration'],
164 ':bringingAnyone' => $data['bringingAnyone'] ? 1 : 0,
165 ':aggregatedPrice' => $data['aggregatedPrice'] ? 1 : 0,
166 ':pictureFullPath' => $data['pictureFullPath'],
167 ':pictureThumbPath' => $data['pictureThumbPath'],
168 ':position' => $data['position'],
169 ':mandatoryExtra' => $data['mandatoryExtra'] ? 1 : 0,
170 ':minSelectedExtras'=> $data['minSelectedExtras'],
171 ];
172
173 $additionalData = Licence\DataModifier::getServiceRepositoryData($data);
174
175 $params = array_merge($params, $additionalData['values']);
176
177 try {
178 $statement = $this->connection->prepare(
179 "INSERT INTO
180 {$this->table}
181 (
182 {$additionalData['columns']}
183 `name`,
184 `description`,
185 `color`,
186 `price`,
187 `status`,
188 `categoryId`,
189 `minCapacity`,
190 `maxCapacity`,
191 `maxExtraPeople`,
192 `duration`,
193 `bringingAnyone`,
194 `aggregatedPrice`,
195 `pictureFullPath`,
196 `pictureThumbPath`,
197 `position`,
198 `mandatoryExtra`,
199 `minSelectedExtras`
200 ) VALUES (
201 {$additionalData['placeholders']}
202 :name,
203 :description,
204 :color,
205 :price,
206 :status,
207 :categoryId,
208 :minCapacity,
209 :maxCapacity,
210 :maxExtraPeople,
211 :duration,
212 :bringingAnyone,
213 :aggregatedPrice,
214 :pictureFullPath,
215 :pictureThumbPath,
216 :position,
217 :mandatoryExtra,
218 :minSelectedExtras
219 )"
220 );
221
222 $result = $statement->execute($params);
223
224 if (!$result) {
225 throw new QueryExecutionException('Unable to add data in ' . __CLASS__);
226 }
227
228 return $this->connection->lastInsertId();
229 } catch (\Exception $e) {
230 throw new QueryExecutionException('Unable to add data in ' . __CLASS__, $e->getCode(), $e);
231 }
232 }
233
234 /**
235 * @param int $id
236 * @param Service $entity
237 *
238 * @return mixed
239 * @throws QueryExecutionException
240 */
241 public function update($id, $entity)
242 {
243 $data = $entity->toArray();
244
245 $params = [
246 ':name' => $data['name'],
247 ':description' => $data['description'],
248 ':color' => $data['color'],
249 ':price' => $data['price'],
250 ':status' => $data['status'],
251 ':categoryId' => $data['categoryId'],
252 ':maxExtraPeople' => $data['maxExtraPeople'],
253 ':duration' => $data['duration'],
254 ':bringingAnyone' => $data['bringingAnyone'] ? 1 : 0,
255 ':aggregatedPrice' => $data['aggregatedPrice'] ? 1 : 0,
256 ':pictureFullPath' => $data['pictureFullPath'],
257 ':pictureThumbPath' => $data['pictureThumbPath'],
258 ':position' => $data['position'],
259 ':mandatoryExtra' => $data['mandatoryExtra'] ? 1 : 0,
260 ':minSelectedExtras'=> $data['minSelectedExtras'],
261 ':id' => $id
262 ];
263
264 $additionalData = Licence\DataModifier::getServiceRepositoryData($data);
265
266 $params = array_merge($params, $additionalData['values']);
267
268 try {
269 $statement = $this->connection->prepare(
270 "UPDATE {$this->table}
271 SET
272 {$additionalData['columnsPlaceholders']}
273 `name` = :name,
274 `description` = :description,
275 `color` = :color,
276 `price` = :price,
277 `status` = :status,
278 `categoryId` = :categoryId,
279 `maxExtraPeople` = :maxExtraPeople,
280 `duration` = :duration,
281 `bringingAnyone` = :bringingAnyone,
282 `aggregatedPrice` = :aggregatedPrice,
283 `pictureFullPath` = :pictureFullPath,
284 `pictureThumbPath` = :pictureThumbPath,
285 `position` = :position,
286 `mandatoryExtra` = :mandatoryExtra,
287 `minSelectedExtras` = :minSelectedExtras
288 WHERE
289 id = :id"
290 );
291
292 $result = $statement->execute($params);
293
294 if (!$result) {
295 throw new QueryExecutionException('Unable to save data in ' . __CLASS__);
296 }
297
298 return $result;
299 } catch (\Exception $e) {
300 throw new QueryExecutionException('Unable to save data in ' . __CLASS__, $e->getCode(), $e);
301 }
302 }
303
304 /**
305 * @param array $criteria
306 * @param int $itemsPerPage
307 *
308 * @return Collection
309 * @throws QueryExecutionException
310 * @throws InvalidArgumentException
311 */
312 public function getFiltered($criteria, $itemsPerPage = null)
313 {
314 $params = [];
315
316 $where = [];
317
318 $orderColumn = 's.position, s.id';
319
320 $orderDirection = 'ASC';
321
322 if (!empty($criteria['sort'])) {
323 switch ($criteria['sort']) {
324 case ('nameAsc'):
325 $orderColumn = 's.name';
326
327 $orderDirection = 'ASC';
328
329 break;
330
331 case ('nameDesc'):
332 $orderColumn = 's.name';
333
334 $orderDirection = 'DESC';
335
336 break;
337
338 case ('priceAsc'):
339 $orderColumn = 's.price';
340
341 $orderDirection = 'ASC';
342
343 break;
344
345 case ('priceDesc'):
346 $orderColumn = 's.price';
347
348 $orderDirection = 'DESC';
349
350 break;
351
352 case ('custom'):
353 $orderColumn = 's.position, s.id';
354
355 $orderDirection = 'ASC';
356
357 break;
358 }
359 }
360
361 if (!empty($criteria['categoryId'])) {
362 $params[':categoryId'] = $criteria['categoryId'];
363
364 $where[] = 's.categoryId = :categoryId';
365 }
366
367 $where = $where ? 'WHERE ' . implode(' AND ', $where) : '';
368
369 $order = "ORDER BY {$orderColumn} {$orderDirection}";
370
371 $limit = $this->getLimit(
372 !empty($criteria['page']) ? (int)$criteria['page'] : 0,
373 (int)$itemsPerPage
374 );
375
376 try {
377 $statement = $this->connection->prepare(
378 "SELECT s.*
379 FROM {$this->table} s
380 {$where}
381 {$order}
382 {$limit}"
383 );
384
385 $statement->execute($params);
386
387 $rows = $statement->fetchAll();
388 } catch (\Exception $e) {
389 throw new QueryExecutionException('Unable to find by ids in ' . __CLASS__, $e->getCode(), $e);
390 }
391
392 $items = new Collection();
393
394 foreach ($rows as $row) {
395 $items->addItem(call_user_func([static::FACTORY, 'create'], $row), $row['id']);
396 }
397
398 return $items;
399 }
400
401 /**
402 * @param array $criteria
403 *
404 * @return mixed
405 * @throws QueryExecutionException
406 */
407 public function getCount($criteria)
408 {
409 $params = [];
410
411 $where = [];
412
413 if (!empty($criteria['categoryId'])) {
414 $params[':categoryId'] = $criteria['categoryId'];
415
416 $where[] = 's.categoryId = :categoryId';
417 }
418
419 $where = $where ? 'WHERE ' . implode(' AND ', $where) : '';
420
421 try {
422 $statement = $this->connection->prepare(
423 "SELECT COUNT(*) as count
424 FROM {$this->table} s
425 {$where}
426 ORDER BY s.position, s.id"
427 );
428
429 $statement->execute($params);
430
431 $row = $statement->fetch()['count'];
432 } catch (\Exception $e) {
433 throw new QueryExecutionException('Unable to get data from ' . __CLASS__, $e->getCode(), $e);
434 }
435
436 return $row;
437 }
438
439 /**
440 * @param int $serviceId
441 * @param int $userId
442 *
443 * @return Collection
444 * @throws QueryExecutionException
445 */
446 public function getProviderServicesWithExtras($serviceId, $userId)
447 {
448 try {
449 $statement = $this->connection->prepare("SELECT
450 s.id AS service_id,
451 s.name AS service_name,
452 s.description AS service_description,
453 s.color AS service_color,
454 ps.price AS service_price,
455 s.status AS service_status,
456 s.categoryId AS service_categoryId,
457 ps.minCapacity AS service_minCapacity,
458 ps.maxCapacity AS service_maxCapacity,
459 ps.customPricing AS service_customPricing,
460 s.limitPerCustomer AS service_limitPerCustomer,
461 s.duration AS service_duration,
462 s.timeBefore AS service_timeBefore,
463 s.timeAfter AS service_timeAfter,
464 s.bringingAnyone as service_bringingAnyone,
465 s.pictureFullPath AS service_picture_full,
466 s.pictureThumbPath AS service_picture_thumb,
467 s.aggregatedPrice AS service_aggregatedPrice,
468 s.settings AS service_settings,
469 s.recurringPayment AS service_recurringPayment,
470 s.translations AS service_translations,
471 s.show AS service_show,
472 s.deposit AS service_deposit,
473 s.depositPayment AS service_depositPayment,
474 s.depositPerPerson AS service_depositPerPerson,
475 s.fullPayment AS service_fullPayment,
476
477 e.id AS extra_id,
478 e.name AS extra_name,
479 e.price AS extra_price,
480 e.maxQuantity AS extra_maxQuantity,
481 e.duration AS extra_duration,
482 e.aggregatedPrice AS extra_aggregatedPrice,
483 e.position AS extra_position,
484 e.translations AS extra_translations
485 FROM {$this->table} s
486 INNER JOIN {$this->providerServicesTable} ps ON s.id = ps.serviceId
487 LEFT JOIN {$this->extrasTable} e ON e.serviceId = s.id
488 WHERE ps.userId = :userId AND ps.serviceId = :serviceId");
489
490 $statement->bindParam(':userId', $userId);
491 $statement->bindParam(':serviceId', $serviceId);
492
493 $statement->execute();
494
495 $rows = $statement->fetchAll();
496 } catch (\Exception $e) {
497 throw new QueryExecutionException('Unable to find by ids in ' . __CLASS__, $e->getCode(), $e);
498 }
499
500 return call_user_func([static::FACTORY, 'createCollection'], $rows);
501 }
502
503 /**
504 * @param $criteria
505 *
506 * @return Collection
507 * @throws QueryExecutionException
508 */
509 public function getByCriteria($criteria)
510 {
511 $params = [];
512 $where = [];
513
514 $order = 'ORDER BY s.name ASC';
515 if (isset($criteria['sort'])) {
516 if ($criteria['sort'] === '') {
517 $order = 'ORDER BY s.position';
518 } else {
519 $orderColumn = strpos($criteria['sort'], 'name') !== false ? 's.name' : 's.price';
520 $orderDirection = $criteria['sort'][0] === '-' ? 'DESC' : 'ASC';
521 $order = "ORDER BY {$orderColumn} {$orderDirection}";
522 }
523 }
524
525 if (!empty($criteria['search'])) {
526 $params[':search'] = "%{$criteria['search']}%";
527
528 $where[] = 's.name LIKE :search';
529 }
530
531 if (!empty($criteria['services'])) {
532 $queryServices = [];
533
534 foreach ((array)$criteria['services'] as $index => $value) {
535 $param = ':service' . $index;
536 $queryServices[] = $param;
537 $params[$param] = $value;
538 }
539
540 $where[] = 's.id IN (' . implode(', ', $queryServices) . ')';
541 }
542
543 if (!empty($criteria['categories'])) {
544 $queryCategories = [];
545
546 foreach ((array)$criteria['categories'] as $index => $value) {
547 $param = ':category' . $index;
548 $queryCategories[] = $param;
549 $params[$param] = $value;
550 }
551
552 $where[] = 's.categoryId IN (' . implode(', ', $queryCategories) . ')';
553 }
554
555 if (!empty($criteria['providers'])) {
556 $queryProviders = [];
557
558 foreach ((array)$criteria['providers'] as $index => $value) {
559 $param = ':provider' . $index;
560 $queryProviders[] = $param;
561 $params[$param] = $value;
562 }
563
564 $where[] = 'ps.userId IN (' . implode(', ', $queryProviders) . ')';
565 }
566
567 if (!empty($criteria['status'])) {
568 $params[':status'] = $criteria['status'];
569
570 $where[] = 's.status = :status';
571 }
572
573 $where = $where ? ' AND ' . implode(' AND ', $where) : '';
574
575 try {
576 $statement = $this->connection->prepare(
577 "SELECT
578 s.id AS service_id,
579 s.name AS service_name,
580 s.description AS service_description,
581 s.color AS service_color,
582 s.price AS service_price,
583 s.status AS service_status,
584 s.categoryId AS service_categoryId,
585 s.maxCapacity AS service_maxCapacity,
586 s.maxExtraPeople AS service_maxExtraPeople,
587 s.minCapacity AS service_minCapacity,
588 s.duration AS service_duration,
589 s.timeBefore AS service_timeBefore,
590 s.timeAfter AS service_timeAfter,
591 s.bringingAnyone AS service_bringingAnyone,
592 s.pictureFullPath AS service_picture_full,
593 s.pictureThumbPath AS service_picture_thumb,
594 s.show AS service_show,
595 s.position AS service_position,
596 s.aggregatedPrice AS service_aggregatedPrice,
597 s.settings AS service_settings,
598 s.translations AS service_translations,
599 s.recurringCycle AS service_recurringCycle,
600 s.recurringSub AS service_recurringSub,
601 s.recurringPayment AS service_recurringPayment,
602 s.deposit AS service_deposit,
603 s.depositPayment AS service_depositPayment,
604 s.depositPerPerson AS service_depositPerPerson,
605 s.fullPayment AS service_fullPayment,
606 s.mandatoryExtra AS service_mandatoryExtra,
607 s.minSelectedExtras AS service_minSelectedExtras,
608 s.customPricing AS service_customPricing,
609 s.limitPerCustomer AS service_limitPerCustomer,
610
611 e.id AS extra_id,
612 e.name AS extra_name,
613 e.price AS extra_price,
614 e.maxQuantity AS extra_maxQuantity,
615 e.duration AS extra_duration,
616 e.position AS extra_position,
617 e.aggregatedPrice AS extra_aggregatedPrice,
618 e.description AS extra_description,
619 e.translations AS extra_translations,
620
621 g.id AS gallery_id,
622 g.pictureFullPath AS gallery_picture_full,
623 g.pictureThumbPath AS gallery_picture_thumb,
624 g.position AS gallery_position
625
626 FROM {$this->table} s
627 LEFT JOIN {$this->extrasTable} e ON e.serviceId = s.id
628 LEFT JOIN {$this->providerServicesTable} ps ON ps.serviceId = s.id
629 LEFT JOIN {$this->galleriesTable} g ON g.entityId = s.id AND g.entityType = 'service'
630 WHERE 1 = 1 $where
631 $order"
632 );
633
634 $statement->execute($params);
635
636 $rows = $statement->fetchAll();
637 } catch (\Exception $e) {
638 throw new QueryExecutionException('Unable to find by id in ' . __CLASS__, $e->getCode(), $e);
639 }
640
641 return call_user_func([static::FACTORY, 'createCollection'], $rows);
642 }
643
644 /**
645 * @param int $serviceId
646 *
647 * @return Service
648 * @throws QueryExecutionException
649 */
650 public function getByIdWithExtras($serviceId)
651 {
652 try {
653 $statement = $this->connection->prepare(
654 "SELECT
655 s.id AS service_id,
656 s.name AS service_name,
657 s.description AS service_description,
658 s.color AS service_color,
659 s.price AS service_price,
660 s.customPricing AS service_customPricing,
661 s.limitPerCustomer AS service_limitPerCustomer,
662 s.status AS service_status,
663 s.categoryId AS service_categoryId,
664 s.maxCapacity AS service_maxCapacity,
665 s.maxExtraPeople AS service_maxExtraPeople,
666 s.minCapacity AS service_minCapacity,
667 s.duration AS service_duration,
668 s.timeBefore AS service_timeBefore,
669 s.timeAfter AS service_timeAfter,
670 s.bringingAnyone AS service_bringingAnyone,
671 s.priority AS service_priority,
672 s.pictureFullPath AS service_picture_full,
673 s.pictureThumbPath AS service_picture_thumb,
674 s.aggregatedPrice AS service_aggregatedPrice,
675 s.settings AS service_settings,
676 s.translations AS service_translations,
677 s.deposit AS service_deposit,
678 s.depositPayment AS service_depositPayment,
679 s.depositPerPerson AS service_depositPerPerson,
680 s.fullPayment AS servie_fullPayment,
681
682 e.id AS extra_id,
683 e.name AS extra_name,
684 e.description AS extra_description,
685 e.price AS extra_price,
686 e.maxQuantity AS extra_maxQuantity,
687 e.duration AS extra_duration,
688 e.aggregatedPrice AS extra_aggregatedPrice,
689 e.position AS extra_position,
690 e.translations AS extra_translations
691
692 FROM {$this->table} s
693 LEFT JOIN {$this->extrasTable} e ON e.serviceId = s.id
694 WHERE s.id = :serviceId
695 ORDER BY s.id, e.id"
696 );
697
698 $statement->bindParam(':serviceId', $serviceId);
699
700 $statement->execute();
701
702 $rows = $statement->fetchAll();
703 } catch (\Exception $e) {
704 throw new QueryExecutionException('Unable to find by id in ' . __CLASS__, $e->getCode(), $e);
705 }
706
707 return call_user_func([static::FACTORY, 'createCollection'], $rows)->getItem($serviceId);
708 }
709
710 /**
711 * @param array $criteria
712 *
713 * @return Collection
714 * @throws QueryExecutionException
715 */
716 public function getWithExtras($criteria)
717 {
718 $order = '';
719
720 $where = [];
721
722 if (isset($criteria['sort'])) {
723 if ($criteria['sort'] === '') {
724 $order = 'ORDER BY s.position';
725 } else {
726 $orderColumn = strpos($criteria['sort'], 'name') !== false ? 's.name' : 's.price';
727
728 $orderDirection = $criteria['sort'][0] === '-' ? 'DESC' : 'ASC';
729
730 $order = "ORDER BY {$orderColumn} {$orderDirection}";
731 }
732 }
733
734 $where = $where ? 'WHERE ' . implode(' AND ', $where) : '';
735
736 try {
737 $statement = $this->connection->query(
738 "SELECT
739 s.id AS service_id,
740 s.name AS service_name,
741 s.description AS service_description,
742 s.color AS service_color,
743 s.price AS service_price,
744 s.customPricing AS service_customPricing,
745 s.status AS service_status,
746 s.categoryId AS service_categoryId,
747 s.maxCapacity AS service_maxCapacity,
748 s.maxExtraPeople AS service_maxExtraPeople,
749 s.minCapacity AS service_minCapacity,
750 s.duration AS service_duration,
751 s.timeBefore AS service_timeBefore,
752 s.timeAfter AS service_timeAfter,
753 s.bringingAnyone as service_bringingAnyone,
754 s.pictureFullPath AS service_picture_full,
755 s.pictureThumbPath AS service_picture_thumb,
756 s.position AS service_position,
757 s.show AS service_show,
758 s.aggregatedPrice AS service_aggregatedPrice,
759 s.settings AS service_settings,
760 s.recurringCycle AS service_recurringCycle,
761 s.recurringSub AS service_recurringSub,
762 s.recurringPayment AS service_recurringPayment,
763 s.translations AS service_translations,
764 s.deposit AS service_deposit,
765 s.depositPayment AS service_depositPayment,
766 s.depositPerPerson AS service_depositPerPerson,
767 s.fullPayment AS service_fullPayment,
768 s.mandatoryExtra AS service_mandatoryExtra,
769 s.minSelectedExtras AS service_minSelectedExtras,
770
771 e.id AS extra_id,
772 e.name AS extra_name,
773 e.price AS extra_price,
774 e.maxQuantity AS extra_maxQuantity,
775 e.duration AS extra_duration,
776 e.position AS extra_position,
777 e.aggregatedPrice AS extra_aggregatedPrice,
778 e.description AS extra_description,
779 e.translations AS extra_translations
780 FROM {$this->table} s
781 LEFT JOIN {$this->extrasTable} e ON e.serviceId = s.id
782 {$where}
783 {$order}"
784 );
785
786 $rows = $statement->fetchAll();
787 } catch (\Exception $e) {
788 throw new QueryExecutionException('Unable to get data from ' . __CLASS__, $e->getCode(), $e);
789 }
790
791 /** @var Collection $services */
792 $services = call_user_func([static::FACTORY, 'createCollection'], $rows);
793
794 /** @var Service $service */
795 foreach ($services->getItems() as $service) {
796 if ($service->getSettings() && json_decode($service->getSettings()->getValue(), true) === null) {
797 $service->setSettings(null);
798 }
799 }
800
801 return $services;
802 }
803
804 /**
805 * @param $serviceId
806 * @param $status
807 *
808 * @return bool
809 * @throws QueryExecutionException
810 */
811 public function updateStatusById($serviceId, $status)
812 {
813 $params = [
814 ':id' => $serviceId,
815 ':status' => $status
816 ];
817
818 try {
819 $statement = $this->connection->prepare(
820 "UPDATE {$this->table}
821 SET
822 `status` = :status
823 WHERE id = :id"
824 );
825
826 $res = $statement->execute($params);
827
828 if (!$res) {
829 throw new QueryExecutionException('Unable to save data in ' . __CLASS__);
830 }
831
832 return $res;
833 } catch (\Exception $e) {
834 throw new QueryExecutionException('Unable to save data in ' . __CLASS__, $e->getCode(), $e);
835 }
836 }
837
838 /**
839 * Return an array of services with the number of appointments for the given date period.
840 * Keys of the array are Services IDs.
841 *
842 * @param $criteria
843 *
844 * @return array
845 * @throws QueryExecutionException
846 * @throws \AmeliaBooking\Domain\Common\Exceptions\InvalidArgumentException
847 */
848 public function getAllNumberOfAppointments($criteria)
849 {
850 $appointmentTable = AppointmentsTable::getTableName();
851
852 $params = [];
853 $where = [];
854
855 if ($criteria['dates']) {
856 $where[] = "(DATE_FORMAT(a.bookingStart, '%Y-%m-%d %H:%i:%s') BETWEEN :bookingFrom AND :bookingTo)";
857 $params[':bookingFrom'] = DateTimeService::getCustomDateTimeInUtc($criteria['dates'][0]);
858 $params[':bookingTo'] = DateTimeService::getCustomDateTimeInUtc($criteria['dates'][1]);
859 }
860
861 if (isset($criteria['status'])) {
862 $where[] = 's.status = :status';
863 $params[':status'] = $criteria['status'];
864 }
865
866 $where = $where ? 'WHERE ' . implode(' AND ', $where) : '';
867
868 try {
869 $statement = $this->connection->prepare("SELECT
870 s.id,
871 s.name,
872 COUNT(a.providerId) AS appointments
873 FROM {$this->table} s
874 INNER JOIN {$appointmentTable} a ON s.id = a.serviceId
875 $where
876 GROUP BY serviceId");
877
878 $statement->execute($params);
879
880 $rows = $statement->fetchAll();
881 } catch (\Exception $e) {
882 throw new QueryExecutionException('Unable to get data from ' . __CLASS__, $e->getCode(), $e);
883 }
884
885 $result = [];
886
887 foreach ($rows as $row) {
888 $result[$row['id']] = $row;
889 }
890
891 return $result;
892 }
893
894 /**
895 * Return an array of services with the number of views for the given date period.
896 * Keys of the array are Services IDs.
897 *
898 * @param $criteria
899 *
900 * @return array
901 * @throws QueryExecutionException
902 */
903 public function getAllNumberOfViews($criteria)
904 {
905 $params = [];
906 $where = [];
907
908 if ($criteria['dates']) {
909 $where[] = "(DATE_FORMAT(sv.date, '%Y-%m-%d %H:%i:%s') BETWEEN :bookingFrom AND :bookingTo)";
910 $params[':bookingFrom'] = DateTimeService::getCustomDateTimeInUtc($criteria['dates'][0]);
911 $params[':bookingTo'] = DateTimeService::getCustomDateTimeInUtc($criteria['dates'][1]);
912 }
913
914 if (isset($criteria['status'])) {
915 $where[] = 's.status = :status';
916 $params[':status'] = $criteria['status'];
917 }
918
919 $where = $where ? 'WHERE ' . implode(' AND ', $where) : '';
920
921 try {
922 $statement = $this->connection->prepare("SELECT
923 s.id,
924 s.name,
925 SUM(sv.views) AS views
926 FROM {$this->table} s
927 INNER JOIN {$this->serviceViewsTable} sv ON sv.serviceId = s.id
928 $where
929 GROUP BY s.id");
930
931 $statement->execute($params);
932
933 $rows = $statement->fetchAll();
934 } catch (\Exception $e) {
935 throw new QueryExecutionException('Unable to get data from ' . __CLASS__, $e->getCode(), $e);
936 }
937
938 $result = [];
939
940 foreach ($rows as $row) {
941 $result[$row['id']] = $row;
942 }
943
944 return $result;
945 }
946
947 /**
948 * @param $serviceId
949 *
950 * @return string
951 * @throws QueryExecutionException
952 */
953 public function addViewStats($serviceId)
954 {
955 $date = DateTimeService::getNowDate();
956
957 $params = [
958 ':serviceId' => $serviceId,
959 ':date' => $date,
960 ':views' => 1
961 ];
962
963 try {
964 // Check if there is already data for this provider for this date
965 $statement = $this->connection->prepare(
966 "SELECT COUNT(*) AS count
967 FROM {$this->serviceViewsTable} AS pv
968 WHERE pv.serviceId = :serviceId
969 AND pv.date = :date"
970 );
971
972 $statement->bindParam(':serviceId', $serviceId);
973 $statement->bindParam(':date', $date);
974 $statement->execute();
975 $count = $statement->fetch()['count'];
976
977 if (!$count) {
978 $statement = $this->connection->prepare(
979 "INSERT INTO {$this->serviceViewsTable}
980 (`serviceId`, `date`, `views`)
981 VALUES
982 (:serviceId, :date, :views)"
983 );
984 } else {
985 $statement = $this->connection->prepare(
986 "UPDATE {$this->serviceViewsTable} pv SET pv.views = pv.views + :views
987 WHERE pv.serviceId = :serviceId
988 AND pv.date = :date"
989 );
990 }
991
992 $response = $statement->execute($params);
993 } catch (\Exception $e) {
994 throw new QueryExecutionException('Unable to add data in ' . __CLASS__, $e->getCode(), $e);
995 }
996
997 if (!$response) {
998 throw new QueryExecutionException('Unable to add data in ' . __CLASS__);
999 }
1000
1001 return true;
1002 }
1003
1004 /**
1005 * @param int $serviceId
1006 *
1007 * @return mixed
1008 * @throws QueryExecutionException
1009 */
1010 public function deleteViewStats($serviceId)
1011 {
1012 $params = [
1013 ':serviceId' => $serviceId,
1014 ];
1015
1016 try {
1017 $statement = $this->connection->prepare(
1018 "DELETE FROM {$this->serviceViewsTable} WHERE serviceId = :serviceId"
1019 );
1020
1021 return $statement->execute($params);
1022 } catch (\Exception $e) {
1023 throw new QueryExecutionException('Unable to delete data from ' . __CLASS__, $e->getCode(), $e);
1024 }
1025 }
1026 }
1027