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 / Infrastructure / Repository / Location / LocationRepository.php
ameliabooking / src / Infrastructure / Repository / Location Last commit date
LocationRepository.php 3 months ago ProviderLocationRepository.php 3 months ago
LocationRepository.php
711 lines
1 <?php
2
3 namespace AmeliaBooking\Infrastructure\Repository\Location;
4
5 use AmeliaBooking\Domain\Collection\Collection;
6 use AmeliaBooking\Domain\Common\Exceptions\InvalidArgumentException;
7 use AmeliaBooking\Domain\Entity\Location\Location;
8 use AmeliaBooking\Domain\Factory\Bookable\Service\ServiceFactory;
9 use AmeliaBooking\Domain\Repository\Location\LocationRepositoryInterface;
10 use AmeliaBooking\Domain\Services\DateTime\DateTimeService;
11 use AmeliaBooking\Domain\ValueObjects\String\Status;
12 use AmeliaBooking\Infrastructure\Common\Exceptions\QueryExecutionException;
13 use AmeliaBooking\Infrastructure\Connection;
14 use AmeliaBooking\Infrastructure\Repository\AbstractRepository;
15 use AmeliaBooking\Domain\Factory\Location\LocationFactory;
16 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Bookable\CategoriesTable;
17 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Bookable\ServicesTable;
18 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Booking\AppointmentsTable;
19 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Booking\EventsPeriodsTable;
20 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Booking\EventsTable;
21 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\User\Provider\ProvidersLocationTable;
22 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\User\Provider\ProvidersPeriodLocationTable;
23 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\User\Provider\ProvidersPeriodTable;
24 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\User\Provider\ProvidersServiceTable;
25 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\User\UsersTable;
26
27 /**
28 * Class LocationRepositoryInterface
29 *
30 * @package AmeliaBooking\Infrastructure\Repository
31 */
32 class LocationRepository extends AbstractRepository implements LocationRepositoryInterface
33 {
34 public const FACTORY = LocationFactory::class;
35 public const SERVICE_FACTORY = ServiceFactory::class;
36
37 /** @var string */
38 protected $providerServicesTable;
39
40 /** @var string */
41 protected $providerLocationTable;
42
43 /** @var string */
44 protected $servicesTable;
45
46 /** @var string */
47 protected $locationViewsTable;
48
49 /**
50 * @param Connection $connection
51 * @param string $table
52 * @param string $providerLocationTable
53 * @param string $providerServicesTable
54 * @param string $servicesTable
55 * @param $locationViewsTable
56 */
57 public function __construct(
58 Connection $connection,
59 $table,
60 $providerLocationTable,
61 $providerServicesTable,
62 $servicesTable,
63 $locationViewsTable
64 ) {
65 parent::__construct($connection, $table);
66
67 $this->providerServicesTable = $providerServicesTable;
68 $this->providerLocationTable = $providerLocationTable;
69 $this->servicesTable = $servicesTable;
70 $this->locationViewsTable = $locationViewsTable;
71 }
72
73 /**
74 * @param Location $location
75 *
76 * @return int
77 * @throws QueryExecutionException
78 */
79 public function add($location)
80 {
81 $data = $location->toArray();
82
83 $params = [
84 ':status' => $data['status'],
85 ':name' => $data['name'],
86 ':description' => $data['description'],
87 ':address' => $data['address'],
88 ':phone' => $data['phone'],
89 ':latitude' => $data['latitude'],
90 ':longitude' => $data['longitude'],
91 ':pictureFullPath' => $data['pictureFullPath'],
92 ':pictureThumbPath' => $data['pictureThumbPath'],
93 ':pin' => $data['pin'],
94 ':translations' => $data['translations'],
95 ':countryPhoneIso' => isset($data['countryPhoneIso']) ? $data['countryPhoneIso'] : null
96 ];
97
98 try {
99 $statement = $this->connection->prepare(
100 "INSERT INTO {$this->table}
101 (
102 `status`,
103 `name`,
104 `description`,
105 `address`,
106 `phone`,
107 `latitude`,
108 `longitude`,
109 `pictureFullPath`,
110 `pictureThumbPath`,
111 `pin`,
112 `translations`,
113 `countryPhoneIso`
114 )
115 VALUES (
116 :status,
117 :name,
118 :description,
119 :address,
120 :phone,
121 :latitude,
122 :longitude,
123 :pictureFullPath,
124 :pictureThumbPath,
125 :pin,
126 :translations,
127 :countryPhoneIso
128 )"
129 );
130
131 $statement->execute($params);
132 } catch (\Exception $e) {
133 throw new QueryExecutionException('Unable to add data in ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
134 }
135
136 return $this->connection->lastInsertId();
137 }
138
139 /**
140 * @param int $id
141 * @param Location $location
142 *
143 * @return bool
144 * @throws QueryExecutionException
145 */
146 public function update($id, $location)
147 {
148 $data = $location->toArray();
149
150 $params = [
151 ':status' => $data['status'],
152 ':name' => $data['name'],
153 ':description' => $data['description'],
154 ':address' => $data['address'],
155 ':phone' => $data['phone'],
156 ':latitude' => $data['latitude'],
157 ':longitude' => $data['longitude'],
158 ':pictureFullPath' => $data['pictureFullPath'],
159 ':pictureThumbPath' => $data['pictureThumbPath'],
160 ':pin' => $data['pin'],
161 ':translations' => $data['translations'],
162 ':id' => $id,
163 ':countryPhoneIso' => isset($data['countryPhoneIso']) ? $data['countryPhoneIso'] : null
164 ];
165
166 try {
167 $statement = $this->connection->prepare(
168 "UPDATE {$this->table}
169 SET `status` = :status, `name` = :name, `description` = :description, `address` = :address,
170 `phone` = :phone, `latitude` = :latitude, `longitude` = :longitude,
171 `pictureFullPath` = :pictureFullPath, `pictureThumbPath` = :pictureThumbPath,
172 `pin` = :pin, `translations` = :translations, `countryPhoneIso` = :countryPhoneIso
173 WHERE id = :id"
174 );
175
176 $statement->execute($params);
177
178 return true;
179 } catch (\Exception $e) {
180 throw new QueryExecutionException('Unable to save data in ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
181 }
182 }
183
184 /**
185 * @return Collection
186 * @throws InvalidArgumentException
187 * @throws QueryExecutionException
188 */
189 public function getAllOrderedByName()
190 {
191 try {
192 $statement = $this->connection->query(
193 "SELECT * FROM {$this->table} ORDER BY name"
194 );
195
196 $rows = $statement->fetchAll();
197 } catch (\Exception $e) {
198 throw new QueryExecutionException('Unable to get data from ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
199 }
200
201 $items = new Collection();
202 foreach ($rows as $row) {
203 $items->addItem(call_user_func([static::FACTORY, 'create'], $row), $row['id']);
204 }
205
206 return $items;
207 }
208
209 /**
210 * @param array $criteria
211 * @param int $itemsPerPage
212 *
213 * @return Collection
214 * @throws InvalidArgumentException
215 * @throws QueryExecutionException
216 */
217 public function getFiltered($criteria, $itemsPerPage)
218 {
219 $params = [];
220
221 $order = '';
222 if (!empty($criteria['sort'])) {
223 $orderColumn = $criteria['sort']['field'];
224 $orderDirection = $criteria['sort']['order'];
225 $order = "ORDER BY {$orderColumn} {$orderDirection}";
226 }
227
228 $search = '';
229 if (!empty($criteria['search'])) {
230 $terms = preg_split('/\s+/', trim($criteria['search']));
231 $termIndex = 0;
232 $where = [];
233
234 foreach ($terms as $term) {
235 $param = ":search{$termIndex}";
236 $params[$param] = "%{$term}%";
237
238 $where[] = "(
239 l.name LIKE {$param}
240 OR l.address LIKE {$param}
241 OR l.id LIKE {$param}
242 )";
243
244 $termIndex++;
245 }
246 $search = ' AND (' . implode(' AND ', $where) . ')';
247 }
248
249 $services = '';
250 if (!empty($criteria['services'])) {
251 foreach ((array)$criteria['services'] as $index => $value) {
252 ++$index;
253 $services .= ':service' . $index . ', ';
254 $params[':service' . $index] = $value;
255 }
256
257 $services = ' AND s.id IN (' . rtrim($services, ', ') . ')';
258 }
259
260 $status = '';
261 if (isset($criteria['status'])) {
262 $status = ' AND l.status = :status';
263 $params[':status'] = $criteria['status'];
264 }
265
266 $limit = $this->getLimit(
267 !empty($criteria['page']) ? (int)$criteria['page'] : 0,
268 (int)$itemsPerPage
269 );
270
271 try {
272 $statement = $this->connection->prepare(
273 "SELECT
274 l.id,
275 l.status,
276 l.name,
277 l.description,
278 l.address,
279 l.phone,
280 l.latitude,
281 l.longitude,
282 l.pictureFullPath,
283 l.pictureThumbPath,
284 l.pin,
285 l.translations,
286 l.countryPhoneIso
287 FROM {$this->table} l
288 LEFT JOIN {$this->providerLocationTable} pl ON pl.locationId = l.id
289 LEFT JOIN {$this->providerServicesTable} ps ON ps.userId = pl.userId
290 LEFT JOIN {$this->servicesTable} s ON s.id = ps.serviceId
291 WHERE 1 = 1 $search $services $status
292 GROUP BY l.id
293 {$order}
294 {$limit}"
295 );
296
297 $statement->execute($params);
298
299 $rows = $statement->fetchAll();
300 } catch (\Exception $e) {
301 throw new QueryExecutionException('Unable to get data from ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
302 }
303
304 $items = [];
305 foreach ($rows as $row) {
306 $items[] = call_user_func([static::FACTORY, 'create'], $row);
307 }
308
309 return new Collection($items);
310 }
311
312 /**
313 * @param $criteria
314 *
315 * @return array
316 * @throws InvalidArgumentException
317 * @throws QueryExecutionException
318 */
319 public function getCount($criteria)
320 {
321 $providerLocationTable = ProvidersLocationTable::getTableName();
322 $providerServicesTable = ProvidersServiceTable::getTableName();
323 $servicesTable = ServicesTable::getTableName();
324
325 $params = [];
326
327 $search = '';
328 if (!empty($criteria['search'])) {
329 $terms = preg_split('/\s+/', trim($criteria['search']));
330 $termIndex = 0;
331 $where = [];
332
333 foreach ($terms as $term) {
334 $param = ":search{$termIndex}";
335 $params[$param] = "%{$term}%";
336
337 $where[] = "(
338 l.name LIKE {$param}
339 OR l.address LIKE {$param}
340 OR l.id LIKE {$param}
341 )";
342
343 $termIndex++;
344 }
345 $search = ' AND (' . implode(' AND ', $where) . ')';
346 }
347
348 $services = '';
349 if (!empty($criteria['services'])) {
350 foreach ((array)$criteria['services'] as $index => $value) {
351 ++$index;
352 $services .= ':service' . $index . ', ';
353 $params[':service' . $index] = $value;
354 }
355
356 $services = ' AND s.id IN (' . rtrim($services, ', ') . ')';
357 }
358
359
360 try {
361 $statement = $this->connection->prepare(
362 "SELECT COUNT(*) as count
363 FROM (
364 SELECT l.id
365 FROM {$this->table} l
366 LEFT JOIN {$providerLocationTable} pl ON pl.locationId = l.id
367 LEFT JOIN {$providerServicesTable} ps ON ps.userId = pl.userId
368 LEFT JOIN {$servicesTable} s ON s.id = ps.serviceId
369 WHERE l.status IN (:visibleStatus, :hiddenStatus) $search $services
370 GROUP BY l.id
371 ) as t"
372 );
373
374 $params[':visibleStatus'] = Status::VISIBLE;
375 $params[':hiddenStatus'] = Status::HIDDEN;
376
377 $statement->execute($params);
378
379 $rows = $statement->fetch()['count'];
380 } catch (\Exception $e) {
381 throw new QueryExecutionException('Unable to get data from ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
382 }
383
384 return $rows;
385 }
386
387 /**
388 * @param $id
389 *
390 * @return Collection
391 * @throws InvalidArgumentException
392 * @throws QueryExecutionException
393 */
394 public function getServicesById($id)
395 {
396 $params = [
397 ':id' => $id
398 ];
399
400 try {
401 $statement = $this->connection->prepare(
402 "
403 SELECT s.*
404 FROM {$this->table} l
405 INNER JOIN {$this->providerLocationTable} pl ON pl.locationId = l.id
406 INNER JOIN {$this->providerServicesTable} ps ON ps.userId = pl.userId
407 INNER JOIN {$this->servicesTable} s ON s.id = ps.serviceId
408 WHERE l.id = :id
409 GROUP BY s.id"
410 );
411
412 $statement->execute($params);
413
414 $rows = $statement->fetchAll();
415 } catch (\Exception $e) {
416 throw new QueryExecutionException('Unable to get data from ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
417 }
418
419 $items = [];
420 foreach ($rows as $row) {
421 $items[] = call_user_func([static::SERVICE_FACTORY, 'create'], $row);
422 }
423
424 return new Collection($items);
425 }
426
427 /**
428 * Return an array of locations with the number of appointments for the given date period.
429 * Keys of the array are Locations IDs.
430 *
431 * @param $criteria
432 *
433 * @return array
434 * @throws QueryExecutionException
435 * @throws \AmeliaBooking\Domain\Common\Exceptions\InvalidArgumentException
436 */
437 public function getAllNumberOfAppointments($criteria)
438 {
439 $userTable = UsersTable::getTableName();
440 $appointmentTable = AppointmentsTable::getTableName();
441
442 $params = [];
443 $where = [];
444
445 if ($criteria['dates']) {
446 $where[] = "(a.bookingStart BETWEEN :bookingFrom AND :bookingTo)";
447 $params[':bookingFrom'] = DateTimeService::getCustomDateTimeInUtc($criteria['dates'][0]);
448 $params[':bookingTo'] = DateTimeService::getCustomDateTimeInUtc($criteria['dates'][1]);
449 }
450
451 if (isset($criteria['status'])) {
452 $where[] = 'l.status = :status';
453 $params[':status'] = $criteria['status'];
454 }
455
456 $where = $where ? 'WHERE ' . implode(' AND ', $where) : '';
457
458 try {
459 $statement = $this->connection->prepare(
460 "SELECT
461 l.id,
462 l.name,
463 COUNT(l.id) AS appointments
464 FROM {$this->table} l
465 INNER JOIN {$this->providerLocationTable} pl ON pl.locationId = l.id
466 INNER JOIN {$userTable} u ON u.id = pl.userId
467 INNER JOIN {$appointmentTable} a ON u.id = a.providerId
468 $where
469 GROUP BY l.id"
470 );
471
472 $statement->execute($params);
473
474 $rows = $statement->fetchAll();
475 } catch (\Exception $e) {
476 throw new QueryExecutionException('Unable to get data from ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
477 }
478
479 $result = [];
480
481 foreach ($rows as $row) {
482 $result[$row['id']] = $row;
483 }
484
485 return $result;
486 }
487
488 /**
489 * Return an array of locations with the number of views for the given date period.
490 * Keys of the array are Locations IDs.
491 *
492 * @param $criteria
493 *
494 * @return array
495 * @throws QueryExecutionException
496 */
497 public function getAllNumberOfViews($criteria)
498 {
499 $params = [];
500
501 $where = [];
502
503 if ($criteria['dates']) {
504 $where[] = "(lv.date BETWEEN :bookingFrom AND :bookingTo)";
505
506 $params[':bookingFrom'] = explode(' ', $criteria['dates'][0])[0];
507
508 $params[':bookingTo'] = explode(' ', $criteria['dates'][1])[0];
509 }
510
511 if (isset($criteria['status'])) {
512 $where[] = 'l.status = :status';
513
514 $params[':status'] = $criteria['status'];
515 }
516
517 $where = $where ? 'WHERE ' . implode(' AND ', $where) : '';
518
519 try {
520 $statement = $this->connection->prepare(
521 "SELECT
522 l.id,
523 l.name,
524 SUM(lv.views) AS views
525 FROM {$this->table} l
526 INNER JOIN {$this->locationViewsTable} lv ON lv.locationId = l.id
527 $where
528 GROUP BY l.id"
529 );
530
531 $statement->execute($params);
532
533 $rows = $statement->fetchAll();
534 } catch (\Exception $e) {
535 throw new QueryExecutionException('Unable to get data from ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
536 }
537
538 $result = [];
539
540 foreach ($rows as $row) {
541 $result[$row['id']] = $row;
542 }
543
544 return $result;
545 }
546
547 /**
548 * @param $locationId
549 *
550 * @return boolean
551 * @throws QueryExecutionException
552 */
553 public function addViewStats($locationId)
554 {
555 $date = DateTimeService::getNowDate();
556
557 $params = [
558 ':locationId' => $locationId,
559 ':date' => $date,
560 ':views' => 1
561 ];
562
563 try {
564 // Check if there is already data for this provider for this date
565 $statement = $this->connection->prepare(
566 "SELECT COUNT(*) AS count
567 FROM {$this->locationViewsTable} AS pv
568 WHERE pv.locationId = :locationId
569 AND pv.date = :date"
570 );
571
572 $statement->bindParam(':locationId', $locationId);
573 $statement->bindParam(':date', $date);
574 $statement->execute();
575 $count = $statement->fetch()['count'];
576
577 if (!$count) {
578 $statement = $this->connection->prepare(
579 "INSERT INTO {$this->locationViewsTable}
580 (`locationId`, `date`, `views`)
581 VALUES
582 (:locationId, :date, :views)"
583 );
584 } else {
585 $statement = $this->connection->prepare(
586 "UPDATE {$this->locationViewsTable} pv SET pv.views = pv.views + :views
587 WHERE pv.locationId = :locationId
588 AND pv.date = :date"
589 );
590 }
591
592 $statement->execute($params);
593 } catch (\Exception $e) {
594 throw new QueryExecutionException('Unable to add data in ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
595 }
596
597 return true;
598 }
599
600 /**
601 * @param int $locationId
602 *
603 * @return mixed
604 * @throws QueryExecutionException
605 */
606 public function deleteViewStats($locationId)
607 {
608 $params = [
609 ':locationId' => $locationId,
610 ];
611
612 try {
613 $statement = $this->connection->prepare(
614 "DELETE FROM {$this->locationViewsTable} WHERE locationId = :locationId"
615 );
616
617 $statement->execute($params);
618 return true;
619 } catch (\Exception $e) {
620 throw new QueryExecutionException('Unable to delete data from ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
621 }
622 }
623
624
625 /**
626 * @param $id
627 *
628 * @return Collection
629 * @throws InvalidArgumentException
630 * @throws QueryExecutionException
631 */
632 public function getByIdWithEntities($id)
633 {
634 $usersTable = UsersTable::getTableName();
635 $providerPeriodsTable = ProvidersPeriodTable::getTableName();
636 $providerPeriodsLocations = ProvidersPeriodLocationTable::getTableName();
637 $eventsTable = EventsTable::getTableName();
638 $categoriesTable = CategoriesTable::getTableName();
639 $eventPeriodsTable = EventsPeriodsTable::getTableName();
640
641 $params = [
642 ':id' => $id,
643 ':eventLocationId' => $id
644 ];
645
646 try {
647 $statement = $this->connection->prepare("
648 SELECT
649 l.id AS location_id,
650 l.status AS location_status,
651 l.name AS location_name,
652 l.description AS location_description,
653 l.address AS location_address,
654 l.phone AS location_phone,
655 l.latitude AS location_latitude,
656 l.longitude AS location_longitude,
657 l.pictureFullPath AS location_pictureFullPath,
658 l.pictureThumbPath AS location_pictureThumbPath,
659 l.pin AS location_pin,
660 l.translations AS location_translations,
661
662 pu.id AS provider_id,
663 pu.firstName AS provider_firstName,
664 pu.lastName AS provider_lastName,
665 pu.email AS provider_email,
666 pu.phone AS provider_phone,
667 pu.pictureThumbPath AS provider_pictureThumbPath,
668 pu.pictureFullPath AS provider_pictureFullPath,
669
670 s.id AS service_id,
671 s.name AS service_name,
672 s.color AS service_color,
673
674 c.id AS category_id,
675 c.name AS category_name,
676
677 e.id AS event_id,
678 e.name AS event_name,
679 e.color AS event_color,
680
681 ep.id AS event_periodId,
682 ep.periodStart AS event_periodStart,
683 ep.periodEnd AS event_periodEnd,
684 ep.zoomMeeting AS event_periodZoomMeeting,
685 ep.lessonSpace AS event_periodLessonSpace,
686 ep.googleMeetUrl AS event_googleMeetUrl
687
688 FROM {$this->table} l
689 LEFT JOIN {$this->providerLocationTable} pl ON pl.locationId = l.id
690 LEFT JOIN {$providerPeriodsTable} pp ON pp.locationId = l.id
691 LEFT JOIN {$providerPeriodsLocations} ppl ON ppl.locationId = l.id
692 LEFT JOIN {$usersTable} pu ON pu.id = pl.userId
693 LEFT JOIN {$this->providerServicesTable} ps ON ps.userId = pl.userId
694 LEFT JOIN (SELECT * FROM {$this->servicesTable} LIMIT 11) s ON s.id = ps.serviceId
695 LEFT JOIN {$categoriesTable} c ON c.id = s.categoryId
696 LEFT JOIN (SELECT * FROM {$eventsTable} WHERE locationId = :eventLocationId LIMIT 11 ) e ON e.locationId = l.id
697 LEFT JOIN {$eventPeriodsTable} ep ON ep.eventId = e.id
698 WHERE l.id = :id
699 ");
700
701 $statement->execute($params);
702
703 $rows = $statement->fetchAll();
704 } catch (\Exception $e) {
705 throw new QueryExecutionException('Unable to get data from ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
706 }
707
708 return call_user_func([static::FACTORY, 'createCollection'], $rows);
709 }
710 }
711