PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 2.3
Booking for Appointments and Events Calendar – Amelia v2.3
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 / User / CustomerRepository.php
ameliabooking / src / Infrastructure / Repository / User Last commit date
CustomerRepository.php 3 months ago ProviderRepository.php 2 months ago UserRepository.php 2 months ago WPUserRepository.php 3 months ago
CustomerRepository.php
414 lines
1 <?php
2
3 namespace AmeliaBooking\Infrastructure\Repository\User;
4
5 use AmeliaBooking\Domain\Collection\Collection;
6 use AmeliaBooking\Domain\Common\Exceptions\InvalidArgumentException;
7 use AmeliaBooking\Domain\Entity\User\AbstractUser;
8 use AmeliaBooking\Domain\Repository\User\CustomerRepositoryInterface;
9 use AmeliaBooking\Domain\Services\DateTime\DateTimeService;
10 use AmeliaBooking\Domain\ValueObjects\String\BookingStatus;
11 use AmeliaBooking\Domain\ValueObjects\String\Status;
12 use AmeliaBooking\Infrastructure\Common\Exceptions\QueryExecutionException;
13 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Bookable\PackagesCustomersTable;
14 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Booking\AppointmentsTable;
15 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Booking\CustomerBookingsTable;
16 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Booking\CustomerBookingsToEventsPeriodsTable;
17 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Booking\EventsPeriodsTable;
18 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\User\WPUsersTable;
19
20 /**
21 * Class UserRepository
22 *
23 * @package AmeliaBooking\Infrastructure\Repository
24 */
25 class CustomerRepository extends UserRepository implements CustomerRepositoryInterface
26 {
27 /**
28 * @param $criteria
29 * @param int $itemsPerPage
30 *
31 * @return array
32 * @throws QueryExecutionException
33 * @throws \Exception
34 */
35 public function getFiltered($criteria, $itemsPerPage = null)
36 {
37 try {
38 $wpUserTable = WPUsersTable::getTableName();
39 $bookingsTable = CustomerBookingsTable::getTableName();
40 $appointmentsTable = AppointmentsTable::getTableName();
41 $eventsPeriodsTable = EventsPeriodsTable::getTableName();
42 $bookingsEventsPeriodsTable = CustomerBookingsToEventsPeriodsTable::getTableName();
43 $packagesCustomersTable = PackagesCustomersTable::getTableName();
44
45 $params = [
46 ':type_customer' => AbstractUser::USER_ROLE_CUSTOMER,
47 ':type_admin' => AbstractUser::USER_ROLE_ADMIN,
48 ];
49
50 $joinWithBookings = empty($criteria['ignoredBookings']);
51
52 $where = [
53 'u.type IN (:type_customer, :type_admin)',
54 ];
55
56 $order = '';
57 if (!empty($criteria['sort'])) {
58 $column = $criteria['sort'][0] === '-' ? substr($criteria['sort'], 1) : $criteria['sort'];
59 $orderColumn = $column === 'customer' ? 'CONCAT(u.firstName, " ", u.lastName)' : 'lastBooking';
60 $orderDirection = $criteria['sort'][0] === '-' ? 'DESC' : 'ASC';
61 $order = "ORDER BY {$orderColumn} {$orderDirection}";
62
63 $joinWithBookings = $column !== 'customer' || $joinWithBookings;
64 }
65
66 if (!empty($criteria['search'])) {
67 $terms = preg_split('/\s+/', trim($criteria['search']));
68 $termIndex = 0;
69
70 foreach ($terms as $term) {
71 $param = ":search{$termIndex}";
72 $params[$param] = "%{$term}%";
73
74 $where[] = "(
75 u.firstName LIKE {$param}
76 OR u.lastName LIKE {$param}
77 OR u.email LIKE {$param}
78 OR u.phone LIKE {$param}
79 OR u.note LIKE {$param}
80 OR wpu.display_name LIKE {$param}
81 OR u.id LIKE {$param}
82 )";
83
84 $termIndex++;
85 }
86 }
87
88 if (!empty($criteria['customers'])) {
89 $customersCriteria = [];
90
91 foreach ((array)$criteria['customers'] as $key => $customerId) {
92 $params[":customerId$key"] = $customerId;
93 $customersCriteria[] = ":customerId$key";
94 }
95
96 $where[] = 'u.id IN (' . implode(', ', $customersCriteria) . ')';
97 }
98
99 $statsFields = '
100 NULL as lastBooking,
101 NULL as lastAppointment,
102 NULL as lastEvent,
103 0 as totalBookings,
104 0 as countPendingAppointments,
105 0 as countAppointmentBookings,
106 0 as countEventBookings,
107 ';
108
109 $statsJoins = '';
110
111 $having = '';
112
113 if ($joinWithBookings) {
114 $params[':bookingPendingStatus'] = BookingStatus::PENDING;
115
116 $statsFields = "
117 COALESCE(GREATEST(MAX(app.bookingStart), MAX(ep.periodStart)),
118 MAX(app.bookingStart), MAX(ep.periodStart), MAX(pc.purchased)) as lastBooking,
119 MAX(app.bookingStart) as lastAppointment,
120 MAX(ep.periodStart) as lastEvent,
121 MAX(pc.purchased) as lastPackage,
122 COUNT(DISTINCT cb.id) as totalBookings,
123 SUM(case when cb.status = :bookingPendingStatus then 1 else 0 end) as countPendingAppointments,
124 COUNT(DISTINCT CASE WHEN cb.appointmentId IS NOT NULL THEN cb.id ELSE NULL END) as countAppointmentBookings,
125 COUNT(DISTINCT CASE WHEN cb.appointmentId IS NULL THEN cb.id ELSE NULL END) as countEventBookings,
126 COUNT(pc.customerId) as countPackagePurchases,
127 ";
128
129 $statsJoins = "
130 LEFT JOIN {$bookingsTable} cb ON u.id = cb.customerId
131 LEFT JOIN {$appointmentsTable} app ON app.id = cb.appointmentId
132 LEFT JOIN {$bookingsEventsPeriodsTable} bep ON bep.customerBookingId = cb.id
133 LEFT JOIN {$eventsPeriodsTable} ep ON ep.id = bep.eventPeriodId
134 LEFT JOIN {$packagesCustomersTable} pc ON pc.customerId = u.id
135 ";
136
137 if (!empty($criteria['noShow'])) {
138 $having = "HAVING (";
139 foreach ($criteria['noShow'] as $index => $noShowId) {
140 $param = ':noShow' . $index;
141 $params[$param] = $noShowId;
142 $having .= ($index === 0 ? "" : " OR ") . "(COUNT(DISTINCT CASE WHEN cb.status = 'no-show' THEN cb.id ELSE NULL END) " .
143 ($noShowId === "3" ? '>=' : '=') . " " . $param . ")";
144 }
145 $having .= ")";
146 }
147 }
148
149 $where = $where ? 'WHERE ' . implode(' AND ', $where) : '';
150
151 $limit = $this->getLimit(
152 !empty($criteria['page']) ? (int)$criteria['page'] : 0,
153 (int)$itemsPerPage
154 );
155
156 $statement = $this->connection->prepare(
157 "SELECT
158 u.id as id,
159 u.status as status,
160 u.firstName as firstName,
161 u.lastName as lastName,
162 u.email as email,
163 u.phone as phone,
164 u.countryPhoneIso AS countryPhoneIso,
165 u.gender as gender,
166 u.externalId as externalId,
167 u.translations as translations,
168 IF(u.birthday IS NOT NULL, u.birthday , '') as birthday,
169 u.note as note,
170 u.customFields as customFields,
171 {$statsFields}
172 IF(wpu.display_name IS NOT NULL, wpu.display_name , '') as wpName
173 FROM {$this->table} as u
174 LEFT JOIN {$wpUserTable} wpu ON u.externalId = wpu.id
175 {$statsJoins}
176 {$where}
177 GROUP BY u.id
178 {$having}
179 {$order}
180 {$limit}"
181 );
182
183 $statement->execute($params);
184
185 $rows = $statement->fetchAll();
186 } catch (\Exception $e) {
187 throw new QueryExecutionException('Unable to get data from ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
188 }
189
190 $items = [];
191 foreach ($rows as $row) {
192 $row['id'] = (int)$row['id'];
193 $row['externalId'] = $row['externalId'] === null ? $row['externalId'] : (int)$row['externalId'];
194 $row['lastBooking'] = !empty($row['lastBooking']) ? DateTimeService::getCustomDateTimeFromUtc($row['lastBooking']) : $row['lastBooking'];
195 $row['lastAppointment'] = !empty($row['lastAppointment']) ?
196 DateTimeService::getCustomDateTimeFromUtc($row['lastAppointment']) :
197 $row['lastAppointment'];
198 $row['lastEvent'] = !empty($row['lastEvent']) ? DateTimeService::getCustomDateTimeFromUtc($row['lastEvent']) : $row['lastEvent'];
199 $row['lastPackage'] = !empty($row['lastPackage']) ? DateTimeService::getCustomDateTimeFromUtc($row['lastPackage']) : null;
200
201 $row['totalBookings'] = (int)$row['totalBookings'];
202 $row['totalAppointments'] = (int)$row['countAppointmentBookings'];
203 $row['totalEvents'] = (int)$row['countEventBookings'];
204 $row['totalPackages'] = !empty($row['countPackagePurchases']) ? (int)$row['countPackagePurchases'] : 0;
205
206 // Fix for customFields being encoded multiple times
207 if ($row['customFields'] && !is_array(json_decode($row['customFields'], true))) {
208 $row['customFields'] = null;
209 }
210
211 $items[$row['id']] = $row;
212 }
213
214 return $items;
215 }
216
217 /**
218 * @param $criteria
219 *
220 * @return mixed
221 * @throws QueryExecutionException
222 */
223 public function getCount($criteria)
224 {
225 $wpUserTable = WPUsersTable::getTableName();
226
227 $params = [
228 ':type_customer' => AbstractUser::USER_ROLE_CUSTOMER,
229 ':type_admin' => AbstractUser::USER_ROLE_ADMIN,
230 ];
231
232 $where = [
233 'u.type IN (:type_customer, :type_admin)',
234 ];
235
236 if (!empty($criteria['search'])) {
237 $terms = preg_split('/\s+/', trim($criteria['search']));
238 $termIndex = 0;
239
240 foreach ($terms as $term) {
241 $param = ":search{$termIndex}";
242 $params[$param] = "%{$term}%";
243
244 $where[] = "(
245 u.firstName LIKE {$param}
246 OR u.lastName LIKE {$param}
247 OR u.email LIKE {$param}
248 OR u.phone LIKE {$param}
249 OR u.note LIKE {$param}
250 OR wpu.display_name LIKE {$param}
251 OR u.id LIKE {$param}
252 )";
253
254 $termIndex++;
255 }
256 }
257
258 if (!empty($criteria['customers'])) {
259 $customersCriteria = [];
260
261 foreach ((array)$criteria['customers'] as $key => $customerId) {
262 $params[":customerId$key"] = $customerId;
263 $customersCriteria[] = ":customerId$key";
264 }
265
266 $where[] = 'u.id IN (' . implode(', ', $customersCriteria) . ')';
267 }
268
269 if (!empty($criteria['noShow'])) {
270 $bookingsTable = CustomerBookingsTable::getTableName();
271
272 $noShowWhere = "exists (SELECT COUNT(*) as c FROM {$bookingsTable} cb WHERE cb.status='no-show' AND cb.customerId=u.id HAVING ";
273
274 foreach ($criteria['noShow'] as $index => $noShowId) {
275 $param = ':noShow' . $index;
276 $params[$param] = $noShowId;
277 $noShowWhere .= ($index === 0 ? "" : " OR ") . "c " . ($noShowId === "3" ? '>=' : '=') . $param;
278 }
279 $noShowWhere .= ")";
280
281 $where[] = $noShowWhere;
282 }
283
284 $where = $where ? 'WHERE ' . implode(' AND ', $where) : '';
285
286 try {
287 $statement = $this->connection->prepare(
288 "SELECT COUNT(*) as count
289 FROM {$this->table} as u
290 LEFT JOIN {$wpUserTable} wpu ON u.externalId = wpu.id
291 $where
292 "
293 );
294
295 $statement->execute($params);
296
297 $rows = $statement->fetch()['count'];
298 } catch (\Exception $e) {
299 throw new QueryExecutionException('Unable to get data from ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
300 }
301
302 return $rows;
303 }
304
305 /**
306 * @param string $phone
307 *
308 * @return array
309 * @throws QueryExecutionException
310 * @throws \Exception
311 */
312 public function getByPhoneNumber($phone)
313 {
314 try {
315 $params[':phone'] = '+' . $phone;
316
317 $statement = $this->connection->prepare(
318 "SELECT
319 u.id as id,
320 u.status as status,
321 u.firstName as firstName,
322 u.lastName as lastName,
323 u.email as email,
324 u.phone as phone,
325 u.countryPhoneIso AS countryPhoneIso,
326 u.gender as gender,
327 u.externalId as externalId,
328 IF(u.birthday IS NOT NULL, u.birthday , '') as birthday,
329 u.note as note
330 FROM {$this->table} as u
331 WHERE u.type = 'customer' AND phone = :phone"
332 );
333
334 $statement->execute($params);
335
336 $rows = $statement->fetchAll();
337 } catch (\Exception $e) {
338 throw new QueryExecutionException('Unable to get data from ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
339 }
340
341 return $rows;
342 }
343
344 /**
345 * @param array $criteria
346 *
347 * @return Collection
348 * @throws QueryExecutionException
349 * @throws InvalidArgumentException
350 * @throws InvalidArgumentException
351 */
352 public function getByCriteria($criteria = [])
353 {
354 $params = [];
355
356 $where = [];
357
358 $fields = '
359 u.id AS id,
360 u.type AS type,
361 u.firstName AS firstName,
362 u.lastName AS lastName,
363 u.email AS email,
364 u.note AS note,
365 u.phone AS phone,
366 u.countryPhoneIso AS countryPhoneIso,
367 u.gender AS gender,
368 u.birthday AS birthday,
369 u.status AS status
370 ';
371
372 if (!empty($criteria['ids'])) {
373 $queryIds = [];
374
375 foreach ($criteria['ids'] as $index => $value) {
376 $param = ':id' . $index;
377
378 $queryIds[] = $param;
379
380 $params[$param] = $value;
381 }
382
383 $where[] = 'u.id IN (' . implode(', ', $queryIds) . ')';
384 }
385
386 $where = $where ? 'WHERE ' . implode(' AND ', $where) : '';
387
388 try {
389 $statement = $this->connection->prepare(
390 "SELECT
391 {$fields}
392 FROM {$this->table} u
393 {$where}"
394 );
395
396 $statement->execute($params);
397
398 $rows = $statement->fetchAll();
399 } catch (\Exception $e) {
400 throw new QueryExecutionException('Unable to find event by id in ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
401 }
402
403 $items = new Collection();
404
405 foreach ($rows as $row) {
406 $row['type'] = 'customer';
407
408 $items->addItem(call_user_func([static::FACTORY, 'create'], $row), $row['id']);
409 }
410
411 return $items;
412 }
413 }
414