Passed
Push — 6.x ( 32235c...0713bf )
by Torben
08:10
created

RegistrationService::checkRegistrationSuccess()   D

Complexity

Conditions 21
Paths 10

Size

Total Lines 40
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 21
eloc 32
nc 10
nop 3
dl 0
loc 40
rs 4.1666
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 DERHANSEN\SfEventMgt\Domain\Model\Event;
15
use DERHANSEN\SfEventMgt\Domain\Model\FrontendUser;
16
use DERHANSEN\SfEventMgt\Domain\Model\Registration;
17
use DERHANSEN\SfEventMgt\Domain\Repository\FrontendUserRepository;
18
use DERHANSEN\SfEventMgt\Domain\Repository\RegistrationRepository;
19
use DERHANSEN\SfEventMgt\Event\AfterRegistrationMovedFromWaitlist;
20
use DERHANSEN\SfEventMgt\Payment\AbstractPayment;
21
use DERHANSEN\SfEventMgt\Utility\MessageType;
22
use DERHANSEN\SfEventMgt\Utility\RegistrationResult;
23
use Psr\EventDispatcher\EventDispatcherInterface;
24
use TYPO3\CMS\Core\Database\Connection;
25
use TYPO3\CMS\Core\Database\ConnectionPool;
26
use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction;
27
use TYPO3\CMS\Core\Utility\GeneralUtility;
28
use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
29
use TYPO3\CMS\Extbase\Security\Cryptography\HashService;
30
31
/**
32
 * RegistrationService
33
 */
