1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
/* |
6
|
|
|
* This file is part of the Extension "sf_event_mgt" for TYPO3 CMS. |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please read the |
9
|
|
|
* LICENSE.txt file that was distributed with this source code. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace DERHANSEN\SfEventMgt\Service; |
13
|
|
|
|
14
|
|
|
use DateTime; |
15
|
|
|
use DERHANSEN\SfEventMgt\Domain\Model\Event; |
16
|
|
|
use DERHANSEN\SfEventMgt\Domain\Model\FrontendUser; |
17
|
|
|
use DERHANSEN\SfEventMgt\Domain\Model\Registration; |
18
|
|
|
use DERHANSEN\SfEventMgt\Domain\Repository\FrontendUserRepository; |
19
|
|
|
use DERHANSEN\SfEventMgt\Domain\Repository\RegistrationRepository; |
20
|
|
|
use DERHANSEN\SfEventMgt\Event\AfterRegistrationMovedFromWaitlist; |
21
|
|
|
use DERHANSEN\SfEventMgt\Event\ModifyCheckRegistrationSuccessEvent; |
22
|
|
|
use DERHANSEN\SfEventMgt\Payment\AbstractPayment; |
23
|
|
|
use DERHANSEN\SfEventMgt\Utility\MessageType; |
24
|
|
|
use DERHANSEN\SfEventMgt\Utility\RegistrationResult; |
25
|
|
|
use Psr\EventDispatcher\EventDispatcherInterface; |
26
|
|
|
use TYPO3\CMS\Core\Database\Connection; |
27
|
|
|
use TYPO3\CMS\Core\Database\ConnectionPool; |
28
|
|
|
use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction; |
29
|
|
|
use TYPO3\CMS\Core\Utility\GeneralUtility; |
30
|
|
|
use TYPO3\CMS\Extbase\Reflection\ObjectAccess; |
31
|
|
|
use TYPO3\CMS\Extbase\Security\Cryptography\HashService; |
32
|
|
|
|
33
|
|
|
class RegistrationService |
34
|
|
|
{ |
35
|
|
|
protected EventDispatcherInterface $eventDispatcher; |
36
|
|
|
protected RegistrationRepository $registrationRepository; |
37
|
|
|
protected FrontendUserRepository $frontendUserRepository; |
38
|
|
|
protected HashService $hashService; |
39
|
|
|
protected PaymentService $paymentService; |
40
|
|
|
protected NotificationService $notificationService; |
41
|
|
|
|
42
|
|
|
public function injectFrontendUserRepository(FrontendUserRepository $frontendUserRepository): void |
43
|
|
|
{ |
44
|
|
|
$this->frontendUserRepository = $frontendUserRepository; |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
public function injectHashService(HashService $hashService): void |
48
|
|
|
{ |
49
|
|
|
$this->hashService = $hashService; |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
public function injectNotificationService(NotificationService $notificationService): void |
53
|
|
|
{ |
54
|
|
|
$this->notificationService = $notificationService; |
55
|
|
|
} |
56
|
|
|
|
57
|
|
|
public function injectEventDispatcher(EventDispatcherInterface $eventDispatcher): void |
58
|
|
|
{ |
59
|
|
|
$this->eventDispatcher = $eventDispatcher; |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
public function injectPaymentService(PaymentService $paymentService): void |
63
|
|
|
{ |
64
|
|
|
$this->paymentService = $paymentService; |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
public function injectRegistrationRepository(RegistrationRepository $registrationRepository): void |
68
|
|
|
{ |
69
|
|
|
$this->registrationRepository = $registrationRepository; |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* Duplicates the given registration (all public accessible properties) the |
74
|
|
|
* amount of times configured in amountOfRegistrations |
75
|
|
|
*/ |
76
|
|
|
public function createDependingRegistrations(Registration $registration): void |
77
|
|
|
{ |
78
|
|
|
$registrations = $registration->getAmountOfRegistrations(); |
79
|
|
|
for ($i = 1; $i <= $registrations - 1; $i++) { |
80
|
|
|
$newReg = GeneralUtility::makeInstance(Registration::class); |
81
|
|
|
$properties = ObjectAccess::getGettableProperties($registration); |
82
|
|
|
foreach ($properties as $propertyName => $propertyValue) { |
83
|
|
|
ObjectAccess::setProperty($newReg, $propertyName, $propertyValue); |
84
|
|
|
} |
85
|
|
|
$newReg->setMainRegistration($registration); |
86
|
|
|
$newReg->setAmountOfRegistrations(1); |
87
|
|
|
$newReg->setIgnoreNotifications(true); |
88
|
|
|
$this->registrationRepository->add($newReg); |
89
|
|
|
} |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* Confirms all depending registrations based on the given main registration |
94
|
|
|
*/ |
95
|
|
|
public function confirmDependingRegistrations(Registration $registration): void |
96
|
|
|
{ |
97
|
|
|
$registrations = $this->registrationRepository->findByMainRegistration($registration); |
|
|
|
|
98
|
|
|
foreach ($registrations as $foundRegistration) { |
99
|
|
|
/** @var Registration $foundRegistration */ |
100
|
|
|
$foundRegistration->setConfirmed(true); |
101
|
|
|
$this->registrationRepository->update($foundRegistration); |
102
|
|
|
} |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* Checks if the registration can be confirmed and returns an array of variables |
107
|
|
|
*/ |
108
|
|
|
public function checkConfirmRegistration(int $regUid, string $hmac): array |
109
|
|
|
{ |
110
|
|
|
/* @var $registration Registration */ |
111
|
|
|
$registration = null; |
112
|
|
|
$failed = false; |
113
|
|
|
$messageKey = 'event.message.confirmation_successful'; |
114
|
|
|
$titleKey = 'confirmRegistration.title.successful'; |
115
|
|
|
|
116
|
|
|
if (!$this->hashService->validateHmac('reg-' . $regUid, $hmac)) { |
117
|
|
|
$failed = true; |
118
|
|
|
$messageKey = 'event.message.confirmation_failed_wrong_hmac'; |
119
|
|
|
$titleKey = 'confirmRegistration.title.failed'; |
120
|
|
|
} else { |
121
|
|
|
$registration = $this->registrationRepository->findByUid($regUid); |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
if (!$failed && is_null($registration)) { |
125
|
|
|
$failed = true; |
126
|
|
|
$messageKey = 'event.message.confirmation_failed_registration_not_found'; |
127
|
|
|
$titleKey = 'confirmRegistration.title.failed'; |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
if (!$failed && !$registration->getEvent()) { |
131
|
|
|
$failed = true; |
132
|
|
|
$messageKey = 'event.message.confirmation_failed_registration_event_not_found'; |
133
|
|
|
$titleKey = 'confirmRegistration.title.failed'; |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
if (!$failed && $registration->getConfirmationUntil() < new DateTime()) { |
137
|
|
|
$failed = true; |
138
|
|
|
$messageKey = 'event.message.confirmation_failed_confirmation_until_expired'; |
139
|
|
|
$titleKey = 'confirmRegistration.title.failed'; |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
if (!$failed && $registration->getConfirmed() === true) { |
143
|
|
|
$failed = true; |
144
|
|
|
$messageKey = 'event.message.confirmation_failed_already_confirmed'; |
145
|
|
|
$titleKey = 'confirmRegistration.title.failed'; |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
if (!$failed && $registration->getWaitlist()) { |
149
|
|
|
$messageKey = 'event.message.confirmation_waitlist_successful'; |
150
|
|
|
$titleKey = 'confirmRegistrationWaitlist.title.successful'; |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
return [ |
154
|
|
|
$failed, |
155
|
|
|
$registration, |
156
|
|
|
$messageKey, |
157
|
|
|
$titleKey, |
158
|
|
|
]; |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
/** |
162
|
|
|
* Cancels all depending registrations based on the given main registration |
163
|
|
|
*/ |
164
|
|
|
public function cancelDependingRegistrations(Registration $registration): void |
165
|
|
|
{ |
166
|
|
|
$registrations = $this->registrationRepository->findByMainRegistration($registration); |
|
|
|
|
167
|
|
|
foreach ($registrations as $foundRegistration) { |
168
|
|
|
$this->registrationRepository->remove($foundRegistration); |
169
|
|
|
} |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* Checks if the registration can be cancelled and returns an array of variables |
174
|
|
|
*/ |
175
|
|
|
public function checkCancelRegistration(int $regUid, string $hmac): array |
176
|
|
|
{ |
177
|
|
|
/* @var $registration Registration */ |
178
|
|
|
$registration = null; |
179
|
|
|
$failed = false; |
180
|
|
|
$messageKey = 'event.message.cancel_successful'; |
181
|
|
|
$titleKey = 'cancelRegistration.title.successful'; |
182
|
|
|
|
183
|
|
|
if (!$this->hashService->validateHmac('reg-' . $regUid, $hmac)) { |
184
|
|
|
$failed = true; |
185
|
|
|
$messageKey = 'event.message.cancel_failed_wrong_hmac'; |
186
|
|
|
$titleKey = 'cancelRegistration.title.failed'; |
187
|
|
|
} else { |
188
|
|
|
$registration = $this->registrationRepository->findByUid($regUid); |
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
if (!$failed && is_null($registration)) { |
192
|
|
|
$failed = true; |
193
|
|
|
$messageKey = 'event.message.cancel_failed_registration_not_found_or_cancelled'; |
194
|
|
|
$titleKey = 'cancelRegistration.title.failed'; |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
if (!$failed && !is_a($registration->getEvent(), Event::class)) { |
198
|
|
|
$failed = true; |
199
|
|
|
$messageKey = 'event.message.cancel_failed_event_not_found'; |
200
|
|
|
$titleKey = 'cancelRegistration.title.failed'; |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
if (!$failed && $registration->getEvent()->getEnableCancel() === false) { |
204
|
|
|
$failed = true; |
205
|
|
|
$messageKey = 'event.message.confirmation_failed_cancel_disabled'; |
206
|
|
|
$titleKey = 'cancelRegistration.title.failed'; |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
if (!$failed && $registration->getEvent()->getCancelDeadline() !== null |
210
|
|
|
&& $registration->getEvent()->getCancelDeadline() < new DateTime() |
211
|
|
|
) { |
212
|
|
|
$failed = true; |
213
|
|
|
$messageKey = 'event.message.cancel_failed_deadline_expired'; |
214
|
|
|
$titleKey = 'cancelRegistration.title.failed'; |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
if (!$failed && $registration->getEvent()->getStartdate() < new DateTime()) { |
218
|
|
|
$failed = true; |
219
|
|
|
$messageKey = 'event.message.cancel_failed_event_started'; |
220
|
|
|
$titleKey = 'cancelRegistration.title.failed'; |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
return [ |
224
|
|
|
$failed, |
225
|
|
|
$registration, |
226
|
|
|
$messageKey, |
227
|
|
|
$titleKey, |
228
|
|
|
]; |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
/** |
232
|
|
|
* Returns the current frontend user object if available |
233
|
|
|
*/ |
234
|
|
|
public function getCurrentFeUserObject(): ?FrontendUser |
235
|
|
|
{ |
236
|
|
|
$user = null; |
237
|
|
|
|
238
|
|
|
if (isset($GLOBALS['TSFE']->fe_user->user['uid'])) { |
239
|
|
|
/** @var FrontendUser $user */ |
240
|
|
|
$user = $this->frontendUserRepository->findByUid($GLOBALS['TSFE']->fe_user->user['uid']); |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
return $user; |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
/** |
247
|
|
|
* Checks, if the registration can successfully be created. |
248
|
|
|
*/ |
249
|
|
|
public function checkRegistrationSuccess(Event $event, Registration $registration, int $result): array |
250
|
|
|
{ |
251
|
|
|
$success = true; |
252
|
|
|
if ($event->getEnableRegistration() === false) { |
253
|
|
|
$success = false; |
254
|
|
|
$result = RegistrationResult::REGISTRATION_NOT_ENABLED; |
255
|
|
|
} elseif ($event->getRegistrationDeadline() != null && $event->getRegistrationDeadline() < new DateTime()) { |
256
|
|
|
$success = false; |
257
|
|
|
$result = RegistrationResult::REGISTRATION_FAILED_DEADLINE_EXPIRED; |
258
|
|
|
} elseif ($event->getStartdate() < new DateTime()) { |
259
|
|
|
$success = false; |
260
|
|
|
$result = RegistrationResult::REGISTRATION_FAILED_EVENT_EXPIRED; |
261
|
|
|
} elseif ($event->getRegistrations()->count() >= $event->getMaxParticipants() |
262
|
|
|
&& $event->getMaxParticipants() > 0 && !$event->getEnableWaitlist() |
263
|
|
|
) { |
264
|
|
|
$success = false; |
265
|
|
|
$result = RegistrationResult::REGISTRATION_FAILED_MAX_PARTICIPANTS; |
266
|
|
|
} elseif ($event->getFreePlaces() < $registration->getAmountOfRegistrations() |
267
|
|
|
&& $event->getMaxParticipants() > 0 && !$event->getEnableWaitlist() |
268
|
|
|
) { |
269
|
|
|
$success = false; |
270
|
|
|
$result = RegistrationResult::REGISTRATION_FAILED_NOT_ENOUGH_FREE_PLACES; |
271
|
|
|
} elseif ($event->getMaxRegistrationsPerUser() < $registration->getAmountOfRegistrations()) { |
272
|
|
|
$success = false; |
273
|
|
|
$result = RegistrationResult::REGISTRATION_FAILED_MAX_AMOUNT_REGISTRATIONS_EXCEEDED; |
274
|
|
|
} elseif ($event->getUniqueEmailCheck() && |
275
|
|
|
$this->emailNotUnique($event, $registration->getEmail()) |
276
|
|
|
) { |
277
|
|
|
$success = false; |
278
|
|
|
$result = RegistrationResult::REGISTRATION_FAILED_EMAIL_NOT_UNIQUE; |
279
|
|
|
} elseif ($event->getRegistrations()->count() >= $event->getMaxParticipants() |
280
|
|
|
&& $event->getMaxParticipants() > 0 && $event->getEnableWaitlist() |
281
|
|
|
) { |
282
|
|
|
$result = RegistrationResult::REGISTRATION_SUCCESSFUL_WAITLIST; |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
$modifyCheckRegistrationSuccessEvent = new ModifyCheckRegistrationSuccessEvent($success, $result); |
286
|
|
|
$this->eventDispatcher->dispatch($modifyCheckRegistrationSuccessEvent); |
287
|
|
|
|
288
|
|
|
return [$modifyCheckRegistrationSuccessEvent->getSuccess(), $modifyCheckRegistrationSuccessEvent->getResult()]; |
289
|
|
|
} |
290
|
|
|
|
291
|
|
|
/** |
292
|
|
|
* Returns if the given email is registered to the given event |
293
|
|
|
*/ |
294
|
|
|
protected function emailNotUnique(Event $event, string $email): bool |
295
|
|
|
{ |
296
|
|
|
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) |
297
|
|
|
->getQueryBuilderForTable('tx_sfeventmgt_domain_model_registration'); |
298
|
|
|
$queryBuilder->getRestrictions()->removeByType(HiddenRestriction::class); |
299
|
|
|
$registrations = $queryBuilder->count('email') |
300
|
|
|
->from('tx_sfeventmgt_domain_model_registration') |
301
|
|
|
->where( |
302
|
|
|
$queryBuilder->expr()->eq( |
303
|
|
|
'event', |
304
|
|
|
$queryBuilder->createNamedParameter($event->getUid(), Connection::PARAM_INT) |
305
|
|
|
), |
306
|
|
|
$queryBuilder->expr()->eq( |
307
|
|
|
'email', |
308
|
|
|
$queryBuilder->createNamedParameter($email, Connection::PARAM_STR) |
309
|
|
|
) |
310
|
|
|
) |
311
|
|
|
->executeQuery() |
312
|
|
|
->fetchOne(); |
313
|
|
|
|
314
|
|
|
return $registrations >= 1; |
315
|
|
|
} |
316
|
|
|
|
317
|
|
|
/** |
318
|
|
|
* Returns, if payment redirect for the payment method is enabled |
319
|
|
|
*/ |
320
|
|
|
public function redirectPaymentEnabled(Registration $registration): bool |
321
|
|
|
{ |
322
|
|
|
if ($registration->getEvent()->getEnablePayment() === false) { |
323
|
|
|
return false; |
324
|
|
|
} |
325
|
|
|
|
326
|
|
|
/** @var AbstractPayment $paymentInstance */ |
327
|
|
|
$paymentInstance = $this->paymentService->getPaymentInstance($registration->getPaymentmethod()); |
328
|
|
|
|
329
|
|
|
return $paymentInstance !== null && $paymentInstance->isRedirectEnabled(); |
330
|
|
|
} |
331
|
|
|
|
332
|
|
|
/** |
333
|
|
|
* Returns if the given amount of registrations for the event will be registrations for the waitlist |
334
|
|
|
* (depending on the total amount of registrations and free places) |
335
|
|
|
*/ |
336
|
|
|
public function isWaitlistRegistration(Event $event, int $amountOfRegistrations): bool |
337
|
|
|
{ |
338
|
|
|
if ($event->getMaxParticipants() === 0 || !$event->getEnableWaitlist()) { |
339
|
|
|
return false; |
340
|
|
|
} |
341
|
|
|
|
342
|
|
|
$result = false; |
343
|
|
|
if (($event->getFreePlaces() > 0 && $event->getFreePlaces() < $amountOfRegistrations) |
344
|
|
|
|| $event->getFreePlaces() <= 0) { |
345
|
|
|
$result = true; |
346
|
|
|
} |
347
|
|
|
|
348
|
|
|
return $result; |
349
|
|
|
} |
350
|
|
|
|
351
|
|
|
/** |
352
|
|
|
* Handles the process of moving registration up from the waitlist. |
353
|
|
|
*/ |
354
|
|
|
public function moveUpWaitlistRegistrations(Event $event, array $settings): void |
355
|
|
|
{ |
356
|
|
|
// Early return if move up not enabled, no registrations on waitlist or no free places left |
357
|
|
|
if (!$event->getEnableWaitlistMoveup() || $event->getRegistrationsWaitlist()->count() === 0 || |
358
|
|
|
$event->getFreePlaces() === 0 |
359
|
|
|
) { |
360
|
|
|
return; |
361
|
|
|
} |
362
|
|
|
|
363
|
|
|
$keepMainRegistrationDependency = $settings['waitlist']['moveUp']['keepMainRegistrationDependency'] ?? false; |
364
|
|
|
$freePlaces = $event->getFreePlaces(); |
365
|
|
|
$moveupRegistrations = $this->registrationRepository->findWaitlistMoveUpRegistrations($event); |
366
|
|
|
|
367
|
|
|
/** @var Registration $registration */ |
368
|
|
|
foreach ($moveupRegistrations as $registration) { |
369
|
|
|
$registration->setWaitlist(false); |
370
|
|
|
$registration->setIgnoreNotifications(false); |
371
|
|
|
|
372
|
|
|
if (!(bool)$keepMainRegistrationDependency) { |
373
|
|
|
$registration->_setProperty('mainRegistration', null); |
374
|
|
|
} |
375
|
|
|
|
376
|
|
|
$this->registrationRepository->update($registration); |
377
|
|
|
|
378
|
|
|
// Send messages to user and admin |
379
|
|
|
$this->notificationService->sendUserMessage( |
380
|
|
|
$event, |
381
|
|
|
$registration, |
382
|
|
|
$settings, |
383
|
|
|
MessageType::REGISTRATION_WAITLIST_MOVE_UP |
384
|
|
|
); |
385
|
|
|
$this->notificationService->sendAdminMessage( |
386
|
|
|
$registration->getEvent(), |
387
|
|
|
$registration, |
388
|
|
|
$settings, |
389
|
|
|
MessageType::REGISTRATION_WAITLIST_MOVE_UP |
390
|
|
|
); |
391
|
|
|
|
392
|
|
|
$this->eventDispatcher->dispatch(new AfterRegistrationMovedFromWaitlist($registration, $this)); |
393
|
|
|
|
394
|
|
|
$freePlaces--; |
395
|
|
|
if ($freePlaces === 0) { |
396
|
|
|
break; |
397
|
|
|
} |
398
|
|
|
} |
399
|
|
|
} |
400
|
|
|
} |
401
|
|
|
|
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.