Passed
Push — typo3_11 ( 1a41a1...78d6ec )
by Torben
07:24
created

EventController::initializeSearchAction()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 26
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 21
nc 4
nop 0
dl 0
loc 26
rs 9.584
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the Extension "sf_event_mgt" for TYPO3 CMS.
5
 *
6
 * For the full copyright and license information, please read the
7
 * LICENSE.txt file that was distributed with this source code.
8
 */
9
10
namespace DERHANSEN\SfEventMgt\Controller;
11
12
use DERHANSEN\SfEventMgt\Domain\Model\Dto\CategoryDemand;
13
use DERHANSEN\SfEventMgt\Domain\Model\Dto\EventDemand;
14
use DERHANSEN\SfEventMgt\Domain\Model\Dto\ForeignRecordDemand;
15
use DERHANSEN\SfEventMgt\Domain\Model\Dto\SearchDemand;
16
use DERHANSEN\SfEventMgt\Domain\Model\Event;
17
use DERHANSEN\SfEventMgt\Domain\Model\Registration;
18
use DERHANSEN\SfEventMgt\Event\AfterRegistrationConfirmedEvent;
19
use DERHANSEN\SfEventMgt\Event\AfterRegistrationSavedEvent;
20
use DERHANSEN\SfEventMgt\Event\EventPidCheckFailedEvent;
21
use DERHANSEN\SfEventMgt\Event\ModifyCalendarViewVariablesEvent;
22
use DERHANSEN\SfEventMgt\Event\ModifyCancelRegistrationViewVariablesEvent;
23
use DERHANSEN\SfEventMgt\Event\ModifyConfirmRegistrationViewVariablesEvent;
24
use DERHANSEN\SfEventMgt\Event\ModifyCreateDependingRegistrationsEvent;
25
use DERHANSEN\SfEventMgt\Event\ModifyDetailViewVariablesEvent;
26
use DERHANSEN\SfEventMgt\Event\ModifyListViewVariablesEvent;
27
use DERHANSEN\SfEventMgt\Event\ModifyRegistrationViewVariablesEvent;
28
use DERHANSEN\SfEventMgt\Event\ModifySearchViewVariablesEvent;
29
use DERHANSEN\SfEventMgt\Event\WaitlistMoveUpEvent;
30
use DERHANSEN\SfEventMgt\Service\EventCacheService;
31
use DERHANSEN\SfEventMgt\Utility\MessageType;
32
use DERHANSEN\SfEventMgt\Utility\PageUtility;
33
use DERHANSEN\SfEventMgt\Utility\RegistrationResult;
34
use Psr\Http\Message\ServerRequestInterface;
35
use TYPO3\CMS\Core\Context\Context;
36
use TYPO3\CMS\Core\Http\ImmediateResponseException;
37
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
38
use TYPO3\CMS\Core\Utility\ArrayUtility;
39
use TYPO3\CMS\Core\Utility\GeneralUtility;
40
use TYPO3\CMS\Core\Utility\HttpUtility;
41
use TYPO3\CMS\Extbase\Annotation as Extbase;
42
use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
43
use TYPO3\CMS\Extbase\Property\TypeConverter\DateTimeConverter;
44
use TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter;
45
use TYPO3\CMS\Fluid\View\StandaloneView;
46
use TYPO3\CMS\Frontend\Controller\ErrorController;
47
48
/**
49
 * EventController
50
 */