34
class RegistrationService
35
{
36
    protected EventDispatcherInterface $eventDispatcher;
37
    protected RegistrationRepository $registrationRepository;
38
    protected FrontendUserRepository $frontendUserRepository;
39
    protected HashService $hashService;
40
    protected PaymentService $paymentService;
41
    protected NotificationService $notificationService;
42
43
    public function injectFrontendUserRepository(FrontendUserRepository $frontendUserRepository): void
44
    {
45
        $this->frontendUserRepository = $frontendUserRepository;
46
    }
47
48
    public function injectHashService(HashService $hashService): void
49
    {
50
        $this->hashService = $hashService;
51
    }
52
53
    public function injectNotificationService(NotificationService $notificationService): void
54
    {
55
        $this->notificationService = $notificationService;
56
    }
57
58
    public function injectEventDispatcher(EventDispatcherInterface $eventDispatcher): void
59
    {
60
        $this->eventDispatcher = $eventDispatcher;
61
    }
62
63
    public function injectPaymentService(PaymentService $paymentService): void
64
    {
65
        $this->paymentService = $paymentService;
66
    }
67
68
    public function injectRegistrationRepository(RegistrationRepository $registrationRepository): void
69
    {
70
        $this->registrationRepository = $registrationRepository;
71
    }
72
73
    /**
74
     * Duplicates (all public accessable properties) the given registration the
75
     * amount of times configured in amountOfRegistrations
76
     */
77
    public function createDependingRegistrations(Registration $registration): void
78
    {
79
        $registrations = $registration->getAmountOfRegistrations();
80
        for ($i = 1; $i <= $registrations - 1; $i++) {
81
            $newReg = GeneralUtility::makeInstance(Registration::class);
82
            $properties = ObjectAccess::getGettableProperties($registration);
83
            foreach ($properties as $propertyName => $propertyValue) {
84
                ObjectAccess::setProperty($newReg, $propertyName, $propertyValue);
85
            }
86
            $newReg->setMainRegistration($registration);
87
            $newReg->setAmountOfRegistrations(1);
88
            $newReg->setIgnoreNotifications(true);
89
            $this->registrationRepository->add($newReg);
90
        }
91
    }
92
93
    /**
94
     * Confirms all depending registrations based on the given main registration
95
     */
96
    public function confirmDependingRegistrations(Registration $registration): void
97
    {
98
        $registrations = $this->registrationRepository->findByMainRegistration($registration);
0 ignored issues
show
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

98
        /** @scrutinizer ignore-call */ 
99
        $registrations = $this->registrationRepository->findByMainRegistration($registration);
Loading history...
99
        foreach ($registrations as $foundRegistration) {
100
            /** @var Registration $foundRegistration */
101
            $foundRegistration->setConfirmed(true);
102
            $this->registrationRepository->update($foundRegistration);
103
        }
104
    }
105
106
    /**
107
     * Checks if the registration can be confirmed and returns an array of variables
108
     */
109
    public function checkConfirmRegistration(int $reguid, string $hmac): array
110
    {
111
        /* @var $registration Registration */
112
        $registration = null;
113
        $failed = false;
114
        $messageKey = 'event.message.confirmation_successful';
115
        $titleKey = 'confirmRegistration.title.successful';
116
117
        if (!$this->hashService->validateHmac('reg-' . $reguid, $hmac)) {
118
            $failed = true;
119
            $messageKey = 'event.message.confirmation_failed_wrong_hmac';
120
            $titleKey = 'confirmRegistration.title.failed';
121
        } else {
122
            $registration = $this->registrationRepository->findByUid($reguid);
123
        }
124
125
        if (!$failed && is_null($registration)) {
126
            $failed = true;
127
            $messageKey = 'event.message.confirmation_failed_registration_not_found';
128
            $titleKey = 'confirmRegistration.title.failed';
129
        }
130
131
        if (!$failed && $registration->getConfirmationUntil() < new \DateTime()) {
132
            $failed = true;
133
            $messageKey = 'event.message.confirmation_failed_confirmation_until_expired';
134
            $titleKey = 'confirmRegistration.title.failed';
135
        }
136
137
        if (!$failed && $registration->getConfirmed() === true) {
138
            $failed = true;
139
            $messageKey = 'event.message.confirmation_failed_already_confirmed';
140
            $titleKey = 'confirmRegistration.title.failed';
141
        }
142
143
        if (!$failed && $registration->getWaitlist()) {
144
            $messageKey = 'event.message.confirmation_waitlist_successful';
145
            $titleKey = 'confirmRegistrationWaitlist.title.successful';
146
        }
147
148
        return [
149
            $failed,
150
            $registration,
151
            $messageKey,
152
            $titleKey,
153
        ];
154
    }
155
156
    /**
157
     * Cancels all depending registrations based on the given main registration
158
     */
159
    public function cancelDependingRegistrations(Registration $registration): void
160
    {
161
        $registrations = $this->registrationRepository->findByMainRegistration($registration);
162
        foreach ($registrations as $foundRegistration) {
163
            $this->registrationRepository->remove($foundRegistration);
164
        }
165
    }
166
167
    /**
168
     * Checks if the registration can be cancelled and returns an array of variables
169
     */
170
    public function checkCancelRegistration(int $reguid, string $hmac): array
171
    {
172
        /* @var $registration Registration */
173
        $registration = null;
174
        $failed = false;
175
        $messageKey = 'event.message.cancel_successful';
176
        $titleKey = 'cancelRegistration.title.successful';
177
178
        if (!$this->hashService->validateHmac('reg-' . $reguid, $hmac)) {
179
            $failed = true;
180
            $messageKey = 'event.message.cancel_failed_wrong_hmac';
181
            $titleKey = 'cancelRegistration.title.failed';
182
        } else {
183
            $registration = $this->registrationRepository->findByUid($reguid);
184
        }
185
186
        if (!$failed && is_null($registration)) {
187
            $failed = true;
188
            $messageKey = 'event.message.cancel_failed_registration_not_found_or_cancelled';
189
            $titleKey = 'cancelRegistration.title.failed';
190
        }
191
192
        if (!$failed && !is_a($registration->getEvent(), Event::class)) {
193
            $failed = true;
194
            $messageKey = 'event.message.cancel_failed_event_not_found';
195
            $titleKey = 'cancelRegistration.title.failed';
196
        }
197
198
        if (!$failed && $registration->getEvent()->getEnableCancel() === false) {
199
            $failed = true;
200
            $messageKey = 'event.message.confirmation_failed_cancel_disabled';
201
            $titleKey = 'cancelRegistration.title.failed';
202
        }
203
204
        if (!$failed && $registration->getEvent()->getCancelDeadline() !== null
205
            && $registration->getEvent()->getCancelDeadline() < new \DateTime()
206
        ) {
207
            $failed = true;
208
            $messageKey = 'event.message.cancel_failed_deadline_expired';
209
            $titleKey = 'cancelRegistration.title.failed';
210
        }
211
212
        if (!$failed && $registration->getEvent()->getStartdate() < new \DateTime()) {
213
            $failed = true;
214
            $messageKey = 'event.message.cancel_failed_event_started';
215
            $titleKey = 'cancelRegistration.title.failed';
216
        }
217
218
        return [
219
            $failed,
220
            $registration,
221
            $messageKey,
222
            $titleKey,
223
        ];
224
    }
225
226
    /**
227
     * Returns the current frontend user object if available
228
     */
229
    public function getCurrentFeUserObject(): ?FrontendUser
230
    {
231
        $user = null;
232
233
        if (isset($GLOBALS['TSFE']->fe_user->user['uid'])) {
234
            /** @var FrontendUser $user */
235
            $user = $this->frontendUserRepository->findByUid($GLOBALS['TSFE']->fe_user->user['uid']);
236
        }
237
238
        return $user;
239
    }
240
241
    /**
242
     * Checks, if the registration can successfully be created. Note, that
243
     * $result is passed by reference!
244
     */
245
    public function checkRegistrationSuccess(Event $event, Registration $registration, int $result): array
246
    {
247
        $success = true;
248
        if ($event->getEnableRegistration() === false) {
249
            $success = false;
250
            $result = RegistrationResult::REGISTRATION_NOT_ENABLED;
251
        } elseif ($event->getRegistrationDeadline() != null && $event->getRegistrationDeadline() < new \DateTime()) {
252
            $success = false;
253
            $result = RegistrationResult::REGISTRATION_FAILED_DEADLINE_EXPIRED;
254
        } elseif (!$event->getAllowRegistrationUntilEnddate() && $event->getStartdate() < new \DateTime()) {
255
            $success = false;
256
            $result = RegistrationResult::REGISTRATION_FAILED_EVENT_EXPIRED;
257
        } elseif ($event->getAllowRegistrationUntilEnddate() && $event->getEnddate() && $event->getEnddate() < new \DateTime()) {
258
            $success = false;
259
            $result = RegistrationResult::REGISTRATION_FAILED_EVENT_ENDED;
260
        } elseif ($event->getRegistrations()->count() >= $event->getMaxParticipants()
261
            && $event->getMaxParticipants() > 0 && !$event->getEnableWaitlist()
262
        ) {
263
            $success = false;
264
            $result = RegistrationResult::REGISTRATION_FAILED_MAX_PARTICIPANTS;
265
        } elseif ($event->getFreePlaces() < $registration->getAmountOfRegistrations()
266
            && $event->getMaxParticipants() > 0 && !$event->getEnableWaitlist()
267
        ) {
268
            $success = false;
269
            $result = RegistrationResult::REGISTRATION_FAILED_NOT_ENOUGH_FREE_PLACES;
270
        } elseif ($event->getMaxRegistrationsPerUser() < $registration->getAmountOfRegistrations()) {
271
            $success = false;
272
            $result = RegistrationResult::REGISTRATION_FAILED_MAX_AMOUNT_REGISTRATIONS_EXCEEDED;
273
        } elseif ($event->getUniqueEmailCheck() &&
274
            $this->emailNotUnique($event, $registration->getEmail())
275
        ) {
276
            $success = false;
277
            $result = RegistrationResult::REGISTRATION_FAILED_EMAIL_NOT_UNIQUE;
278
        } elseif ($event->getRegistrations()->count() >= $event->getMaxParticipants()
279
            && $event->getMaxParticipants() > 0 && $event->getEnableWaitlist()
280
        ) {
281
            $result = RegistrationResult::REGISTRATION_SUCCESSFUL_WAITLIST;
282
        }
283
284
        return [$success, $result];
285
    }
286
287
    /**
288
     * Returns if the given email is registered to the given event
289
     */
290
    protected function emailNotUnique(Event $event, string $email): bool
291
    {
292
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
293
            ->getQueryBuilderForTable('tx_sfeventmgt_domain_model_registration');
294
        $queryBuilder->getRestrictions()->removeByType(HiddenRestriction::class);
295
        $registrations = $queryBuilder->count('email')
296
            ->from('tx_sfeventmgt_domain_model_registration')
297
            ->where(
298
                $queryBuilder->expr()->eq(
299
                    'event',
300
                    $queryBuilder->createNamedParameter($event->getUid(), Connection::PARAM_INT)
301
                ),
302
                $queryBuilder->expr()->eq(
303
                    'email',
304
                    $queryBuilder->createNamedParameter($email, Connection::PARAM_STR)
305
                )
306
            )
307
            ->execute()
308
            ->fetchOne();
309
310
        return $registrations >= 1;
311
    }
312
313
    /**
314
     * Returns, if payment redirect for the payment method is enabled
315
     */
316
    public function redirectPaymentEnabled(Registration $registration): bool
317
    {
318
        if ($registration->getEvent()->getEnablePayment() === false) {
319
            return false;
320
        }
321
322
        /** @var AbstractPayment $paymentInstance */
323
        $paymentInstance = $this->paymentService->getPaymentInstance($registration->getPaymentmethod());
324
        if ($paymentInstance !== null && $paymentInstance->isRedirectEnabled()) {
325
            return true;
326
        }
327
328
        return false;
329
    }
330
331
    /**
332
     * Returns if the given amount of registrations for the event will be registrations for the waitlist
333
     * (depending on the total amount of registrations and free places)
334
     */
335
    public function isWaitlistRegistration(Event $event, int $amountOfRegistrations): bool
336
    {
337
        if ($event->getMaxParticipants() === 0 || !$event->getEnableWaitlist()) {
338
            return false;
339
        }
340
341
        $result = false;
342
        if (($event->getFreePlaces() > 0 && $event->getFreePlaces() < $amountOfRegistrations)
343
            || $event->getFreePlaces() <= 0) {
344
            $result = true;
345
        }
346
347
        return $result;
348
    }
349
350
    /**
351
     * Handles the process of moving registration up from the waitlist.
352
     */
353
    public function moveUpWaitlistRegistrations(Event $event, array $settings): void
354
    {
355
        // Early return if move up not enabled, no registrations on waitlist or no free places left
356
        if (!$event->getEnableWaitlistMoveup() || $event->getRegistrationsWaitlist()->count() === 0 ||
357
            $event->getFreePlaces() <= 0
358
        ) {
359
            return;
360
        }
361
362
        $keepMainRegistrationDependency = $settings['waitlist']['moveUp']['keepMainRegistrationDependency'] ?? false;
363
        $freePlaces = $event->getFreePlaces();
364
        $moveupRegistrations = $this->registrationRepository->findWaitlistMoveUpRegistrations($event);
365
366
        /** @var Registration $registration */
367
        foreach ($moveupRegistrations as $registration) {
368
            $registration->setWaitlist(false);
369
            $registration->setIgnoreNotifications(false);
370
371
            if (!(bool)$keepMainRegistrationDependency) {
372
                $registration->_setProperty('mainRegistration', null);
373
            }
374
375
            $this->registrationRepository->update($registration);
376
377
            // Send messages to user and admin
378
            $this->notificationService->sendUserMessage(
379
                $event,
380
                $registration,
381
                $settings,
382
                MessageType::REGISTRATION_WAITLIST_MOVE_UP
383
            );
384
            $this->notificationService->sendAdminMessage(
385
                $registration->getEvent(),
386
                $registration,
387
                $settings,
388
                MessageType::REGISTRATION_WAITLIST_MOVE_UP
389
            );
390
391
            $this->eventDispatcher->dispatch(new AfterRegistrationMovedFromWaitlist($registration, $this));
392
393
            $freePlaces--;
394
            if ($freePlaces === 0) {
395
                break;
396
            }
397
        }
398
    }
399
}
400