Passed
Push — main ( 7c0335...555ab4 )
by Torben
03:29
created

RegistrationService::checkConfirmRegistration()   C

Complexity

Conditions 12
Paths 64

Size

Total Lines 50
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 34
nc 64
nop 2
dl 0
loc 50
rs 6.9666
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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);
0 ignored issues
show
Deprecated Code introduced by
The function DERHANSEN\SfEventMgt\Dom...ionRepository::__call() has been deprecated: since v12, will be removed in v14, use {@see findBy}, {@see findOneBy} and {@see count} instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

97
        $registrations = /** @scrutinizer ignore-deprecated */ $this->registrationRepository->findByMainRegistration($registration);

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.

Loading history...
Bug introduced by
The method findByMainRegistration() does not exist on DERHANSEN\SfEventMgt\Dom...\RegistrationRepository. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

97
        /** @scrutinizer ignore-call */ 
98
        $registrations = $this->registrationRepository->findByMainRegistration($registration);
Loading history...
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);
0 ignored issues
show
Deprecated Code introduced by
The function DERHANSEN\SfEventMgt\Dom...ionRepository::__call() has been deprecated: since v12, will be removed in v14, use {@see findBy}, {@see findOneBy} and {@see count} instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

166
        $registrations = /** @scrutinizer ignore-deprecated */ $this->registrationRepository->findByMainRegistration($registration);

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.

Loading history...
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