51
class EventController extends AbstractController
52
{
53
    /**
54
     * @var EventCacheService
55
     */
56
    protected $eventCacheService;
57
58
    /**
59
     * @param EventCacheService $cacheService
60
     */
61
    public function injectEventCacheService(EventCacheService $cacheService)
62
    {
63
        $this->eventCacheService = $cacheService;
64
    }
65
66
    /**
67
     * Assign contentObjectData and pageData to earch view
68
     *
69
     * @param \TYPO3\CMS\Extbase\Mvc\View\ViewInterface $view
70
     */
71
    protected function initializeView(\TYPO3\CMS\Extbase\Mvc\View\ViewInterface $view)
72
    {
73
        // @extensionScannerIgnoreLine
74
        $view->assign('contentObjectData', $this->configurationManager->getContentObject()->data);
75
        if (is_object($GLOBALS['TSFE'])) {
76
            $view->assign('pageData', $GLOBALS['TSFE']->page);
77
        }
78
        parent::initializeView($view);
79
    }
80
81
    /**
82
     * Initializes the current action
83
     */
84
    public function initializeAction()
85
    {
86
        $typoScriptFrontendController = $this->getTypoScriptFrontendController();
87
        if ($typoScriptFrontendController !== null) {
88
            static $cacheTagsSet = false;
89
90
            if (!$cacheTagsSet) {
91
                $typoScriptFrontendController->addCacheTags(['tx_sfeventmgt']);
92
                $cacheTagsSet = true;
93
            }
94
        }
95
    }
96
97
    /**
98
     * Initialize list action and set format
99
     */
100
    public function initializeListAction()
101
    {
102
        if (isset($this->settings['list']['format'])) {
103
            $this->request->setFormat($this->settings['list']['format']);
104
        }
105
    }
106
107
    /**
108
     * List view
109
     *
110
     * @param array $overwriteDemand OverwriteDemand
111
     */
112
    public function listAction(array $overwriteDemand = [])
113
    {
114
        $eventDemand = EventDemand::createFromSettings($this->settings);
115
        $foreignRecordDemand = ForeignRecordDemand::createFromSettings($this->settings);
116
        $categoryDemand = CategoryDemand::createFromSettings($this->settings);
117
        if ($this->isOverwriteDemand($overwriteDemand)) {
118
            $eventDemand = $this->overwriteEventDemandObject($eventDemand, $overwriteDemand);
119
        }
120
        $events = $this->eventRepository->findDemanded($eventDemand);
121
        $categories = $this->categoryRepository->findDemanded($categoryDemand);
122
        $locations = $this->locationRepository->findDemanded($foreignRecordDemand);
123
        $organisators = $this->organisatorRepository->findDemanded($foreignRecordDemand);
124
        $speakers = $this->speakerRepository->findDemanded($foreignRecordDemand);
125
126
        $modifyListViewVariablesEvent = new ModifyListViewVariablesEvent(
127
            [
128
                'events' => $events,
129
                'categories' => $categories,
130
                'locations' => $locations,
131
                'organisators' => $organisators,
132
                'speakers' => $speakers,
133
                'overwriteDemand' => $overwriteDemand,
134
                'eventDemand' => $eventDemand
135
            ],
136
            $this
137
        );
138
        $this->eventDispatcher->dispatch($modifyListViewVariablesEvent);
139
        $variables = $modifyListViewVariablesEvent->getVariables();
140
        $this->view->assignMultiple($variables);
141
142
        $this->eventCacheService->addPageCacheTagsByEventDemandObject($eventDemand);
143
    }
144
145
    /**
146
     * Calendar view
147
     *
148
     * @param array $overwriteDemand OverwriteDemand
149
     */
150
    public function calendarAction(array $overwriteDemand = [])
151
    {
152
        $eventDemand = EventDemand::createFromSettings($this->settings);
153
        $foreignRecordDemand = ForeignRecordDemand::createFromSettings($this->settings);
154
        $categoryDemand = CategoryDemand::createFromSettings($this->settings);
155
        if ($this->isOverwriteDemand($overwriteDemand)) {
156
            $eventDemand = $this->overwriteEventDemandObject($eventDemand, $overwriteDemand);
157
        }
158
159
        // Set month/year to demand if not given
160
        if (!$eventDemand->getMonth()) {
161
            $currentMonth = date('n');
162
            $eventDemand->setMonth($currentMonth);
0 ignored issues
show
Bug introduced by
$currentMonth of type string is incompatible with the type integer expected by parameter $month of DERHANSEN\SfEventMgt\Dom...EventDemand::setMonth(). ( Ignorable by Annotation )

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

162
            $eventDemand->setMonth(/** @scrutinizer ignore-type */ $currentMonth);
Loading history...
163
        } else {
164
            $currentMonth = $eventDemand->getMonth();
165
        }
166
        if (!$eventDemand->getYear()) {
167
            $currentYear = date('Y');
168
            $eventDemand->setYear($currentYear);
0 ignored issues
show
Bug introduced by
$currentYear of type string is incompatible with the type integer expected by parameter $year of DERHANSEN\SfEventMgt\Dom...\EventDemand::setYear(). ( Ignorable by Annotation )

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

168
            $eventDemand->setYear(/** @scrutinizer ignore-type */ $currentYear);
Loading history...
169
        } else {
170
            $currentYear = $eventDemand->getYear();
171
        }
172
173
        // Set demand from calendar date range instead of month / year
174
        if ((bool)$this->settings['calendar']['includeEventsForEveryDayOfAllCalendarWeeks']) {
175
            $eventDemand = $this->changeEventDemandToFullMonthDateRange($eventDemand);
176
        }
177
178
        $events = $this->eventRepository->findDemanded($eventDemand);
179
        $weeks = $this->calendarService->getCalendarArray(
180
            $currentMonth,
0 ignored issues
show
Bug introduced by
It seems like $currentMonth can also be of type string; however, parameter $month of DERHANSEN\SfEventMgt\Ser...ice::getCalendarArray() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

180
            /** @scrutinizer ignore-type */ $currentMonth,
Loading history...
181
            $currentYear,
0 ignored issues
show
Bug introduced by
It seems like $currentYear can also be of type string; however, parameter $year of DERHANSEN\SfEventMgt\Ser...ice::getCalendarArray() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

181
            /** @scrutinizer ignore-type */ $currentYear,
Loading history...
182
            strtotime('today midnight'),
183
            (int)$this->settings['calendar']['firstDayOfWeek'],
184
            $events
185
        );
186
187
        $modifyCalendarViewVariablesEvent = new ModifyCalendarViewVariablesEvent(
188
            [
189
                'events' => $events,
190
                'weeks' => $weeks,
191
                'categories' => $this->categoryRepository->findDemanded($categoryDemand),
192
                'locations' => $this->locationRepository->findDemanded($foreignRecordDemand),
193
                'organisators' => $this->organisatorRepository->findDemanded($foreignRecordDemand),
194
                'eventDemand' => $eventDemand,
195
                'overwriteDemand' => $overwriteDemand,
196
                'currentPageId' => $GLOBALS['TSFE']->id,
197
                'firstDayOfMonth' => \DateTime::createFromFormat(
198
                    'd.m.Y',
199
                    sprintf('1.%s.%s', $currentMonth, $currentYear)
200
                ),
201
                'previousMonthConfig' => $this->calendarService->getDateConfig($currentMonth, $currentYear, '-1 month'),
0 ignored issues
show
Bug introduced by
It seems like $currentMonth can also be of type string; however, parameter $month of DERHANSEN\SfEventMgt\Ser...ervice::getDateConfig() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

201
                'previousMonthConfig' => $this->calendarService->getDateConfig(/** @scrutinizer ignore-type */ $currentMonth, $currentYear, '-1 month'),
Loading history...
Bug introduced by
It seems like $currentYear can also be of type string; however, parameter $year of DERHANSEN\SfEventMgt\Ser...ervice::getDateConfig() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

201
                'previousMonthConfig' => $this->calendarService->getDateConfig($currentMonth, /** @scrutinizer ignore-type */ $currentYear, '-1 month'),
Loading history...
202
                'nextMonthConfig' => $this->calendarService->getDateConfig($currentMonth, $currentYear, '+1 month')
203
            ],
204
            $this
205
        );
206
        $this->eventDispatcher->dispatch($modifyCalendarViewVariablesEvent);
207
        $variables = $modifyCalendarViewVariablesEvent->getVariables();
208
209
        $this->view->assignMultiple($variables);
210
    }
211
212
    /**
213
     * Changes the given event demand object to select a date range for a calendar month including days of the previous
214
     * month for the first week and they days for the next month for the last week
215
     *
216
     * @param EventDemand $eventDemand
217
     * @return EventDemand
218
     */
219
    protected function changeEventDemandToFullMonthDateRange(EventDemand $eventDemand)
220
    {
221
        $calendarDateRange = $this->calendarService->getCalendarDateRange(
222
            $eventDemand->getMonth(),
223
            $eventDemand->getYear(),
224
            $this->settings['calendar']['firstDayOfWeek']
225
        );
226
227
        $eventDemand->setMonth(0);
228
        $eventDemand->setYear(0);
229
230
        $startDate = new \DateTime();
231
        $startDate->setTimestamp($calendarDateRange['firstDayOfCalendar']);
232
        $endDate = new \DateTime();
233
        $endDate->setTimestamp($calendarDateRange['lastDayOfCalendar']);
234
        $endDate->setTime(23, 59, 59);
235
236
        $searchDemand = new SearchDemand();
237
        $searchDemand->setStartDate($startDate);
238
        $searchDemand->setEndDate($endDate);
239
        $eventDemand->setSearchDemand($searchDemand);
240
241
        return $eventDemand;
242
    }
243
244
    /**
245
     * Detail view for an event
246
     *
247
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Event $event Event
248
     * @return mixed string|void
249
     */
250
    public function detailAction(Event $event = null)
251
    {
252
        $event = $this->evaluateSingleEventSetting($event);
253
        $event = $this->evaluateIsShortcutSetting($event);
254
        if (is_a($event, Event::class) && $this->settings['detail']['checkPidOfEventRecord']) {
255
            $event = $this->checkPidOfEventRecord($event);
256
        }
257
258
        if (is_null($event) && isset($this->settings['event']['errorHandling'])) {
259
            return $this->handleEventNotFoundError($this->settings);
260
        }
261
262
        $modifyDetailViewVariablesEvent = new ModifyDetailViewVariablesEvent(['event' => $event], $this);
263
        $this->eventDispatcher->dispatch($modifyDetailViewVariablesEvent);
264
        $variables = $modifyDetailViewVariablesEvent->getVariables();
265
266
        $this->view->assignMultiple($variables);
267
        if ($event !== null) {
268
            $this->eventCacheService->addCacheTagsByEventRecords([$event]);
269
        }
270
    }
271
272
    /**
273
     * Error handling if event is not found
274
     *
275
     * @param array $settings
276
     */
277
    protected function handleEventNotFoundError($settings)
278
    {
279
        if (empty($settings['event']['errorHandling'])) {
280
            return null;
281
        }
282
283
        $configuration = GeneralUtility::trimExplode(',', $settings['event']['errorHandling'], true);
284
285
        switch ($configuration[0]) {
286
            case 'redirectToListView':
287
                $listPid = (int)$settings['listPid'] > 0 ? (int)$settings['listPid'] : 1;
288
                $this->redirect('list', null, null, null, $listPid);
289
                break;
290
            case 'pageNotFoundHandler':
291
                $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
292
                    $GLOBALS['TYPO3_REQUEST'],
293
                    'Event not found.'
294
                );
295
                throw new ImmediateResponseException($response, 1549896549);
296
            case 'showStandaloneTemplate':
297
                if (isset($configuration[2])) {
298
                    $statusCode = constant(HttpUtility::class . '::HTTP_STATUS_' . $configuration[2]);
299
                    HttpUtility::setResponseCode($statusCode);
0 ignored issues
show
Deprecated Code introduced by
The function TYPO3\CMS\Core\Utility\H...lity::setResponseCode() has been deprecated: since v11, will be removed in v12. ( Ignorable by Annotation )

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

299
                    /** @scrutinizer ignore-deprecated */ HttpUtility::setResponseCode($statusCode);

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...
300
                }
301
                $standaloneTemplate = GeneralUtility::makeInstance(StandaloneView::class);
302
                $standaloneTemplate->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($configuration[1]));
303
304
                return $standaloneTemplate->render();
305
            default:
306
        }
