Passed
Push — main ( 8c9e9f...58ee80 )
by Torben
02:32
created

RegistrationService::checkRegistrationSuccess()   D

Complexity

Conditions 21
Paths 10

Size

Total Lines 43
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 21
eloc 34
nc 10
nop 3
dl 0
loc 43
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 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;
0 ignored issues
show
Bug introduced by
The type TYPO3\CMS\Extbase\Reflection\ObjectAccess was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
31
use TYPO3\CMS\Extbase\Security\Cryptography\HashService;
0 ignored issues
show
Bug introduced by
The type TYPO3\CMS\Extbase\Securi...ryptography\HashService was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
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->getAllowRegistrationUntilEnddate() && $event->getStartdate() < new DateTime()) {
259
            $success = false;
260
            $result = RegistrationResult::REGISTRATION_FAILED_EVENT_EXPIRED;
261
        } elseif ($event->getAllowRegistrationUntilEnddate() && $event->getEnddate() && $event->getEnddate() < new DateTime()) {
262
            $success = false;
263
            $result = RegistrationResult::REGISTRATION_FAILED_EVENT_ENDED;
264
        } elseif ($event->getRegistrations()->count() >= $event->getMaxParticipants()
265
            && $event->getMaxParticipants() > 0 && !$event->getEnableWaitlist()
266
        ) {
267
            $success = false;
268
            $result = RegistrationResult::REGISTRATION_FAILED_MAX_PARTICIPANTS;
269
        } elseif ($event->getFreePlaces() < $registration->getAmountOfRegistrations()
270
            && $event->getMaxParticipants() > 0 && !$event->getEnableWaitlist()
271
        ) {
272
            $success = false;
273
            $result = RegistrationResult::REGISTRATION_FAILED_NOT_ENOUGH_FREE_PLACES;
274
        } elseif ($event->getMaxRegistrationsPerUser() < $registration->getAmountOfRegistrations()) {
275
            $success = false;
276
            $result = RegistrationResult::REGISTRATION_FAILED_MAX_AMOUNT_REGISTRATIONS_EXCEEDED;
277
        } elseif ($event->getUniqueEmailCheck() &&
278
            $this->emailNotUnique($event, $registration->getEmail())
279
        ) {
280
            $success = false;
281
            $result = RegistrationResult::REGISTRATION_FAILED_EMAIL_NOT_UNIQUE;
282
        } elseif ($event->getRegistrations()->count() >= $event->getMaxParticipants()
283
            && $event->getMaxParticipants() > 0 && $event->getEnableWaitlist()
284
        ) {
285
            $result = RegistrationResult::REGISTRATION_SUCCESSFUL_WAITLIST;
286
        }
287
288
        $modifyCheckRegistrationSuccessEvent = new ModifyCheckRegistrationSuccessEvent($success, $result);
289
        $this->eventDispatcher->dispatch($modifyCheckRegistrationSuccessEvent);
290
291
        return [$modifyCheckRegistrationSuccessEvent->getSuccess(), $modifyCheckRegistrationSuccessEvent->getResult()];
292
    }
293
294
    /**
295
     * Returns if the given email is registered to the given event
296
     */
297
    protected function emailNotUnique(Event $event, string $email): bool
298
    {
299
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
300
            ->getQueryBuilderForTable('tx_sfeventmgt_domain_model_registration');
301
        $queryBuilder->getRestrictions()->removeByType(HiddenRestriction::class);
302
        $registrations = $queryBuilder->count('email')
303
            ->from('tx_sfeventmgt_domain_model_registration')
304
            ->where(
305
                $queryBuilder->expr()->eq(
306
                    'event',
307
                    $queryBuilder->createNamedParameter($event->getUid(), Connection::PARAM_INT)
308
                ),
309
                $queryBuilder->expr()->eq(
310
                    'email',
311
                    $queryBuilder->createNamedParameter($email, Connection::PARAM_STR)
312
                )
313
            )
314
            ->executeQuery()
315
            ->fetchOne();
316
317
        return $registrations >= 1;
318
    }
319
320
    /**
321
     * Returns, if payment redirect for the payment method is enabled
322
     */
323
    public function redirectPaymentEnabled(Registration $registration): bool
324
    {
325
        if ($registration->getEvent()->getEnablePayment() === false) {
326
            return false;
327
        }
328
329
        /** @var AbstractPayment $paymentInstance */
330
        $paymentInstance = $this->paymentService->getPaymentInstance($registration->getPaymentmethod());
331
332
        return $paymentInstance !== null && $paymentInstance->isRedirectEnabled();
333
    }
334
335
    /**
336
     * Returns if the given amount of registrations for the event will be registrations for the waitlist
337
     * (depending on the total amount of registrations and free places)
338
     */
339
    public function isWaitlistRegistration(Event $event, int $amountOfRegistrations): bool
340
    {
341
        if ($event->getMaxParticipants() === 0 || !$event->getEnableWaitlist()) {
342
            return false;
343
        }
344
345
        $result = false;
346
        if (($event->getFreePlaces() > 0 && $event->getFreePlaces() < $amountOfRegistrations)
347
            || $event->getFreePlaces() <= 0) {
348
            $result = true;
349
        }
350
351
        return $result;
352
    }
353
354
    /**
355
     * Handles the process of moving registration up from the waitlist.
356
     */
357
    public function moveUpWaitlistRegistrations(Event $event, array $settings): void
358
    {
359
        // Early return if move up not enabled, no registrations on waitlist or no free places left
360
        if (!$event->getEnableWaitlistMoveup() || $event->getRegistrationsWaitlist()->count() === 0 ||
361
            $event->getFreePlaces() <= 0
362
        ) {
363
            return;
364
        }
365
366
        $keepMainRegistrationDependency = $settings['waitlist']['moveUp']['keepMainRegistrationDependency'] ?? false;
367
        $freePlaces = $event->getFreePlaces();
368
        $moveupRegistrations = $this->registrationRepository->findWaitlistMoveUpRegistrations($event);
369
370
        /** @var Registration $registration */
371
        foreach ($moveupRegistrations as $registration) {
372
            $registration->setWaitlist(false);
373
            $registration->setIgnoreNotifications(false);
374
375
            if (!(bool)$keepMainRegistrationDependency) {
376
                $registration->_setProperty('mainRegistration', null);
377
            }
378
379
            $this->registrationRepository->update($registration);
380
381
            // Send messages to user and admin
382
            $this->notificationService->sendUserMessage(
383
                $event,
384
                $registration,
385
                $settings,
386
                MessageType::REGISTRATION_WAITLIST_MOVE_UP
387
            );
388
            $this->notificationService->sendAdminMessage(
389
                $registration->getEvent(),
390
                $registration,
391
                $settings,
392
                MessageType::REGISTRATION_WAITLIST_MOVE_UP
393
            );
394
395
            $this->eventDispatcher->dispatch(new AfterRegistrationMovedFromWaitlist($registration, $this));
396
397
            $freePlaces--;
398
            if ($freePlaces === 0) {
399
                break;
400
            }
401
        }
402
    }
403
}
404