PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 1.2.32
Booking for Appointments and Events Calendar – Amelia v1.2.32
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 1 year ago ProviderLocationRepository.php 1 year ago
LocationRepository.php
623 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\ServicesTable;
17 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Booking\AppointmentsTable;
18 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\User\Provider\ProvidersLocationTable;
19 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\User\Provider\ProvidersServiceTable;
20 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\User\UsersTable;
21
22 /**
23 * Class LocationRepositoryInterface
24 *
25 * @package AmeliaBooking\Infrastructure\Repository
26 */
27 class LocationRepository extends AbstractRepository implements LocationRepositoryInterface
28 {
29 public const FACTORY = LocationFactory::class;
30 public const SERVICE_FACTORY = ServiceFactory::class;
31
32 /** @var string */
33 protected $providerServicesTable;
34
35 /** @var string */
36 protected $providerLocationTable;
37
38 /** @var string */
39 protected $servicesTable;
40
41 /** @var string */
42 protected $locationViewsTable;
43
44 /**
45 * @param Connection $connection
46 * @param string $table
47 * @param string $providerLocationTable
48 * @param string $providerServicesTable
49 * @param string $servicesTable
50 * @param $locationViewsTable
51 */
52 public function __construct(
53 Connection $connection,
54 $table,
55 $providerLocationTable,
56 $providerServicesTable,
57 $servicesTable,
58 $locationViewsTable
59 ) {
60 parent::__construct($connection, $table);
61
62 $this->providerServicesTable = $providerServicesTable;
63 $this->providerLocationTable = $providerLocationTable;
64 $this->servicesTable = $servicesTable;
65 $this->locationViewsTable = $locationViewsTable;
66 }
67
68 /**
69 * @param Location $location
70 *
71 * @return bool
72 * @throws QueryExecutionException
73 */
74 public function add($location)
75 {
76 $data = $location->toArray();
77
78 $params = [
79 ':status' => $data['status'],
80 ':name' => $data['name'],
81 ':description' => $data['description'],
82 ':address' => $data['address'],
83 ':phone' => $data['phone'],
84 ':latitude' => $data['latitude'],
85 ':longitude' => $data['longitude'],
86 ':pictureFullPath' => $data['pictureFullPath'],
87 ':pictureThumbPath' => $data['pictureThumbPath'],
88 ':pin' => $data['pin'],
89 ':translations' => $data['translations']
90 ];
91
92 try {
93 $statement = $this->connection->prepare(
94 "INSERT INTO {$this->table}
95 (
96 `status`,
97 `name`,
98 `description`,
99 `address`,
100 `phone`,
101 `latitude`,
102 `longitude`,
103 `pictureFullPath`,
104 `pictureThumbPath`,
105 `pin`,
106 `translations`
107 )
108 VALUES (
109 :status,
110 :name,
111 :description,
112 :address,
113 :phone,
114 :latitude,
115 :longitude,
116 :pictureFullPath,
117 :pictureThumbPath,
118 :pin,
119 :translations
120 )"
121 );
122
123 $res = $statement->execute($params);
124 if (!$res) {
125 throw new QueryExecutionException('Unable to add data in ' . __CLASS__);
126 }
127 } catch (\Exception $e) {
128 throw new QueryExecutionException('Unable to add data in ' . __CLASS__, $e->getCode(), $e);
129 }
130
131 return $this->connection->lastInsertId();
132 }
133
134 /**
135 * @param int $id
136 * @param Location $location
137 *
138 * @return bool
139 * @throws QueryExecutionException
140 */
141 public function update($id, $location)
142 {
143 $data = $location->toArray();
144
145 $params = [
146 ':status' => $data['status'],
147 ':name' => $data['name'],
148 ':description' => $data['description'],
149 ':address' => $data['address'],
150 ':phone' => $data['phone'],
151 ':latitude' => $data['latitude'],
152 ':longitude' => $data['longitude'],
153 ':pictureFullPath' => $data['pictureFullPath'],
154 ':pictureThumbPath' => $data['pictureThumbPath'],
155 ':pin' => $data['pin'],
156 ':translations' => $data['translations'],
157 ':id' => $id
158 ];
159
160 try {
161 $statement = $this->connection->prepare(
162 "UPDATE {$this->table}
163 SET `status` = :status, `name` = :name, `description` = :description, `address` = :address,
164 `phone` = :phone, `latitude` = :latitude, `longitude` = :longitude,
165 `pictureFullPath` = :pictureFullPath, `pictureThumbPath` = :pictureThumbPath,
166 `pin` = :pin, `translations` = :translations
167 WHERE id = :id"
168 );
169
170 $res = $statement->execute($params);
171 if (!$res) {
172 throw new QueryExecutionException('Unable to save data in ' . __CLASS__);
173 }
174
175 return $res;
176 } catch (\Exception $e) {
177 throw new QueryExecutionException('Unable to save data in ' . __CLASS__, $e->getCode(), $e);
178 }
179 }
180
181 /**
182 * @param int $id
183 * @param string $status
184 *
185 * @return mixed
186 * @throws QueryExecutionException
187 */
188 public function updateStatusById($id, $status)
189 {
190 $params = [
191 ':id' => $id,
192 ':status' => $status
193 ];
194
195 try {
196 $statement = $this->connection->prepare(
197 "UPDATE {$this->table}
198 SET
199 `status` = :status
200 WHERE id = :id"
201 );
202
203 $res = $statement->execute($params);
204
205 if (!$res) {
206 throw new QueryExecutionException('Unable to save data in ' . __CLASS__);
207 }
208
209 return $res;
210 } catch (\Exception $e) {
211 throw new QueryExecutionException('Unable to save data in ' . __CLASS__, $e->getCode(), $e);
212 }
213 }
214
215 /**
216 * @return Collection
217 * @throws InvalidArgumentException
218 * @throws QueryExecutionException
219 */
220 public function getAllOrderedByName()
221 {
222 try {
223 $statement = $this->connection->query(
224 "SELECT * FROM {$this->table} ORDER BY name"
225 );
226
227 $rows = $statement->fetchAll();
228 } catch (\Exception $e) {
229 throw new QueryExecutionException('Unable to get data from ' . __CLASS__, $e->getCode(), $e);
230 }
231
232 $items = new Collection();
233 foreach ($rows as $row) {
234 $items->addItem(call_user_func([static::FACTORY, 'create'], $row), $row['id']);
235 }
236
237 return $items;
238 }
239
240 /**
241 * @param array $criteria
242 * @param int $itemsPerPage
243 *
244 * @return Collection
245 * @throws InvalidArgumentException
246 * @throws QueryExecutionException
247 */
248 public function getFiltered($criteria, $itemsPerPage)
249 {
250 $params = [];
251
252 $order = '';
253 if (!empty($criteria['sort'])) {
254 $orderColumn = $criteria['sort'][0] === '-' ? substr($criteria['sort'], 1) : $criteria['sort'];
255 $orderDirection = $criteria['sort'][0] === '-' ? 'DESC' : 'ASC';
256 $order = "ORDER BY {$orderColumn} {$orderDirection}";
257 }
258
259 $search = '';
260 if (!empty($criteria['search'])) {
261 $params[':search1'] = $params[':search2'] = "%{$criteria['search']}%";
262
263 $search = ' AND (l.name LIKE :search1 OR l.address LIKE :search2)';
264 }
265
266 $services = '';
267 if (!empty($criteria['services'])) {
268 foreach ((array)$criteria['services'] as $index => $value) {
269 ++$index;
270 $services .= ':service' . $index . ', ';
271 $params[':service' . $index] = $value;
272 }
273
274 $services = ' AND s.id IN (' . rtrim($services, ', ') . ')';
275 }
276
277 $limit = $this->getLimit(
278 !empty($criteria['page']) ? (int)$criteria['page'] : 0,
279 (int)$itemsPerPage
280 );
281
282 try {
283 $statement = $this->connection->prepare(
284 "SELECT
285 l.id,
286 l.status,
287 l.name,
288 l.description,
289 l.address,
290 l.phone,
291 l.latitude,
292 l.longitude,
293 l.pictureFullPath,
294 l.pictureThumbPath,
295 l.pin,
296 l.translations
297 FROM {$this->table} l
298 LEFT JOIN {$this->providerLocationTable} pl ON pl.locationId = l.id
299 LEFT JOIN {$this->providerServicesTable} ps ON ps.userId = pl.userId
300 LEFT JOIN {$this->servicesTable} s ON s.id = ps.serviceId
301 WHERE 1 = 1 $search $services
302 GROUP BY l.id
303 {$order}
304 {$limit}"
305 );
306
307 $statement->execute($params);
308
309 $rows = $statement->fetchAll();
310 } catch (\Exception $e) {
311 throw new QueryExecutionException('Unable to get data from ' . __CLASS__, $e->getCode(), $e);
312 }
313
314 $items = [];
315 foreach ($rows as $row) {
316 $items[] = call_user_func([static::FACTORY, 'create'], $row);
317 }
318
319 return new Collection($items);
320 }
321
322 /**
323 * @param $criteria
324 *
325 * @return array
326 * @throws InvalidArgumentException
327 * @throws QueryExecutionException
328 */
329 public function getCount($criteria)
330 {
331 $providerLocationTable = ProvidersLocationTable::getTableName();
332 $providerServicesTable = ProvidersServiceTable::getTableName();
333 $servicesTable = ServicesTable::getTableName();
334
335 $params = [];
336
337 $search = '';
338 if (!empty($criteria['search'])) {
339 $params[':search1'] = $params[':search2'] = "%{$criteria['search']}%";
340
341 $search = ' AND (l.name LIKE :search1 OR l.address LIKE :search2)';
342 }
343
344 $services = '';
345 if (!empty($criteria['services'])) {
346 foreach ((array)$criteria['services'] as $index => $value) {
347 ++$index;
348 $services .= ':service' . $index . ', ';
349 $params[':service' . $index] = $value;
350 }
351
352 $services = ' AND s.id IN (' . rtrim($services, ', ') . ')';
353 }
354
355
356 try {
357 $statement = $this->connection->prepare(
358 "SELECT COUNT(*) as count
359 FROM (
360 SELECT l.id
361 FROM {$this->table} l
362 LEFT JOIN {$providerLocationTable} pl ON pl.locationId = l.id
363 LEFT JOIN {$providerServicesTable} ps ON ps.userId = pl.userId
364 LEFT JOIN {$servicesTable} s ON s.id = ps.serviceId
365 WHERE l.status IN (:visibleStatus, :hiddenStatus) $search $services
366 GROUP BY l.id
367 ) as t"
368 );
369
370 $params[':visibleStatus'] = Status::VISIBLE;
371 $params[':hiddenStatus'] = Status::HIDDEN;
372
373 $statement->execute($params);
374
375 $rows = $statement->fetch()['count'];
376 } catch (\Exception $e) {
377 throw new QueryExecutionException('Unable to get data from ' . __CLASS__, $e->getCode(), $e);
378 }
379
380 return $rows;
381 }
382
383 /**
384 * @param $id
385 *
386 * @return Collection
387 * @throws InvalidArgumentException
388 * @throws QueryExecutionException
389 */
390 public function getServicesById($id)
391 {
392 $params = [
393 ':id' => $id
394 ];
395
396 try {
397 $statement = $this->connection->prepare(
398 "
399 SELECT s.*
400 FROM {$this->table} l
401 INNER JOIN {$this->providerLocationTable} pl ON pl.locationId = l.id
402 INNER JOIN {$this->providerServicesTable} ps ON ps.userId = pl.userId
403 INNER JOIN {$this->servicesTable} s ON s.id = ps.serviceId
404 WHERE l.id = :id
405 GROUP BY s.id"
406 );
407
408 $statement->execute($params);
409
410 $rows = $statement->fetchAll();
411 } catch (\Exception $e) {
412 throw new QueryExecutionException('Unable to get data from ' . __CLASS__, $e->getCode(), $e);
413 }
414
415 $items = [];
416 foreach ($rows as $row) {
417 $items[] = call_user_func([static::SERVICE_FACTORY, 'create'], $row);
418 }
419
420 return new Collection($items);
421 }
422
423 /**
424 * Return an array of locations with the number of appointments for the given date period.
425 * Keys of the array are Locations IDs.
426 *
427 * @param $criteria
428 *
429 * @return array
430 * @throws QueryExecutionException
431 * @throws \AmeliaBooking\Domain\Common\Exceptions\InvalidArgumentException
432 */
433 public function getAllNumberOfAppointments($criteria)
434 {
435 $userTable = UsersTable::getTableName();
436 $appointmentTable = AppointmentsTable::getTableName();
437
438 $params = [];
439 $where = [];
440
441 if ($criteria['dates']) {
442 $where[] = "(a.bookingStart BETWEEN :bookingFrom AND :bookingTo)";
443 $params[':bookingFrom'] = DateTimeService::getCustomDateTimeInUtc($criteria['dates'][0]);
444 $params[':bookingTo'] = DateTimeService::getCustomDateTimeInUtc($criteria['dates'][1]);
445 }
446
447 if (isset($criteria['status'])) {
448 $where[] = 'l.status = :status';
449 $params[':status'] = $criteria['status'];
450 }
451
452 $where = $where ? 'WHERE ' . implode(' AND ', $where) : '';
453
454 try {
455 $statement = $this->connection->prepare(
456 "SELECT
457 l.id,
458 l.name,
459 COUNT(l.id) AS appointments
460 FROM {$this->table} l
461 INNER JOIN {$this->providerLocationTable} pl ON pl.locationId = l.id
462 INNER JOIN {$userTable} u ON u.id = pl.userId
463 INNER JOIN {$appointmentTable} a ON u.id = a.providerId
464 $where
465 GROUP BY l.id"
466 );
467
468 $statement->execute($params);
469
470 $rows = $statement->fetchAll();
471 } catch (\Exception $e) {
472 throw new QueryExecutionException('Unable to get data from ' . __CLASS__, $e->getCode(), $e);
473 }
474
475 $result = [];
476
477 foreach ($rows as $row) {
478 $result[$row['id']] = $row;
479 }
480
481 return $result;
482 }
483
484 /**
485 * Return an array of locations with the number of views for the given date period.
486 * Keys of the array are Locations IDs.
487 *
488 * @param $criteria
489 *
490 * @return array
491 * @throws QueryExecutionException
492 */
493 public function getAllNumberOfViews($criteria)
494 {
495 $params = [];
496
497 $where = [];
498
499 if ($criteria['dates']) {
500 $where[] = "(lv.date BETWEEN :bookingFrom AND :bookingTo)";
501
502 $params[':bookingFrom'] = explode(' ', $criteria['dates'][0])[0];
503
504 $params[':bookingTo'] = explode(' ', $criteria['dates'][1])[0];
505 }
506
507 if (isset($criteria['status'])) {
508 $where[] = 'l.status = :status';
509
510 $params[':status'] = $criteria['status'];
511 }
512
513 $where = $where ? 'WHERE ' . implode(' AND ', $where) : '';
514
515 try {
516 $statement = $this->connection->prepare(
517 "SELECT
518 l.id,
519 l.name,
520 SUM(lv.views) AS views
521 FROM {$this->table} l
522 INNER JOIN {$this->locationViewsTable} lv ON lv.locationId = l.id
523 $where
524 GROUP BY l.id"
525 );
526
527 $statement->execute($params);
528
529 $rows = $statement->fetchAll();
530 } catch (\Exception $e) {
531 throw new QueryExecutionException('Unable to get data from ' . __CLASS__, $e->getCode(), $e);
532 }
533
534 $result = [];
535
536 foreach ($rows as $row) {
537 $result[$row['id']] = $row;
538 }
539
540 return $result;
541 }
542
543 /**
544 * @param $locationId
545 *
546 * @return string
547 * @throws QueryExecutionException
548 */
549 public function addViewStats($locationId)
550 {
551 $date = DateTimeService::getNowDate();
552
553 $params = [
554 ':locationId' => $locationId,
555 ':date' => $date,
556 ':views' => 1
557 ];
558
559 try {
560 // Check if there is already data for this provider for this date
561 $statement = $this->connection->prepare(
562 "SELECT COUNT(*) AS count
563 FROM {$this->locationViewsTable} AS pv
564 WHERE pv.locationId = :locationId
565 AND pv.date = :date"
566 );
567
568 $statement->bindParam(':locationId', $locationId);
569 $statement->bindParam(':date', $date);
570 $statement->execute();
571 $count = $statement->fetch()['count'];
572
573 if (!$count) {
574 $statement = $this->connection->prepare(
575 "INSERT INTO {$this->locationViewsTable}
576 (`locationId`, `date`, `views`)
577 VALUES
578 (:locationId, :date, :views)"
579 );
580 } else {
581 $statement = $this->connection->prepare(
582 "UPDATE {$this->locationViewsTable} pv SET pv.views = pv.views + :views
583 WHERE pv.locationId = :locationId
584 AND pv.date = :date"
585 );
586 }
587
588 $response = $statement->execute($params);
589 } catch (\Exception $e) {
590 throw new QueryExecutionException('Unable to add data in ' . __CLASS__, $e->getCode(), $e);
591 }
592
593 if (!$response) {
594 throw new QueryExecutionException('Unable to add data in ' . __CLASS__);
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 return $statement->execute($params);
618 } catch (\Exception $e) {
619 throw new QueryExecutionException('Unable to delete data from ' . __CLASS__, $e->getCode(), $e);
620 }
621 }
622 }
623