307
    }
308
309
    /**
310
     * Initiates the iCalendar download for the given event
311
     *
312
     * @param Event $event The event
313
     *
314
     * @return string|false
315
     */
316
    public function icalDownloadAction(Event $event = null)
317
    {
318
        if (is_a($event, Event::class) && $this->settings['detail']['checkPidOfEventRecord']) {
319
            $event = $this->checkPidOfEventRecord($event);
320
        }
321
        if (is_null($event) && isset($this->settings['event']['errorHandling'])) {
322
            return $this->handleEventNotFoundError($this->settings);
323
        }
324
        $this->icalendarService->downloadiCalendarFile($event);
0 ignored issues
show
Bug introduced by
It seems like $event can also be of type null; however, parameter $event of DERHANSEN\SfEventMgt\Ser...downloadiCalendarFile() does only seem to accept DERHANSEN\SfEventMgt\Domain\Model\Event, maybe add an additional type check? ( Ignorable by Annotation )

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

324
        $this->icalendarService->downloadiCalendarFile(/** @scrutinizer ignore-type */ $event);
Loading history...
325
        exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
326
    }
327
328
    /**
329
     * Registration view for an event
330
     *
331
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Event $event Event
332
     *
333
     * @return mixed string|void
334
     */
335
    public function registrationAction(Event $event = null)
