Completed
Push — master ( b10e41...04d25a )
by Torben
07:05 queued 05:12
created

EventController   B

Complexity

Total Complexity 45

Size/Duplication

Total Lines 521
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 13

Test Coverage

Coverage 97.92%

Importance

Changes 22
Bugs 2 Features 12
Metric Value
wmc 45
c 22
b 2
f 12
lcom 2
cbo 13
dl 0
loc 521
ccs 235
cts 240
cp 0.9792
rs 8.3673

15 Methods

Rating   Name   Duplication   Size   Complexity  
A detailAction() 0 4 1
A registrationAction() 0 4 1
A createEventDemandObjectFromSettings() 0 14 1
A createForeignRecordDemandObjectFromSettings() 0 8 1
A overwriteEventDemandObject() 0 11 3
A listAction() 0 15 2
A initializeSaveRegistrationAction() 0 10 1
A icalDownloadAction() 0 5 1
C saveRegistrationAction() 0 75 7
D saveRegistrationResultAction() 0 43 9
B confirmRegistrationAction() 0 31 3
B cancelRegistrationAction() 0 34 3
A initializeSearchAction() 0 19 3
C searchAction() 0 33 7
A isOverwriteDemand() 0 4 2

How to fix   Complexity   

Complex Class

Complex classes like EventController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use EventController, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace DERHANSEN\SfEventMgt\Controller;
3
4
/*
5
 * This file is part of the TYPO3 CMS project.
6
 *
7
 * It is free software; you can redistribute it and/or modify it under
8
 * the terms of the GNU General Public License, either version 2
9
 * of the License, or any later version.
10
 *
11
 * For the full copyright and license information, please read the
12
 * LICENSE.txt file that was distributed with this source code.
13
 *
14
 * The TYPO3 project - inspiring people to share!
15
 */
16
17
use DERHANSEN\SfEventMgt\Domain\Model\Dto\EventDemand;
18
use DERHANSEN\SfEventMgt\Domain\Model\Dto\SearchDemand;
19
use DERHANSEN\SfEventMgt\Domain\Model\Event;
20
use DERHANSEN\SfEventMgt\Domain\Model\Registration;
21
use DERHANSEN\SfEventMgt\Utility\RegistrationResult;
22
use DERHANSEN\SfEventMgt\Utility\MessageType;
23
use DERHANSEN\SfEventMgt\Utility\Page;
24
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
25
use TYPO3\CMS\Extbase\Property\TypeConverter\DateTimeConverter;
26
27
/**
28
 * EventController
29
 *
30
 * @author Torben Hansen <[email protected]>
31
 */
