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