336
    {
337
        $event = $this->evaluateSingleEventSetting($event);
338
        if (is_a($event, Event::class) && $this->settings['registration']['checkPidOfEventRecord']) {
339
            $event = $this->checkPidOfEventRecord($event);
340
        }
341
        if (is_null($event) && isset($this->settings['event']['errorHandling'])) {
342
            return $this->handleEventNotFoundError($this->settings);
343
        }
344
        if ($event->getRestrictPaymentMethods()) {
345
            $paymentMethods = $this->paymentService->getRestrictedPaymentMethods($event);
346
        } else {
347
            $paymentMethods = $this->paymentService->getPaymentMethods();
348
        }
349
350
        $modifyRegistrationViewVariablesEvent = new ModifyRegistrationViewVariablesEvent(
351
            [
352
                'event' => $event,
353
                'paymentMethods' => $paymentMethods,
354
            ],
355
            $this
356
        );
357
        $this->eventDispatcher->dispatch($modifyRegistrationViewVariablesEvent);
358
        $variables = $modifyRegistrationViewVariablesEvent->getVariables();
359
        $this->view->assignMultiple($variables);
360
    }
361
362
    /**
363
     * Removes all possible spamcheck fields (which do not belong to the domain model) from arguments.
364
     */
365
    protected function removePossibleSpamCheckFieldsFromArguments()
366
    {
367
        $arguments = $this->request->getArguments();
368
        if (!isset($arguments['event'])) {
369
            return;
370
        }
371
372
        // Remove a possible honeypot field
373
        $honeypotField = 'hp' . (int)$arguments['event'];
374
        if (isset($arguments['registration'][$honeypotField])) {
375
            unset($arguments['registration'][$honeypotField]);
376
        }
377
378
        // Remove a possible challenge/response field
379
        if (isset($arguments['registration']['cr-response'])) {
380
            unset($arguments['registration']['cr-response']);
381
        }
382
383
        $this->request->setArguments($arguments);
384
    }
385
386
    /**
387
     * Processes incoming registrations fields and adds field values to arguments
388
     */
389
    protected function setRegistrationFieldValuesToArguments()
390
    {
391
        $arguments = $this->request->getArguments();
392
        if (!isset($arguments['event'])) {
393
            return;
394
        }
395
396
        /** @var Event $event */
397
        $event = $this->eventRepository->findByUid((int)$this->request->getArgument('event'));
398
        if (!$event || $event->getRegistrationFields()->count() === 0) {
0 ignored issues
show
introduced by
$event is of type DERHANSEN\SfEventMgt\Domain\Model\Event, thus it always evaluated to true.
Loading history...
399
            return;
400
        }
401
402
        $registrationMvcArgument = $this->arguments->getArgument('registration');
403
        $propertyMapping = $registrationMvcArgument->getPropertyMappingConfiguration();
404
        $propertyMapping->allowProperties('fieldValues');
405
        $propertyMapping->allowCreationForSubProperty('fieldValues');
406
        $propertyMapping->allowModificationForSubProperty('fieldValues');
407
408
        // allow creation of new objects (for validation)
409
        $propertyMapping->setTypeConverterOptions(
410
            PersistentObjectConverter::class,
411
            [
412
                PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => true,
413
                PersistentObjectConverter::CONFIGURATION_MODIFICATION_ALLOWED => true
414
            ]
415
        );
416
417
        // Set event to registration (required for validation)
418
        $propertyMapping->allowProperties('event');
419
        $propertyMapping->allowCreationForSubProperty('event');
420
        $propertyMapping->allowModificationForSubProperty('event');
421
        $arguments['registration']['event'] = (int)$this->request->getArgument('event');
422
423
        $index = 0;
424
        foreach ((array)$arguments['registration']['fields'] as $fieldUid => $value) {
425
            // Only accept registration fields of the current event
426
            if (!in_array((int)$fieldUid, $event->getRegistrationFieldsUids(), true)) {
427
                continue;
428
            }
429
430
            // allow subvalues in new property mapper
431
            $propertyMapping->forProperty('fieldValues')->allowProperties($index);
432
            $propertyMapping->forProperty('fieldValues.' . $index)->allowAllProperties();
433
            $propertyMapping->allowCreationForSubProperty('fieldValues.' . $index);
434
            $propertyMapping->allowModificationForSubProperty('fieldValues.' . $index);
435
436
            if (is_array($value)) {
437
                if (empty($value)) {
438
                    $value = '';
439
                } else {
440
                    $value = json_encode($value);
441
                }
442
            }
443
444
            /** @var Registration\Field $field */
445
            $field = $this->fieldRepository->findByUid((int)$fieldUid);
446
447
            $arguments['registration']['fieldValues'][$index] = [
448
                'pid' => $field->getPid(),
449
                'value' => $value,
450
                'field' => (string)$fieldUid,
451
                'valueType' => $field->getValueType()
452
            ];
453
454
            $index++;
455
        }
456
457
        // Remove temporary "fields" field
458
        if (isset($arguments['registration']['fields'])) {
459
            $arguments = ArrayUtility::removeByPath($arguments, 'registration/fields');
460
        }
461
        $this->request->setArguments($arguments);
462
    }
463
464
    /**
465
     * Set date format for field dateOfBirth
466
     */
467
    public function initializeSaveRegistrationAction()
