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