32
class EventController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
33
{
34
35
    /**
36
     * Configuration Manager
37
     *
38
     * @var ConfigurationManagerInterface
39
     */
40
    protected $configurationManager;
41
42
    /**
43
     * EventRepository
44
     *
45
     * @var \DERHANSEN\SfEventMgt\Domain\Repository\EventRepository
46
     * @inject
47
     */
48
    protected $eventRepository = null;
49
50
    /**
51
     * Registration repository
52
     *
53
     * @var \DERHANSEN\SfEventMgt\Domain\Repository\RegistrationRepository
54
     * @inject
55
     */
56
    protected $registrationRepository = null;
57
58
    /**
59
     * Category repository
60
     *
61
     * @var \DERHANSEN\SfEventMgt\Domain\Repository\CategoryRepository
62
     * @inject
63
     */
64
    protected $categoryRepository = null;
65
66
    /**
67
     * Location repository
68
     *
69
     * @var \DERHANSEN\SfEventMgt\Domain\Repository\LocationRepository
70
     * @inject
71
     */
72
    protected $locationRepository = null;
73
74
    /**
75
     * Notification Service
76
     *
77
     * @var \DERHANSEN\SfEventMgt\Service\NotificationService
78
     * @inject
79
     */
80
    protected $notificationService = null;
81
82
    /**
83
     * ICalendar Service
84
     *
85
     * @var \DERHANSEN\SfEventMgt\Service\ICalendarService
86
     * @inject
87
     */
88
    protected $icalendarService = null;
89
90
    /**
91
     * Hash Service
92
     *
93
     * @var \TYPO3\CMS\Extbase\Security\Cryptography\HashService
94
     * @inject
95
     */
96
    protected $hashService;
97
98
    /**
99
     * RegistrationService
100
     *
101
     * @var \DERHANSEN\SfEventMgt\Service\RegistrationService
102
     * @inject
103
     */
104
    protected $registrationService = null;
105
106
    /**
107
     * UtilityService
108
     *
109
     * @var \DERHANSEN\SfEventMgt\Service\UtilityService
110
     * @inject
111
     */
112
    protected $utilityService = null;
113
114
    /**
115
     * Properties in this array will be ignored by overwriteDemandObject()
116
     *
117
     * @var array
118
     */
119
    protected $ignoredSettingsForOverwriteDemand = ['storagePage'];
120
121
    /**
122
     * Creates an event demand object with the given settings
123
     *
124
     * @param array $settings The settings
125
     *
126
     * @return \DERHANSEN\SfEventMgt\Domain\Model\Dto\EventDemand
127
     */
128 1
    public function createEventDemandObjectFromSettings(array $settings)
129
    {
130
        /** @var \DERHANSEN\SfEventMgt\Domain\Model\Dto\EventDemand $demand */
131 1
        $demand = $this->objectManager->get('DERHANSEN\\SfEventMgt\\Domain\\Model\\Dto\\EventDemand');
132 1
        $demand->setDisplayMode($settings['displayMode']);
133 1
        $demand->setStoragePage(Page::extendPidListByChildren($settings['storagePage'], $settings['recursive']));
134 1
        $demand->setCategory($settings['category']);
135 1
        $demand->setTopEventRestriction((int)$settings['topEventRestriction']);
136 1
        $demand->setOrderField($settings['orderField']);
137 1
        $demand->setOrderDirection($settings['orderDirection']);
138 1
        $demand->setQueryLimit($settings['queryLimit']);
139 1
        $demand->setLocation($settings['location']);
140 1
        return $demand;
141
    }
142
143
    /**
144
     * Creates a foreign record demand object with the given settings
145
     *
146
     * @param array $settings The settings
147
     *
148
     * @return \DERHANSEN\SfEventMgt\Domain\Model\Dto\ForeignRecordDemand
149
     */
150
    public function createForeignRecordDemandObjectFromSettings(array $settings)
151
    {
152
        /** @var \DERHANSEN\SfEventMgt\Domain\Model\Dto\ForeignRecordDemand $demand */
153
        $demand = $this->objectManager->get('DERHANSEN\\SfEventMgt\\Domain\\Model\\Dto\\ForeignRecordDemand');
154
        $demand->setStoragePage(Page::extendPidListByChildren($settings['storagePage'], $settings['recursive']));
155
        $demand->setRestrictForeignRecordsToStoragePage((int)$settings['restrictForeignRecordsToStoragePage']);
156
        return $demand;
157
    }
158
159
    /**
160
     * Overwrites a given demand object by an propertyName =>  $propertyValue array
161
     *
162
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Dto\EventDemand $demand Demand
163
     * @param array $overwriteDemand OwerwriteDemand
164
     *
165
     * @return \DERHANSEN\SfEventMgt\Domain\Model\Dto\EventDemand
166
     */
167 2
    protected function overwriteEventDemandObject(EventDemand $demand, array $overwriteDemand)
168
    {
169 2
        foreach ($this->ignoredSettingsForOverwriteDemand as $property) {
170 2
            unset($overwriteDemand[$property]);
171 2
        }
172
173 2
        foreach ($overwriteDemand as $propertyName => $propertyValue) {
174 2
            \TYPO3\CMS\Extbase\Reflection\ObjectAccess::setProperty($demand, $propertyName, $propertyValue);
175 2
        }
176 2
        return $demand;
177
    }
178
179
    /**
180
     * List view
181
     *
182
     * @param array $overwriteDemand OverwriteDemand
183
     *
184
     * @return void
185
     */
186 3
    public function listAction(array $overwriteDemand = [])
187
    {
188 3
        $eventDemand = $this->createEventDemandObjectFromSettings($this->settings);
189 3
        $foreignRecordDemand = $this->createForeignRecordDemandObjectFromSettings($this->settings);
190 3
        if ($this->isOverwriteDemand($overwriteDemand)) {
191 1
            $eventDemand = $this->overwriteEventDemandObject($eventDemand, $overwriteDemand);
192 1
        }
193 3
        $events = $this->eventRepository->findDemanded($eventDemand);
194 3
        $categories = $this->categoryRepository->findDemanded($foreignRecordDemand);
195 3
        $locations = $this->locationRepository->findDemanded($foreignRecordDemand);
196 3
        $this->view->assign('events', $events);
197 3
        $this->view->assign('categories', $categories);
198 3
        $this->view->assign('locations', $locations);
199 3
        $this->view->assign('overwriteDemand', $overwriteDemand);
200 3
    }
201
202
    /**
203
     * Detail view for an event
204
     *
205
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Event $event Event
206
     *
207
     * @return void
208
     */
209 1
    public function detailAction(Event $event = null)
210
    {
211 1
        $this->view->assign('event', $event);
212 1
    }
213
214
    /**
215
     * Initiates the iCalendar download for the given event
216
     *
217
     * @param Event $event The event
218
     *
219
     * @return bool
220
     */
221 1
    public function icalDownloadAction(Event $event)
222
    {
223 1
        $this->icalendarService->downloadiCalendarFile($event);
224 1
        return false;
225
    }
226
227
    /**
228
     * Registration view for an event
229
     *
230
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Event $event Event
231
     *
232
     * @return void
233
     */
234 1
    public function registrationAction(Event $event)
235
    {
236 1
        $this->view->assign('event', $event);
237 1
    }
238
239
    /**
240
     * Set date format for field dateOfBirth
241
     *
242
     * @return void
243
     */
244 1
    public function initializeSaveRegistrationAction()
245
    {
246 1
        $this->arguments->getArgument('registration')
247 1
            ->getPropertyMappingConfiguration()->forProperty('dateOfBirth')
248 1
            ->setTypeConverterOption(
249 1
                'TYPO3\\CMS\\Extbase\\Property\\TypeConverter\\DateTimeConverter',
250 1
                DateTimeConverter::CONFIGURATION_DATE_FORMAT,
251 1
                $this->settings['registration']['formatDateOfBirth']
252 1
            );
253 1
    }
254
255
    /**
256
     * Saves the registration
257
     *
258
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Registration $registration Registration
259
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Event $event Event
260
     * @validate $registration \DERHANSEN\SfEventMgt\Validation\Validator\RegistrationValidator
261
     *
262
     * @return void
263
     */
264 10
    public function saveRegistrationAction(Registration $registration, Event $event)
265
    {
266 10
        $autoConfirmation = (bool)$this->settings['registration']['autoConfirmation'];
267 10
        $result = RegistrationResult::REGISTRATION_SUCCESSFUL;
268 10
        $success = $this->registrationService->checkRegistrationSuccess($event, $registration, $result);
269
270
        // Save registration if no errors
271 10
        if ($success) {
272 3
            $linkValidity = (int)$this->settings['confirmation']['linkValidity'];
273 3
            if ($linkValidity === 0) {
274
                // Use 3600 seconds as default value if not set
275 3
                $linkValidity = 3600;
276 3
            }
277 3
            $confirmationUntil = new \DateTime();
278 3
            $confirmationUntil->add(new \DateInterval('PT' . $linkValidity . 'S'));
279
280 3
            $registration->setEvent($event);
281 3
            $registration->setPid($event->getPid());
282 3
            $registration->setConfirmationUntil($confirmationUntil);
283 3
            $registration->setLanguage($GLOBALS['TSFE']->config['config']['language']);
284 3
            $registration->setFeUser($this->registrationService->getCurrentFeUserObject());
285 3
            $registration->_setProperty('_languageUid', $GLOBALS['TSFE']->sys_language_uid);
286 3
            $this->registrationRepository->add($registration);
287
288
            // Persist registration, so we have an UID
289 3
            $this->objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\PersistenceManager')->persistAll();
290
291
            // Add new registration to event
292 3
            $event->addRegistration($registration);
293 3
            $this->eventRepository->update($event);
294
295
            // Send notifications to user and admin if confirmation link should be sent
296 3
            if (!$autoConfirmation) {
297 2
                $this->notificationService->sendUserMessage(
298 2
                    $event,
299 2
                    $registration,
300 2
                    $this->settings,
301
                    MessageType::REGISTRATION_NEW
302 2
                );
303 2
                $this->notificationService->sendAdminMessage(
304 2
                    $event,
305 2
                    $registration,
306 2
                    $this->settings,
307
                    MessageType::REGISTRATION_NEW
308 2
                );
309 2
            }
310
311
            // Create given amount of registrations if necessary
312 3
            if ($registration->getAmountOfRegistrations() > 1) {
313 1
                $this->registrationService->createDependingRegistrations($registration);
314 1
            }
315
316
            // Clear cache for configured pages
317 3
            $this->utilityService->clearCacheForConfiguredUids($this->settings);
318 3
        }
319
320 10
        if ($autoConfirmation && $success) {
321 1
            $this->redirect(
322 1
                'confirmRegistration',
323 1
                null,
324 1
                null,
325
                [
326 1
                    'reguid' => $registration->getUid(),
327 1
                    'hmac' => $this->hashService->generateHmac('reg-' . $registration->getUid())
328 1
                ]
329 1
            );
330 1
        } else {
331 9
            $this->redirect(
332 9
                'saveRegistrationResult',
333 9
                null,
334 9
                null,
335 9
                ['result' => $result]
336 9
            );
337
        }
338 10
    }
339
340
    /**
341
     * Shows the result of the saveRegistrationAction
342
     *
343
     * @param int $result Result
344
     *
345
     * @return void
346
     */
347 9
    public function saveRegistrationResultAction($result)
348
    {
349
        switch ($result) {
350 9
            case RegistrationResult::REGISTRATION_SUCCESSFUL:
351 1
                $messageKey = 'event.message.registrationsuccessful';
352 1
                $titleKey = 'registrationResult.title.successful';
353 1
                break;
354 8
            case RegistrationResult::REGISTRATION_FAILED_EVENT_EXPIRED:
355 1
                $messageKey = 'event.message.registrationfailedeventexpired';
356 1
                $titleKey = 'registrationResult.title.failed';
357 1
                break;
358 7
            case RegistrationResult::REGISTRATION_FAILED_MAX_PARTICIPANTS:
359 1
                $messageKey = 'event.message.registrationfailedmaxparticipants';
360 1
                $titleKey = 'registrationResult.title.failed';
361 1
                break;
362 6
            case RegistrationResult::REGISTRATION_NOT_ENABLED:
363 1
                $messageKey = 'event.message.registrationfailednotenabled';
364 1
                $titleKey = 'registrationResult.title.failed';
365 1
                break;
366 5
            case RegistrationResult::REGISTRATION_FAILED_DEADLINE_EXPIRED:
367 1
                $messageKey = 'event.message.registrationfaileddeadlineexpired';
368 1
                $titleKey = 'registrationResult.title.failed';
369 1
                break;
370 4
            case RegistrationResult::REGISTRATION_FAILED_NOT_ENOUGH_FREE_PLACES:
371 1
                $messageKey = 'event.message.registrationfailednotenoughfreeplaces';
372 1
                $titleKey = 'registrationResult.title.failed';
373 1
                break;
374 3
            case RegistrationResult::REGISTRATION_FAILED_MAX_AMOUNT_REGISTRATIONS_EXCEEDED:
375 1
                $messageKey = 'event.message.registrationfailedmaxamountregistrationsexceeded';
376 1
                $titleKey = 'registrationResult.title.failed';
377 1
                break;
378 2
            case RegistrationResult::REGISTRATION_FAILED_EMAIL_NOT_UNIQUE:
379 1
                $messageKey = 'event.message.registrationfailedemailnotunique';
380 1
                $titleKey = 'registrationResult.title.failed';
381 1
                break;
382 1
            default:
383 1
                $messageKey = '';
384 1
                $titleKey = '';
385 1
        }
386
387 9
        $this->view->assign('messageKey', $messageKey);
388 9
        $this->view->assign('titleKey', $titleKey);
389 9
    }
390
391
    /**
392
     * Confirms the registration if possible and sends e-mails to admin and user
393
     *
394
     * @param int $reguid UID of registration
395
     * @param string $hmac HMAC for parameters
396
     *
397
     * @return void
398
     */
399 2
    public function confirmRegistrationAction($reguid, $hmac)
400
    {
401
        /* @var $registration Registration */
402 2
        list($failed, $registration, $messageKey, $titleKey) = $this->registrationService->checkConfirmRegistration($reguid, $hmac);
403
404 2
        if ($failed === false) {
405 1
            $registration->setConfirmed(true);
406 1
            $this->registrationRepository->update($registration);
407
408
            // Send notifications to user and admin
409 1
            $this->notificationService->sendUserMessage(
410 1
                $registration->getEvent(),
411 1
                $registration,
412 1
                $this->settings,
413
                MessageType::REGISTRATION_CONFIRMED
414 1
            );
415 1
            $this->notificationService->sendAdminMessage(
416 1
                $registration->getEvent(),
417 1
                $registration,
418 1
                $this->settings,
419
                MessageType::REGISTRATION_CONFIRMED
420 1
            );
421
422
            // Confirm registrations depending on main registration if necessary
423 1
            if ($registration->getAmountOfRegistrations() > 1) {
424 1
                $this->registrationService->confirmDependingRegistrations($registration);
425 1
            }
426 1
        }
427 2
        $this->view->assign('messageKey', $messageKey);
428 2
        $this->view->assign('titleKey', $titleKey);
429 2
    }
430
431
    /**
432
     * Cancels the registration if possible and sends e-mails to admin and user
433
     *
434
     * @param int $reguid UID of registration
435
     * @param string $hmac HMAC for parameters
436
     *
437
     * @return void
438
     */
439 2
    public function cancelRegistrationAction($reguid, $hmac)
440
    {
441
        /* @var $registration Registration */
442 2
        list($failed, $registration, $messageKey, $titleKey) = $this->registrationService->checkCancelRegistration($reguid, $hmac);
443
444 2
        if ($failed === false) {
445
            // Send notifications (must run before cancelling the registration)
446 1
            $this->notificationService->sendUserMessage(
447 1
                $registration->getEvent(),
448 1
                $registration,
449 1
                $this->settings,
450
                MessageType::REGISTRATION_CANCELLED
451 1
            );
452 1
            $this->notificationService->sendAdminMessage(
453 1
                $registration->getEvent(),
454 1
                $registration,
455 1
                $this->settings,
456
                MessageType::REGISTRATION_CANCELLED
457 1
            );
458
459
            // First cancel depending registrations
460 1
            if ($registration->getAmountOfRegistrations() > 1) {
461 1
                $this->registrationService->cancelDependingRegistrations($registration);
462 1
            }
463
464
            // Finally cancel registration
465 1
            $this->registrationRepository->remove($registration);
466
467
            // Clear cache for configured pages
468 1
            $this->utilityService->clearCacheForConfiguredUids($this->settings);
469 1
        }
470 2
        $this->view->assign('messageKey', $messageKey);
471 2
        $this->view->assign('titleKey', $titleKey);
472 2
    }
473
474
    /**
475
     * Set date format for field startDate and endDate
476
     *
477
     * @return void
478
     */
479 1
    public function initializeSearchAction()
480
    {
481 1
        if ($this->settings !== null && $this->settings['search']['dateFormat']) {
482 1
            $this->arguments->getArgument('searchDemand')
483 1
                ->getPropertyMappingConfiguration()->forProperty('startDate')
484 1
                ->setTypeConverterOption(
485 1
                    'TYPO3\\CMS\\Extbase\\Property\\TypeConverter\\DateTimeConverter',
486 1
                    DateTimeConverter::CONFIGURATION_DATE_FORMAT,
487 1
                    $this->settings['search']['dateFormat']
488 1
                );
489 1
            $this->arguments->getArgument('searchDemand')
490 1
                ->getPropertyMappingConfiguration()->forProperty('endDate')
491 1
                ->setTypeConverterOption(
492 1
                    'TYPO3\\CMS\\Extbase\\Property\\TypeConverter\\DateTimeConverter',
493 1
                    DateTimeConverter::CONFIGURATION_DATE_FORMAT,
494 1
                    $this->settings['search']['dateFormat']
495 1
                );
496 1
        }
497 1
    }
498
499
    /**
500
     * Search view
501
     *
502
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Dto\SearchDemand $searchDemand SearchDemand
503
     * @param array $overwriteDemand OverwriteDemand
504
     *
505
     * @return void
506
     */
507 6
    public function searchAction(SearchDemand $searchDemand = null, array $overwriteDemand = [])
508
    {
509 6
        $eventDemand = $this->createEventDemandObjectFromSettings($this->settings);
510 6
        $eventDemand->setSearchDemand($searchDemand);
511 6
        $foreignRecordDemand = $this->createForeignRecordDemandObjectFromSettings($this->settings);
512
513 6
        if ($searchDemand !== null) {
514 5
            $searchDemand->setFields($this->settings['search']['fields']);
515
516 5
            if ($this->settings['search']['adjustTime'] && $searchDemand->getStartDate() !== null) {
517 1
                $searchDemand->getStartDate()->setTime(0, 0, 0);
518 1
            }
519
520 5
            if ($this->settings['search']['adjustTime'] && $searchDemand->getEndDate() !== null) {
521 1
                $searchDemand->getEndDate()->setTime(23, 59, 59);
522 1
            }
523 5
        }
524
525 6
        if ($this->isOverwriteDemand($overwriteDemand)) {
526 1
            $eventDemand = $this->overwriteEventDemandObject($eventDemand, $overwriteDemand);
527 1
        }
528
529 6
        $categories = $this->categoryRepository->findDemanded($foreignRecordDemand);
530 6
        $locations = $this->locationRepository->findDemanded($foreignRecordDemand);
531
532 6
        $events = $this->eventRepository->findDemanded($eventDemand);
533
534 6
        $this->view->assign('events', $events);
535 6
        $this->view->assign('categories', $categories);
536 6
        $this->view->assign('locations', $locations);
537 6
        $this->view->assign('searchDemand', $searchDemand);
538 6
        $this->view->assign('overwriteDemand', $overwriteDemand);
539 6
    }
540
541
    /**
542
     * Returns if a demand object can be overwritten with the given overwriteDemand array
543
     *
544
     * @param array $overwriteDemand
545
     * @return bool
546
     */
547 9
    protected function isOverwriteDemand($overwriteDemand)
548
    {
549 9
        return $this->settings['disableOverrideDemand'] != 1 && $overwriteDemand !== [];
550
    }
551
552
}
553