468
    {
469
        $this->arguments->getArgument('registration')
470
            ->getPropertyMappingConfiguration()->forProperty('dateOfBirth')
471
            ->setTypeConverterOption(
472
                DateTimeConverter::class,
473
                DateTimeConverter::CONFIGURATION_DATE_FORMAT,
474
                $this->settings['registration']['formatDateOfBirth']
475
            );
476
        $this->removePossibleSpamCheckFieldsFromArguments();
477
        $this->setRegistrationFieldValuesToArguments();
478
    }
479
480
    /**
481
     * Saves the registration
482
     *
483
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Registration $registration Registration
484
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Event $event Event
485
     * @Extbase\Validate("DERHANSEN\SfEventMgt\Validation\Validator\RegistrationFieldValidator", param="registration")
486
     * @Extbase\Validate("DERHANSEN\SfEventMgt\Validation\Validator\RegistrationValidator", param="registration")
487
     *
488
     * @return mixed string|void
489
     */
490
    public function saveRegistrationAction(Registration $registration, Event $event)
491
    {
492
        if (is_a($event, Event::class) && $this->settings['registration']['checkPidOfEventRecord']) {
493
            $event = $this->checkPidOfEventRecord($event);
494
        }
495
        if (is_null($event) && isset($this->settings['event']['errorHandling'])) {
496
            return $this->handleEventNotFoundError($this->settings);
497
        }
498
        $autoConfirmation = (bool)$this->settings['registration']['autoConfirmation'] || $event->getEnableAutoconfirm();
499
        $result = RegistrationResult::REGISTRATION_SUCCESSFUL;
500
        list($success, $result) = $this->registrationService->checkRegistrationSuccess($event, $registration, $result);
501
502
        // Save registration if no errors
503
        if ($success) {
504
            $isWaitlistRegistration = $this->registrationService->isWaitlistRegistration(
505
                $event,
506
                $registration->getAmountOfRegistrations()
507
            );
508
            $linkValidity = (int)$this->settings['confirmation']['linkValidity'];
509
            if ($linkValidity === 0) {
510
                // Use 3600 seconds as default value if not set
511
                $linkValidity = 3600;
512
            }
513
            $confirmationUntil = new \DateTime();
514
            $confirmationUntil->add(new \DateInterval('PT' . $linkValidity . 'S'));
515
516
            $registration->setEvent($event);
517
            $registration->setPid($event->getPid());
518
            $registration->setRegistrationDate(new \DateTime());
519
            $registration->setConfirmationUntil($confirmationUntil);
520
            $registration->setLanguage($this->getCurrentLanguageTwoLetterIsoCode());
521
            $registration->setFeUser($this->registrationService->getCurrentFeUserObject());
522
            $registration->setWaitlist($isWaitlistRegistration);
523
            $this->registrationRepository->add($registration);
524
525
            // Persist registration, so we have an UID
526
            $this->persistAll();
527
528
            if ($isWaitlistRegistration) {
529
                $messageType = MessageType::REGISTRATION_WAITLIST_NEW;
530
            } else {
531
                $messageType = MessageType::REGISTRATION_NEW;
532
            }
533
534
            $this->eventDispatcher->dispatch(new AfterRegistrationSavedEvent($registration, $this));
535
536
            // Send notifications to user and admin if confirmation link should be sent
537
            if (!$autoConfirmation) {
538
                $this->notificationService->sendUserMessage(
539
                    $event,
540
                    $registration,
541
                    $this->settings,
542
                    $messageType
543
                );
544
                $this->notificationService->sendAdminMessage(
545
                    $event,
546
                    $registration,
547
                    $this->settings,
548
                    $messageType
549
                );
550
            }
551
552
            // Create given amount of registrations if necessary
553
            $modifyCreateDependingRegistrationsEvent = new ModifyCreateDependingRegistrationsEvent(
554
                $registration,
555
                ($registration->getAmountOfRegistrations() > 1),
556
                $this
557
            );
558
            $this->eventDispatcher->dispatch($modifyCreateDependingRegistrationsEvent);
559
            $createDependingRegistrations = $modifyCreateDependingRegistrationsEvent->getCreateDependingRegistrations();
560
            if ($createDependingRegistrations) {
561
                $this->registrationService->createDependingRegistrations($registration);
562
            }
563
564
            // Flush page cache for event, since new registration has been added
565
            $this->eventCacheService->flushEventCache($event->getUid(), $event->getPid());
566
        }
567
568
        if ($autoConfirmation && $success) {
569
            $this->redirect(
570
                'confirmRegistration',
571
                null,
572
                null,
573
                [
574
                    'reguid' => $registration->getUid(),
575
                    'hmac' => $this->hashService->generateHmac('reg-' . $registration->getUid())
576
                ]
577
            );
578
        } else {
579
            $this->redirect(
580
                'saveRegistrationResult',
581
                null,
582
                null,
583
                [
584
                    'result' => $result,
585
                    'eventuid' => $event->getUid(),
586
                    'hmac' => $this->hashService->generateHmac('event-' . $event->getUid())
587
                ]
588
            );
589
        }
590
    }
591
592
    /**
593
     * Shows the result of the saveRegistrationAction
594
     *
595
     * @param int $result Result
596
     * @param int $eventuid
597
     * @param string $hmac
598
     */
599
    public function saveRegistrationResultAction($result, $eventuid, $hmac)
600
    {
601
        $event = null;
602
603
        switch ($result) {
604
            case RegistrationResult::REGISTRATION_SUCCESSFUL:
605
                $messageKey = 'event.message.registrationsuccessful';
606
                $titleKey = 'registrationResult.title.successful';
607
                break;
608
            case RegistrationResult::REGISTRATION_SUCCESSFUL_WAITLIST:
609
                $messageKey = 'event.message.registrationwaitlistsuccessful';
610
                $titleKey = 'registrationWaitlistResult.title.successful';
611
                break;
612
            case RegistrationResult::REGISTRATION_FAILED_EVENT_EXPIRED:
613
                $messageKey = 'event.message.registrationfailedeventexpired';
614
                $titleKey = 'registrationResult.title.failed';
615
                break;
616
            case RegistrationResult::REGISTRATION_FAILED_MAX_PARTICIPANTS:
617
                $messageKey = 'event.message.registrationfailedmaxparticipants';
618
                $titleKey = 'registrationResult.title.failed';
619
                break;
620
            case RegistrationResult::REGISTRATION_NOT_ENABLED:
621
                $messageKey = 'event.message.registrationfailednotenabled';
622
                $titleKey = 'registrationResult.title.failed';
623
                break;
624
            case RegistrationResult::REGISTRATION_FAILED_DEADLINE_EXPIRED:
625
                $messageKey = 'event.message.registrationfaileddeadlineexpired';
626
                $titleKey = 'registrationResult.title.failed';
627
                break;
628
            case RegistrationResult::REGISTRATION_FAILED_NOT_ENOUGH_FREE_PLACES:
629
                $messageKey = 'event.message.registrationfailednotenoughfreeplaces';
630
                $titleKey = 'registrationResult.title.failed';
631
                break;
632
            case RegistrationResult::REGISTRATION_FAILED_MAX_AMOUNT_REGISTRATIONS_EXCEEDED:
633
                $messageKey = 'event.message.registrationfailedmaxamountregistrationsexceeded';
634
                $titleKey = 'registrationResult.title.failed';
635
                break;
636
            case RegistrationResult::REGISTRATION_FAILED_EMAIL_NOT_UNIQUE:
637
                $messageKey = 'event.message.registrationfailedemailnotunique';
638
                $titleKey = 'registrationResult.title.failed';
639
                break;
640
            default:
641
                $messageKey = '';
642
                $titleKey = '';
643
        }
644
645
        if (!$this->hashService->validateHmac('event-' . $eventuid, $hmac)) {
646
            $messageKey = 'event.message.registrationsuccessfulwrongeventhmac';
647
            $titleKey = 'registrationResult.title.failed';
648
        } else {
649
            $event = $this->eventRepository->findByUid((int)$eventuid);
650
        }
651
652
        $this->view->assignMultiple([
653
            'messageKey' => $messageKey,
654
            'titleKey' => $titleKey,
655
            'event' => $event,
656
        ]);
657
    }
658
659
    /**
660
     * Confirms the registration if possible and sends emails to admin and user
661
     *
662
     * @param int $reguid UID of registration
663
     * @param string $hmac HMAC for parameters
664
     */
665
    public function confirmRegistrationAction($reguid, $hmac)
666
    {
667
        $event = null;
668
669
        /* @var $registration Registration */
670
        list($failed, $registration, $messageKey, $titleKey) = $this->registrationService->checkConfirmRegistration(
671
            $reguid,
672
            $hmac
673
        );
674
675
        if ($failed === false) {
676
            $registration->setConfirmed(true);
677
            $event = $registration->getEvent();
678
            $this->registrationRepository->update($registration);
679
680
            $this->eventDispatcher->dispatch(new AfterRegistrationConfirmedEvent($registration, $this));
681
682
            $messageType = MessageType::REGISTRATION_CONFIRMED;
683
            if ($registration->getWaitlist()) {
684
                $messageType = MessageType::REGISTRATION_WAITLIST_CONFIRMED;
685
            }
686
687
            // Send notifications to user and admin
688
            $this->notificationService->sendUserMessage(
689
                $registration->getEvent(),
690
                $registration,
691
                $this->settings,
692
                $messageType
693
            );
694
            $this->notificationService->sendAdminMessage(
695
                $registration->getEvent(),
696
                $registration,
697
                $this->settings,
698
                $messageType
699
            );
700
701
            // Confirm registrations depending on main registration if necessary
702
            if ($registration->getAmountOfRegistrations() > 1) {
703
                $this->registrationService->confirmDependingRegistrations($registration);
704
            }
705
        }
706
707
        // Redirect to payment provider if payment/redirect is enabled
708
        $paymentPid = (int)$this->settings['paymentPid'];
709
        if (!$failed && $paymentPid > 0 && $this->registrationService->redirectPaymentEnabled($registration)) {
710
            $this->uriBuilder->reset()
711
                ->setTargetPageUid($paymentPid);
712
            $uri = $this->uriBuilder->uriFor(
713
                'redirect',
714
                [
715
                    'registration' => $registration,
716
                    'hmac' => $this->hashService->generateHmac('redirectAction-' . $registration->getUid())
717
                ],
718
                'Payment',
719
                'sfeventmgt',
720
                'Pipayment'
721
            );
722
            $this->redirectToUri($uri);
723
        }
724
725
        $modifyConfirmRegistrationViewVariablesEvent = new ModifyConfirmRegistrationViewVariablesEvent(
726
            [
727
                'failed' => $failed,
728
                'messageKey' => $messageKey,
729
                'titleKey' => $titleKey,
730
                'event' => $event,
731
                'registration' => $registration,
732
            ],
733
            $this
734
        );
735
        $this->eventDispatcher->dispatch($modifyConfirmRegistrationViewVariablesEvent);
736
        $variables = $modifyConfirmRegistrationViewVariablesEvent->getVariables();
737
        $this->view->assignMultiple($variables);
738
    }
739
740
    /**
741
     * Cancels the registration if possible and sends emails to admin and user
742
     *
743
     * @param int $reguid UID of registration
744
     * @param string $hmac HMAC for parameters
745
     */
746
    public function cancelRegistrationAction($reguid, $hmac)
747
    {
748
        $event = null;
749
750
        /* @var $registration Registration */
751
        list($failed, $registration, $messageKey, $titleKey) =
752
            $this->registrationService->checkCancelRegistration($reguid, $hmac);
753
754
        if ($failed === false) {
755
            $event = $registration->getEvent();
756
757
            // Send notifications (must run before cancelling the registration)
758
            $this->notificationService->sendUserMessage(
759
                $registration->getEvent(),
760
                $registration,
761
                $this->settings,
762
                MessageType::REGISTRATION_CANCELLED
763
            );
764
            $this->notificationService->sendAdminMessage(
765
                $registration->getEvent(),
766
                $registration,
767
                $this->settings,
768
                MessageType::REGISTRATION_CANCELLED
769
            );
770
771
            // First cancel depending registrations
772
            if ($registration->getAmountOfRegistrations() > 1) {
773
                $this->registrationService->cancelDependingRegistrations($registration);
774
            }
775
776
            // Finally cancel registration
777
            $this->registrationRepository->remove($registration);
778
779
            // Persist changes, so following functions can work with $event properties (e.g. amount of registrations)
780
            $this->persistAll();
781
782
            // Dispatch event, so waitlist registrations can be moved up and default move up process can be stopped
783
            $waitlistMoveUpEvent = new WaitlistMoveUpEvent($event, $this, true);
784
            $this->eventDispatcher->dispatch($waitlistMoveUpEvent);
785
786
            // Move up waitlist registrations if configured on event basis and if not disabled by $waitlistMoveUpEvent
787
            if ($waitlistMoveUpEvent->getProcessDefaultMoveUp()) {
788
                $this->registrationService->moveUpWaitlistRegistrations($event, $this->settings);
789
            }
790
791
            // Flush page cache for event, since amount of registrations has changed
792
            $this->eventCacheService->flushEventCache($event->getUid(), $event->getPid());
0 ignored issues
show
Bug introduced by
It seems like $event->getPid() can also be of type null; however, parameter $eventPid of DERHANSEN\SfEventMgt\Ser...vice::flushEventCache() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

792
            $this->eventCacheService->flushEventCache($event->getUid(), /** @scrutinizer ignore-type */ $event->getPid());
Loading history...
Bug introduced by
It seems like $event->getUid() can also be of type null; however, parameter $eventUid of DERHANSEN\SfEventMgt\Ser...vice::flushEventCache() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

792
            $this->eventCacheService->flushEventCache(/** @scrutinizer ignore-type */ $event->getUid(), $event->getPid());
Loading history...
793
        }
794
795
        $modifyCancelRegistrationViewVariablesEvent = new ModifyCancelRegistrationViewVariablesEvent(
796
            [
797
                'failed' => $failed,
798
                'messageKey' => $messageKey,
799
                'titleKey' => $titleKey,
800
                'event' => $event,
801
            ],
802
            $this
803
        );
804
        $this->eventDispatcher->dispatch($modifyCancelRegistrationViewVariablesEvent);
805
        $variables = $modifyCancelRegistrationViewVariablesEvent->getVariables();
806
        $this->view->assignMultiple($variables);
807
    }
808
809
    /**
810
     * Set date format for field startDate and endDate
811
     */
812
    public function initializeSearchAction()
813
    {
814
        if ($this->settings !== null && $this->settings['search']['dateFormat']) {
815
            $this->arguments->getArgument('searchDemand')
816
                ->getPropertyMappingConfiguration()->forProperty('startDate')
817
                ->setTypeConverterOption(
818
                    DateTimeConverter::class,
819
                    DateTimeConverter::CONFIGURATION_DATE_FORMAT,
820
                    $this->settings['search']['dateFormat']
821
                );
822
            $this->arguments->getArgument('searchDemand')
823
                ->getPropertyMappingConfiguration()->forProperty('endDate')
824
                ->setTypeConverterOption(
825
                    DateTimeConverter::class,
826
                    DateTimeConverter::CONFIGURATION_DATE_FORMAT,
827
                    $this->settings['search']['dateFormat']
828
                );
829
        }
830
        if ($this->arguments->hasArgument('searchDemand')) {
831
            $propertyMappingConfiguration = $this->arguments->getArgument('searchDemand')
832
                ->getPropertyMappingConfiguration();
833
            $propertyMappingConfiguration->allowAllProperties();
834
            $propertyMappingConfiguration->setTypeConverterOption(
835
                PersistentObjectConverter::class,
836
                PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED,
837
                true
838
            );
839
        }
840
    }
841
842
    /**
843
     * Search view
844
     *
845
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Dto\SearchDemand $searchDemand SearchDemand
846
     * @param array $overwriteDemand OverwriteDemand
847
     */
848
    public function searchAction(SearchDemand $searchDemand = null, array $overwriteDemand = [])
849
    {
850
        $eventDemand = EventDemand::createFromSettings($this->settings);
851
        $eventDemand->setSearchDemand($searchDemand);
852
        $foreignRecordDemand = ForeignRecordDemand::createFromSettings($this->settings);
853
        $categoryDemand = CategoryDemand::createFromSettings($this->settings);
854
855
        if ($searchDemand !== null) {
856
            $searchDemand->setFields($this->settings['search']['fields']);
857
858
            if ($this->settings['search']['adjustTime'] && $searchDemand->getStartDate() !== null) {
859
                $searchDemand->getStartDate()->setTime(0, 0, 0);
860
            }
861
862
            if ($this->settings['search']['adjustTime'] && $searchDemand->getEndDate() !== null) {
863
                $searchDemand->getEndDate()->setTime(23, 59, 59);
864
            }
865
        }
866
867
        if ($this->isOverwriteDemand($overwriteDemand)) {
868
            $eventDemand = $this->overwriteEventDemandObject($eventDemand, $overwriteDemand);
869
        }
870
871
        $categories = $this->categoryRepository->findDemanded($categoryDemand);
872
        $locations = $this->locationRepository->findDemanded($foreignRecordDemand);
873
        $organisators = $this->organisatorRepository->findDemanded($foreignRecordDemand);
874
        $speakers = $this->speakerRepository->findDemanded($foreignRecordDemand);
875
        $events = $this->eventRepository->findDemanded($eventDemand);
876
877
        $modifySearchViewVariablesEvent = new ModifySearchViewVariablesEvent(
878
            [
879
                'events' => $events,
880
                'categories' => $categories,
881
                'locations' => $locations,
882
                'organisators' => $organisators,
883
                'speakers' => $speakers,
884
                'searchDemand' => $searchDemand,
885
                'overwriteDemand' => $overwriteDemand,
886
            ],
887
            $this
888
        );
889
        $this->eventDispatcher->dispatch($modifySearchViewVariablesEvent);
890
        $variables = $modifySearchViewVariablesEvent->getVariables();
891
        $this->view->assignMultiple($variables);
892
    }
893
894
    /**
895
     * Returns if a demand object can be overwritten with the given overwriteDemand array
896
     *
897
     * @param array $overwriteDemand
898
     * @return bool
899
     */
900
    protected function isOverwriteDemand($overwriteDemand)
901
    {
902
        return $this->settings['disableOverrideDemand'] != 1 && $overwriteDemand !== [];
903
    }
904
905
    /**
906
     * If no event is given and the singleEvent setting is set, the configured single event is returned
907
     *
908
     * @param Event|null $event
909
     * @return Event|null
910
     */
911
    protected function evaluateSingleEventSetting($event)
912
    {
913
        if ($event === null && (int)$this->settings['singleEvent'] > 0) {
914
            $event = $this->eventRepository->findByUid((int)$this->settings['singleEvent']);
915
        }
916
917
        return $event;
918
    }
919
920
    /**
921
     * If no event is given and the isShortcut setting is set, the event is displayed using the "Insert Record"
922
     * content element and should be loaded from contect object data
923
     *
924
     * @param Event|null $event
925
     * @return Event|null
926
     */
927
    protected function evaluateIsShortcutSetting($event)
928
    {
929
        if ($event === null && (bool)$this->settings['detail']['isShortcut']) {
930
            $eventRawData = $this->configurationManager->getContentObject()->data;
931
            $event = $this->eventRepository->findByUid($eventRawData['uid']);
932
        }
933
934
        return $event;
935
    }
936
937
    /**
938
     * Checks if the event pid could be found in the storagePage settings of the detail plugin and
939
     * if the pid could not be found it return null instead of the event object.
940
     *
941
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Event $event
942
     * @return \DERHANSEN\SfEventMgt\Domain\Model\Event|null
943
     */
944
    protected function checkPidOfEventRecord(Event $event): ?Event
945
    {
946
        $allowedStoragePages = GeneralUtility::trimExplode(
947
            ',',
948
            PageUtility::extendPidListByChildren(
949
                $this->settings['storagePage'] ?? '',
950
                $this->settings['recursive'] ?? 0
951
            ),
952
            true
953
        );
954
        if (count($allowedStoragePages) > 0 && !in_array($event->getPid(), $allowedStoragePages)) {
955
            $this->eventDispatcher->dispatch(new EventPidCheckFailedEvent($event, $this));
956
            $event = null;
957
        }
958
959
        return $event;
960
    }
961
962
    /**
963
     * Calls persistAll() of the persistenceManager
964
     */
965
    protected function persistAll()
966
    {
967
        $this->objectManager->get(PersistenceManager::class)->persistAll();
0 ignored issues
show
Deprecated Code introduced by
The function TYPO3\CMS\Extbase\Object...ManagerInterface::get() has been deprecated: since TYPO3 10.4, will be removed in version 12.0 ( Ignorable by Annotation )

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

967
        /** @scrutinizer ignore-deprecated */ $this->objectManager->get(PersistenceManager::class)->persistAll();

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...
Deprecated Code introduced by
The property TYPO3\CMS\Extbase\Mvc\Co...troller::$objectManager has been deprecated: since v11, will be removed in v12 ( Ignorable by Annotation )

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

967
        /** @scrutinizer ignore-deprecated */ $this->objectManager->get(PersistenceManager::class)->persistAll();

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
968
    }
969
970
    /**
971
     * Returns the current sys_language_uid
972
     *
973
     * @return int
974
     */
975
    protected function getSysLanguageUid(): int
976
    {
977
        $languageAspect = GeneralUtility::makeInstance(Context::class)->getAspect('language');
978
979
        return $languageAspect->getId();
980
    }
981
982
    /**
983
     * Returns the two letter ISO code for the current language
984
     *
985
     * @return string
986
     */
987
    protected function getCurrentLanguageTwoLetterIsoCode(): string
988
    {
989
        if ($GLOBALS['TYPO3_REQUEST'] instanceof ServerRequestInterface &&
990
            $GLOBALS['TYPO3_REQUEST']->getAttribute('language') instanceof SiteLanguage
991
        ) {
992
            /** @var SiteLanguage $siteLanguage */
993
            $siteLanguage = $GLOBALS['TYPO3_REQUEST']->getAttribute('language');
994
            return $siteLanguage->getTwoLetterIsoCode();
995
        }
996
997
        return '';
998
    }
999
}
1000