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

EventController::evaluateEventPreviewSetting()   A

Complexity

Conditions 6
Paths 4

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 10
nc 4
nop 1
dl 0
loc 16
rs 9.2222
c 0
b 0
f 0
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\Controller;
13
14
use DateInterval;
15
use DateTime;
16
use DERHANSEN\SfEventMgt\Domain\Model\Dto\CategoryDemand;
17
use DERHANSEN\SfEventMgt\Domain\Model\Dto\EventDemand;
18
use DERHANSEN\SfEventMgt\Domain\Model\Dto\ForeignRecordDemand;
19
use DERHANSEN\SfEventMgt\Domain\Model\Dto\SearchDemand;
20
use DERHANSEN\SfEventMgt\Domain\Model\Event;
21
use DERHANSEN\SfEventMgt\Domain\Model\Registration;
22
use DERHANSEN\SfEventMgt\Event\AfterRegistrationCancelledEvent;
23
use DERHANSEN\SfEventMgt\Event\AfterRegistrationConfirmedEvent;
24
use DERHANSEN\SfEventMgt\Event\AfterRegistrationSavedEvent;
25
use DERHANSEN\SfEventMgt\Event\EventPidCheckFailedEvent;
26
use DERHANSEN\SfEventMgt\Event\ModifyCalendarViewVariablesEvent;
27
use DERHANSEN\SfEventMgt\Event\ModifyCancelRegistrationViewVariablesEvent;
28
use DERHANSEN\SfEventMgt\Event\ModifyConfirmRegistrationViewVariablesEvent;
29
use DERHANSEN\SfEventMgt\Event\ModifyCreateDependingRegistrationsEvent;
30
use DERHANSEN\SfEventMgt\Event\ModifyDetailViewVariablesEvent;
31
use DERHANSEN\SfEventMgt\Event\ModifyListViewVariablesEvent;
32
use DERHANSEN\SfEventMgt\Event\ModifyRegistrationViewVariablesEvent;
33
use DERHANSEN\SfEventMgt\Event\ModifySearchViewVariablesEvent;
34
use DERHANSEN\SfEventMgt\Event\ProcessCancelDependingRegistrationsEvent;
35
use DERHANSEN\SfEventMgt\Event\ProcessRedirectToPaymentEvent;
36
use DERHANSEN\SfEventMgt\Event\WaitlistMoveUpEvent;
37
use DERHANSEN\SfEventMgt\Exception;
38
use DERHANSEN\SfEventMgt\Service\EventCacheService;
39
use DERHANSEN\SfEventMgt\Utility\MessageType;
40
use DERHANSEN\SfEventMgt\Utility\PageUtility;
41
use DERHANSEN\SfEventMgt\Utility\RegistrationResult;
42
use Psr\Http\Message\ResponseInterface;
43
use TYPO3\CMS\Core\Context\Context;
44
use TYPO3\CMS\Core\Error\Http\PageNotFoundException;
45
use TYPO3\CMS\Core\Http\PropagateResponseException;
46
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
47
use TYPO3\CMS\Core\Utility\ArrayUtility;
48
use TYPO3\CMS\Core\Utility\GeneralUtility;
49
use TYPO3\CMS\Extbase\Annotation as Extbase;
0 ignored issues
show
Bug introduced by
The type TYPO3\CMS\Extbase\Annotation 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...
50
use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
0 ignored issues
show
Bug introduced by
The type TYPO3\CMS\Extbase\Persis...eric\PersistenceManager 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...
51
use TYPO3\CMS\Extbase\Property\TypeConverter\DateTimeConverter;
0 ignored issues
show
Bug introduced by
The type TYPO3\CMS\Extbase\Proper...erter\DateTimeConverter 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...
52
use TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter;
0 ignored issues
show
Bug introduced by
The type TYPO3\CMS\Extbase\Proper...rsistentObjectConverter 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...
53
use TYPO3\CMS\Fluid\View\StandaloneView;
0 ignored issues
show
Bug introduced by
The type TYPO3\CMS\Fluid\View\StandaloneView 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...
54
use TYPO3\CMS\Frontend\Controller\ErrorController;
0 ignored issues
show
Bug introduced by
The type TYPO3\CMS\Frontend\Controller\ErrorController 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...
55
56
class EventController extends AbstractController
57
{
58
    protected EventCacheService $eventCacheService;
59
60
    public function injectEventCacheService(EventCacheService $cacheService): void
61
    {
62
        $this->eventCacheService = $cacheService;
63
    }
64
65
    /**
66
     * Assign contentObjectData and pageData view
67
     */
68
    protected function initializeView(): void
69
    {
70
        $this->view->assign('contentObjectData', $this->request->getAttribute('currentContentObject')->data ?? null);
71
        if ($this->getTypoScriptFrontendController()) {
72
            $this->view->assign('pageData', $this->getTypoScriptFrontendController()->page);
73
        }
74
    }
75
76
    /**
77
     * Initializes the current action
78
     */
79
    public function initializeAction(): void
80
    {
81
        $typoScriptFrontendController = $this->getTypoScriptFrontendController();
82
        if ($typoScriptFrontendController !== null) {
83
            static $cacheTagsSet = false;
84
85
            if (!$cacheTagsSet) {
86
                $typoScriptFrontendController->addCacheTags(['tx_sfeventmgt']);
87
                $cacheTagsSet = true;
88
            }
89
        }
90
    }
91
92
    /**
93
     * Initialize list action and set format
94
     */
95
    public function initializeListAction(): void
96
    {
97
        if (isset($this->settings['list']['format'])) {
98
            $this->request = $this->request->withFormat($this->settings['list']['format']);
0 ignored issues
show
Bug Best Practice introduced by
The property request does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
99
        }
100
    }
101
102
    /**
103
     * List view
104
     */
105
    public function listAction(array $overwriteDemand = []): ResponseInterface
106
    {
107
        $eventDemand = EventDemand::createFromSettings($this->settings);
108
        $foreignRecordDemand = ForeignRecordDemand::createFromSettings($this->settings);
109
        $categoryDemand = CategoryDemand::createFromSettings($this->settings);
110
        if ($this->isOverwriteDemand($overwriteDemand)) {
111
            $eventDemand = $this->overwriteEventDemandObject($eventDemand, $overwriteDemand);
112
        }
113
        $events = $this->eventRepository->findDemanded($eventDemand);
114
        $categories = $this->categoryRepository->findDemanded($categoryDemand);
115
        $locations = $this->locationRepository->findDemanded($foreignRecordDemand);
116
        $organisators = $this->organisatorRepository->findDemanded($foreignRecordDemand);
117
        $speakers = $this->speakerRepository->findDemanded($foreignRecordDemand);
118
119
        $modifyListViewVariablesEvent = new ModifyListViewVariablesEvent(
120
            [
121
                'events' => $events,
122
                'pagination' => $this->getPagination($events, $this->settings['pagination'] ?? []),
123
                'categories' => $categories,
124
                'locations' => $locations,
125
                'organisators' => $organisators,
126
                'speakers' => $speakers,
127
                'overwriteDemand' => $overwriteDemand,
128
                'eventDemand' => $eventDemand,
129
                'settings' => $this->settings,
130
            ],
131
            $this
132
        );
133
        $this->eventDispatcher->dispatch($modifyListViewVariablesEvent);
134
        $variables = $modifyListViewVariablesEvent->getVariables();
135
        $this->view->assignMultiple($variables);
136
137
        $this->eventCacheService->addPageCacheTagsByEventDemandObject($eventDemand);
138
139
        return $this->htmlResponse();
140
    }
141
142
    /**
143
     * Calendar view
144
     */
145
    public function calendarAction(array $overwriteDemand = []): ResponseInterface
146
    {
147
        $eventDemand = EventDemand::createFromSettings($this->settings);
148
        $foreignRecordDemand = ForeignRecordDemand::createFromSettings($this->settings);
149
        $categoryDemand = CategoryDemand::createFromSettings($this->settings);
150
        if ($this->isOverwriteDemand($overwriteDemand)) {
151
            $eventDemand = $this->overwriteEventDemandObject($eventDemand, $overwriteDemand);
152
        }
153
154
        // Set month/year to demand if not given
155
        if (!$eventDemand->getMonth()) {
156
            $currentMonth = (int)date('n');
157
            $eventDemand->setMonth($currentMonth);
158
        } else {
159
            $currentMonth = $eventDemand->getMonth();
160
        }
161
        if (!$eventDemand->getYear()) {
162
            $currentYear = (int)date('Y');
163
            $eventDemand->setYear($currentYear);
164
        } else {
165
            $currentYear = $eventDemand->getYear();
166
        }
167
168
        // If a weeknumber is given in overwriteDemand['week'], we overwrite the current month
169
        if ($overwriteDemand['week'] ?? false) {
170
            $firstDayOfWeek = (new DateTime())->setISODate($currentYear, (int)$overwriteDemand['week']);
171
            $currentMonth = (int)$firstDayOfWeek->format('m');
172
            $eventDemand->setMonth($currentMonth);
173
        } else {
174
            $firstDayOfWeek = (new DateTime())->setISODate($currentYear, (int)date('W'));
175
        }
176
177
        // Set demand from calendar date range instead of month / year
178
        if ((bool)($this->settings['calendar']['includeEventsForEveryDayOfAllCalendarWeeks'] ?? false)) {
179
            $eventDemand = $this->changeEventDemandToFullMonthDateRange($eventDemand);
180
        }
181
182
        $events = $this->eventRepository->findDemanded($eventDemand);
183
        $weeks = $this->calendarService->getCalendarArray(
184
            $currentMonth,
185
            $currentYear,
186
            strtotime('today midnight'),
187
            (int)($this->settings['calendar']['firstDayOfWeek'] ?? 1),
188
            $events
189
        );
190
191
        $modifyCalendarViewVariablesEvent = new ModifyCalendarViewVariablesEvent(
192
            [
193
                'events' => $events,
194
                'weeks' => $weeks,
195
                'categories' => $this->categoryRepository->findDemanded($categoryDemand),
196
                'locations' => $this->locationRepository->findDemanded($foreignRecordDemand),
197
                'organisators' => $this->organisatorRepository->findDemanded($foreignRecordDemand),
198
                'eventDemand' => $eventDemand,
199
                'overwriteDemand' => $overwriteDemand,
200
                'currentPageId' => $this->getTypoScriptFrontendController()->id,
201
                'firstDayOfMonth' => DateTime::createFromFormat(
202
                    'd.m.Y',
203
                    sprintf('1.%s.%s', $currentMonth, $currentYear)
204
                ),
205
                'previousMonthConfig' => $this->calendarService->getDateConfig($currentMonth, $currentYear, '-1 month'),
206
                'nextMonthConfig' => $this->calendarService->getDateConfig($currentMonth, $currentYear, '+1 month'),
207
                'weekConfig' => $this->calendarService->getWeekConfig($firstDayOfWeek),
208
                'settings' => $this->settings,
209
            ],
210
            $this
211
        );
212
        $this->eventDispatcher->dispatch($modifyCalendarViewVariablesEvent);
213
        $variables = $modifyCalendarViewVariablesEvent->getVariables();
214
215
        $this->view->assignMultiple($variables);
216
        return $this->htmlResponse();
217
    }
218
219
    /**
220
     * Changes the given event demand object to select a date range for a calendar month including days of the previous
221
     * month for the first week and they days for the next month for the last week
222
     */
223
    protected function changeEventDemandToFullMonthDateRange(EventDemand $eventDemand): EventDemand
224
    {
225
        $calendarDateRange = $this->calendarService->getCalendarDateRange(
226
            $eventDemand->getMonth(),
227
            $eventDemand->getYear(),
228
            (int)($this->settings['calendar']['firstDayOfWeek'] ?? 0)
229
        );
230
231
        $eventDemand->setMonth(0);
232
        $eventDemand->setYear(0);
233
234
        $startDate = new DateTime();
235
        $startDate->setTimestamp($calendarDateRange['firstDayOfCalendar']);
236
        $endDate = new DateTime();
237
        $endDate->setTimestamp($calendarDateRange['lastDayOfCalendar']);
238
        $endDate->setTime(23, 59, 59);
239
240
        $searchDemand = GeneralUtility::makeInstance(SearchDemand::class);
241
        $searchDemand->setStartDate($startDate);
242
        $searchDemand->setEndDate($endDate);
243
        $eventDemand->setSearchDemand($searchDemand);
244
245
        return $eventDemand;
246
    }
247
248
    /**
249
     * Detail view for an event
250
     *
251
     * @return mixed
252
     */
253
    public function detailAction(?Event $event = null)
254
    {
255
        $event = $this->evaluateSingleEventSetting($event);
256
        $event = $this->evaluateIsShortcutSetting($event);
257
        $event = $this->evaluateEventPreviewSetting($event);
258
        if (is_a($event, Event::class) && ($this->settings['detail']['checkPidOfEventRecord'] ?? false)) {
259
            $event = $this->checkPidOfEventRecord($event);
260
        }
261
262
        if (is_null($event) && isset($this->settings['event']['errorHandling'])) {
263
            return $this->handleEventNotFoundError($this->settings);
264
        }
265
266
        $modifyDetailViewVariablesEvent = new ModifyDetailViewVariablesEvent(['event' => $event, 'settings' => $this->settings], $this);
267
        $this->eventDispatcher->dispatch($modifyDetailViewVariablesEvent);
268
        $variables = $modifyDetailViewVariablesEvent->getVariables();
269
270
        $this->view->assignMultiple($variables);
271
        if ($event !== null) {
272
            $this->eventCacheService->addCacheTagsByEventRecords([$event]);
273
        }
274
275
        return $this->htmlResponse();
276
    }
277
278
    /**
279
     * Error handling if event is not found
280
     *
281
     * @param array $settings
282
     * @return ResponseInterface
283
     * @throws Exception
284
     * @throws PropagateResponseException
285
     * @throws PageNotFoundException
286
     */
287
    protected function handleEventNotFoundError(array $settings): ResponseInterface
288
    {
289
        if (empty($settings['event']['errorHandling'])) {
290
            throw new Exception('Event errorHandling not configured. Please check settings.event.errorHandling', 1671205677);
291
        }
292
293
        $configuration = GeneralUtility::trimExplode(',', $settings['event']['errorHandling'], true);
294
295
        switch ($configuration[0]) {
296
            case 'redirectToListView':
297
                $listPid = (int)($settings['listPid'] ?? 0) > 0 ? (int)$settings['listPid'] : 1;
298
                return $this->redirect('list', null, null, null, $listPid);
299
            case 'pageNotFoundHandler':
300
                $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
301
                    $this->request,
302
                    'Event not found.'
303
                );
304
                throw new PropagateResponseException($response, 1631261423);
305
            case 'showStandaloneTemplate':
306
            default:
307
                $status = (int)($configuration[2] ?? 200);
308
                $standaloneTemplate = GeneralUtility::makeInstance(StandaloneView::class);
309
                $standaloneTemplate->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($configuration[1]));
310
311
                $response = $this->responseFactory->createResponse()
312
                    ->withStatus($status)
313
                    ->withHeader('Content-Type', 'text/html; charset=utf-8');
314
                $response->getBody()->write($standaloneTemplate->render());
315
                return $response;
316
        }
317
    }
318
319
    /**
320
     * Initiates the iCalendar download for the given event
321
     *
322
     * @return mixed
323
     */
324
    public function icalDownloadAction(?Event $event = null)
325
    {
326
        if (is_a($event, Event::class) && ($this->settings['detail']['checkPidOfEventRecord'] ?? false)) {
327
            $event = $this->checkPidOfEventRecord($event);
328
        }
329
        if (is_null($event) && isset($this->settings['event']['errorHandling'])) {
330
            return $this->handleEventNotFoundError($this->settings);
331
        }
332
        $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

332
        $this->icalendarService->downloadiCalendarFile(/** @scrutinizer ignore-type */ $event);
Loading history...
333
        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...
334
    }
335
336
    /**
337
     * Registration view for an event
338
     */
339
    public function registrationAction(?Event $event = null): ResponseInterface
340
    {
341
        $event = $this->evaluateSingleEventSetting($event);
342
        if (is_a($event, Event::class) && ($this->settings['registration']['checkPidOfEventRecord'] ?? false)) {
343
            $event = $this->checkPidOfEventRecord($event);
344
        }
345
        if (is_null($event) && isset($this->settings['event']['errorHandling'])) {
346
            return $this->handleEventNotFoundError($this->settings);
347
        }
348
        if ($event->getRestrictPaymentMethods()) {
349
            $paymentMethods = $this->paymentService->getRestrictedPaymentMethods($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...trictedPaymentMethods() 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

349
            $paymentMethods = $this->paymentService->getRestrictedPaymentMethods(/** @scrutinizer ignore-type */ $event);
Loading history...
350
        } else {
351
            $paymentMethods = $this->paymentService->getPaymentMethods();
352
        }
353
354
        $modifyRegistrationViewVariablesEvent = new ModifyRegistrationViewVariablesEvent(
355
            [
356
                'event' => $event,
357
                'paymentMethods' => $paymentMethods,
358
                'settings' => $this->settings,
359
            ],
360
            $this
361
        );
362
        $this->eventDispatcher->dispatch($modifyRegistrationViewVariablesEvent);
363
        $variables = $modifyRegistrationViewVariablesEvent->getVariables();
364
        $this->view->assignMultiple($variables);
365
366
        return $this->htmlResponse();
367
    }
368
369
    /**
370
     * Removes all possible spamcheck fields (which do not belong to the domain model) from arguments.
371
     */
372
    protected function removePossibleSpamCheckFieldsFromArguments(): void
373
    {
374
        $arguments = $this->request->getArguments();
375
        if (!isset($arguments['event'])) {
376
            return;
377
        }
378
379
        // Remove a possible honeypot field
380
        $honeypotField = 'hp' . (int)$arguments['event'];
381
        if (isset($arguments['registration'][$honeypotField])) {
382
            unset($arguments['registration'][$honeypotField]);
383
        }
384
385
        // Remove a possible challenge/response field
386
        if (isset($arguments['registration']['cr-response'])) {
387
            unset($arguments['registration']['cr-response']);
388
        }
389
390
        $this->request = $this->request->withArguments($arguments);
0 ignored issues
show
Bug Best Practice introduced by
The property request does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
391
    }
392
393
    /**
394
     * Processes incoming registrations fields and adds field values to arguments
395
     */
396
    protected function setRegistrationFieldValuesToArguments(): void
397
    {
398
        $arguments = $this->request->getArguments();
399
        if (!isset($arguments['event'])) {
400
            return;
401
        }
402
403
        /** @var Event $event */
404
        $event = $this->eventRepository->findByUid((int)$this->request->getArgument('event'));
405
        if (!is_a($event, Event::class)) {
406
            return;
407
        }
408
409
        $registrationMvcArgument = $this->arguments->getArgument('registration');
410
        $propertyMapping = $registrationMvcArgument->getPropertyMappingConfiguration();
411
        $propertyMapping->allowProperties('fieldValues');
412
        $propertyMapping->allowCreationForSubProperty('fieldValues');
413
        $propertyMapping->allowModificationForSubProperty('fieldValues');
414
415
        // Set event to registration (required for validation)
416
        $propertyMapping->allowProperties('event');
417
        $propertyMapping->allowCreationForSubProperty('event');
418
        $propertyMapping->allowModificationForSubProperty('event');
419
        $arguments['registration']['event'] = (int)$this->request->getArgument('event');
420
421
        if (count($event->getRegistrationFieldsUids()) === 0) {
422
            // Set arguments to request, so event is set for event
423
            $this->request = $this->request->withArguments($arguments);
0 ignored issues
show
Bug Best Practice introduced by
The property request does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
424
            return;
425
        }
426
427
        // allow creation of new objects (for validation)
428
        $propertyMapping->setTypeConverterOptions(
429
            PersistentObjectConverter::class,
430
            [
431
                PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => true,
432
                PersistentObjectConverter::CONFIGURATION_MODIFICATION_ALLOWED => true,
433
            ]
434
        );
435
436
        $index = 0;
437
        foreach ((array)($arguments['registration']['fields'] ?? []) as $fieldUid => $value) {
438
            // Only accept registration fields of the current event
439
            if (!in_array((int)$fieldUid, $event->getRegistrationFieldsUids(), true)) {
440
                continue;
441
            }
442
443
            // allow subvalues in new property mapper
444
            $propertyMapping->forProperty('fieldValues')->allowProperties($index);
445
            $propertyMapping->forProperty('fieldValues.' . $index)->allowAllProperties();
446
            $propertyMapping->allowCreationForSubProperty('fieldValues.' . $index);
447
            $propertyMapping->allowModificationForSubProperty('fieldValues.' . $index);
448
449
            if (is_array($value)) {
450
                if (empty($value)) {
451
                    $value = '';
452
                } else {
453
                    $value = json_encode($value);
454
                }
455
            }
456
457
            /** @var Registration\Field $field */
458
            $field = $this->fieldRepository->findByUid((int)$fieldUid);
459
460
            $arguments['registration']['fieldValues'][$index] = [
461
                'pid' => $field->getPid(),
462
                'value' => $value,
463
                'field' => (string)$fieldUid,
464
                'valueType' => $field->getValueType(),
465
            ];
466
467
            $index++;
468
        }
469
470
        // Remove temporary "fields" field
471
        if (isset($arguments['registration']['fields'])) {
472
            $arguments = ArrayUtility::removeByPath($arguments, 'registration/fields');
473
        }
474
        $this->request = $this->request->withArguments($arguments);
475
    }
476
477
    /**
478
     * Set date format for field dateOfBirth
479
     */
480
    public function initializeSaveRegistrationAction(): void
481
    {
482
        $this->arguments->getArgument('registration')
483
            ->getPropertyMappingConfiguration()->forProperty('dateOfBirth')
484
            ->setTypeConverterOption(
485
                DateTimeConverter::class,
486
                DateTimeConverter::CONFIGURATION_DATE_FORMAT,
487
                $this->settings['registration']['formatDateOfBirth'] ?? 'd.m.Y'
488
            );
489
        $this->removePossibleSpamCheckFieldsFromArguments();
490
        $this->setRegistrationFieldValuesToArguments();
491
    }
492
493
    /**
494
     * Saves the registration
495
     *
496
     * @Extbase\Validate("DERHANSEN\SfEventMgt\Validation\Validator\RegistrationFieldValidator", param="registration")
497
     * @Extbase\Validate("DERHANSEN\SfEventMgt\Validation\Validator\RegistrationValidator", param="registration")
498
     */
499
    public function saveRegistrationAction(Registration $registration, Event $event): ResponseInterface
500
    {
501
        if (is_a($event, Event::class) && ($this->settings['registration']['checkPidOfEventRecord'] ?? false)) {
502
            $event = $this->checkPidOfEventRecord($event);
503
        }
504
        if (is_null($event) && isset($this->settings['event']['errorHandling'])) {
505
            return $this->handleEventNotFoundError($this->settings);
506
        }
507
        $autoConfirmation = (bool)($this->settings['registration']['autoConfirmation'] ?? false) ||
508
            $event->getEnableAutoconfirm();
509
        $result = RegistrationResult::REGISTRATION_SUCCESSFUL;
510
        [$success, $result] = $this->registrationService->checkRegistrationSuccess($event, $registration, $result);
511
512
        // Save registration if no errors
513
        $registrationUid = 0;
514
        if ($success) {
515
            $isWaitlistRegistration = $this->registrationService->isWaitlistRegistration(
516
                $event,
517
                $registration->getAmountOfRegistrations()
518
            );
519
            $linkValidity = (int)($this->settings['confirmation']['linkValidity'] ?? 3600);
520
            if ($linkValidity === 0) {
521
                // Use 3600 seconds as default value if not set or zero
522
                $linkValidity = 3600;
523
            }
524
            $confirmationUntil = new DateTime();
525
            $confirmationUntil->add(new DateInterval('PT' . $linkValidity . 'S'));
526
527
            $registration->setEvent($event);
528
            $registration->setPid($event->getPid());
529
            $registration->setRegistrationDate(new DateTime());
530
            $registration->setConfirmationUntil($confirmationUntil);
531
            $registration->setLanguage($this->getCurrentLanguageCode());
532
            $registration->setFeUser($this->registrationService->getCurrentFeUserObject());
533
            $registration->setWaitlist($isWaitlistRegistration);
534
            $this->registrationRepository->add($registration);
535
536
            // Persist registration, so we have an UID
537
            $this->persistAll();
538
            $registrationUid = $registration->getUid();
539
540
            if ($isWaitlistRegistration) {
541
                $messageType = MessageType::REGISTRATION_WAITLIST_NEW;
542
            } else {
543
                $messageType = MessageType::REGISTRATION_NEW;
544
            }
545
546
            $this->eventDispatcher->dispatch(new AfterRegistrationSavedEvent($registration, $this));
547
548
            // Send notifications to user and admin if confirmation link should be sent
549
            if (!$autoConfirmation) {
550
                $this->notificationService->sendUserMessage(
551
                    $event,
552
                    $registration,
553
                    $this->settings,
554
                    $messageType
555
                );
556
                $this->notificationService->sendAdminMessage(
557
                    $event,
558
                    $registration,
559
                    $this->settings,
560
                    $messageType
561
                );
562
            }
563
564
            // Create given amount of registrations if necessary
565
            $modifyCreateDependingRegistrationsEvent = new ModifyCreateDependingRegistrationsEvent(
566
                $registration,
567
                ($registration->getAmountOfRegistrations() > 1),
568
                $this
569
            );
570
            $this->eventDispatcher->dispatch($modifyCreateDependingRegistrationsEvent);
571
            $createDependingRegistrations = $modifyCreateDependingRegistrationsEvent->getCreateDependingRegistrations();
572
            if ($createDependingRegistrations) {
573
                $this->registrationService->createDependingRegistrations($registration);
574
            }
575
576
            // Flush page cache for event, since new registration has been added
577
            $this->eventCacheService->flushEventCache($event->getUid(), $event->getPid());
578
        }
579
580
        if ($autoConfirmation && $success) {
581
            return $this->redirect(
582
                'confirmRegistration',
583
                null,
584
                null,
585
                [
586
                    'reguid' => $registration->getUid(),
587
                    'hmac' => $this->hashService->generateHmac('reg-' . $registration->getUid()),
588
                ]
589
            );
590
        }
591
592
        return $this->redirect(
593
            'saveRegistrationResult',
594
            null,
595
            null,
596
            [
597
                'result' => $result,
598
                'eventuid' => $event->getUid(),
599
                'reguid' => $registrationUid,
600
                'hmac' => $this->hashService->generateHmac('event-' . $event->getUid() . '-reg-' . $registrationUid),
601
            ]
602
        );
603
    }
604
605
    /**
606
     * Shows the result of the saveRegistrationAction
607
     */
608
    public function saveRegistrationResultAction(int $result, int $eventuid, string $hmac): ResponseInterface
609
    {
610
        $reguid = $this->request->hasArgument('reguid') ? (int)$this->request->getArgument('reguid') : 0;
611
612
        $event = null;
613
        $registration = null;
614
        $failed = true;
615
616
        switch ($result) {
617
            case RegistrationResult::REGISTRATION_SUCCESSFUL:
618
                $messageKey = 'event.message.registrationsuccessful';
619
                $titleKey = 'registrationResult.title.successful';
620
                $failed = false;
621
                break;
622
            case RegistrationResult::REGISTRATION_SUCCESSFUL_WAITLIST:
623
                $messageKey = 'event.message.registrationwaitlistsuccessful';
624
                $titleKey = 'registrationWaitlistResult.title.successful';
625
                $failed = false;
626
                break;
627
            case RegistrationResult::REGISTRATION_FAILED_EVENT_EXPIRED:
628
                $messageKey = 'event.message.registrationfailedeventexpired';
629
                $titleKey = 'registrationResult.title.failed';
630
                break;
631
            case RegistrationResult::REGISTRATION_FAILED_EVENT_ENDED:
632
                $messageKey = 'event.message.registrationfailedeventended';
633
                $titleKey = 'registrationResult.title.failed';
634
                break;
635
            case RegistrationResult::REGISTRATION_FAILED_MAX_PARTICIPANTS:
636
                $messageKey = 'event.message.registrationfailedmaxparticipants';
637
                $titleKey = 'registrationResult.title.failed';
638
                break;
639
            case RegistrationResult::REGISTRATION_NOT_ENABLED:
640
                $messageKey = 'event.message.registrationfailednotenabled';
641
                $titleKey = 'registrationResult.title.failed';
642
                break;
643
            case RegistrationResult::REGISTRATION_FAILED_DEADLINE_EXPIRED:
644
                $messageKey = 'event.message.registrationfaileddeadlineexpired';
645
                $titleKey = 'registrationResult.title.failed';
646
                break;
647
            case RegistrationResult::REGISTRATION_FAILED_NOT_ENOUGH_FREE_PLACES:
648
                $messageKey = 'event.message.registrationfailednotenoughfreeplaces';
649
                $titleKey = 'registrationResult.title.failed';
650
                break;
651
            case RegistrationResult::REGISTRATION_FAILED_MAX_AMOUNT_REGISTRATIONS_EXCEEDED:
652
                $messageKey = 'event.message.registrationfailedmaxamountregistrationsexceeded';
653
                $titleKey = 'registrationResult.title.failed';
654
                break;
655
            case RegistrationResult::REGISTRATION_FAILED_EMAIL_NOT_UNIQUE:
656
                $messageKey = 'event.message.registrationfailedemailnotunique';
657
                $titleKey = 'registrationResult.title.failed';
658
                break;
659
            default:
660
                $messageKey = '';
661
                $titleKey = '';
662
        }
663
664
        if (!$this->hashService->validateHmac('event-' . $eventuid . '-reg-' . $reguid, $hmac)) {
665
            $messageKey = 'event.message.registrationsuccessfulwrongeventhmac';
666
            $titleKey = 'registrationResult.title.failed';
667
        } else {
668
            $event = $this->eventRepository->findByUid($eventuid);
669
            $registration = $this->registrationRepository->findByUid($reguid);
670
        }
671
672
        $this->view->assignMultiple([
673
            'messageKey' => $messageKey,
674
            'titleKey' => $titleKey,
675
            'event' => $event,
676
            'registration' => $registration,
677
            'result' => $result,
678
            'failed' => $failed,
679
        ]);
680
681
        return $this->htmlResponse();
682
    }
683
684
    /**
685
     * Shows the verify confirmation registration view, where the user has to submit a form to finally confirm the registration
686
     */
687
    public function verifyConfirmRegistrationAction(int $reguid, string $hmac): ResponseInterface
688
    {
689
        /* @var $registration Registration */
690
        [$failed, $registration, $messageKey, $titleKey] = $this->registrationService->checkConfirmRegistration(
691
            $reguid,
692
            $hmac
693
        );
694
695
        $variables = [
696
            'reguid' => $reguid,
697
            'hmac' => $hmac,
698
            'confirmationPossible' => $registration && !$registration->getConfirmed(),
699
            'failed' => $failed,
700
            'messageKey' => $messageKey,
701
            'titleKey' => $titleKey,
702
            'event' => $registration?->getEvent(),
703
            'registration' => $registration,
704
            'settings' => $this->settings,
705
        ];
706
707
        $this->view->assignMultiple($variables);
708
709
        return $this->htmlResponse();
710
    }
711
712
    /**
713
     * Confirms the registration if possible and sends emails to admin and user
714
     */
715
    public function confirmRegistrationAction(int $reguid, string $hmac): ResponseInterface
716
    {
717
        $event = null;
718
719
        /* @var $registration Registration */
720
        [$failed, $registration, $messageKey, $titleKey] = $this->registrationService->checkConfirmRegistration(
721
            $reguid,
722
            $hmac
723
        );
724
725
        if ($failed === false) {
726
            $registration->setConfirmed(true);
727
            $event = $registration->getEvent();
728
            $this->registrationRepository->update($registration);
729
730
            $this->eventDispatcher->dispatch(new AfterRegistrationConfirmedEvent($registration, $this));
731
732
            $messageType = MessageType::REGISTRATION_CONFIRMED;
733
            if ($registration->getWaitlist()) {
734
                $messageType = MessageType::REGISTRATION_WAITLIST_CONFIRMED;
735
            }
736
737
            // Send notifications to user and admin
738
            $this->notificationService->sendUserMessage(
739
                $registration->getEvent(),
0 ignored issues
show
Bug introduced by
It seems like $registration->getEvent() can also be of type null; however, parameter $event of DERHANSEN\SfEventMgt\Ser...vice::sendUserMessage() 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

739
                /** @scrutinizer ignore-type */ $registration->getEvent(),
Loading history...
740
                $registration,
741
                $this->settings,
742
                $messageType
743
            );
744
            $this->notificationService->sendAdminMessage(
745
                $registration->getEvent(),
0 ignored issues
show
Bug introduced by
It seems like $registration->getEvent() can also be of type null; however, parameter $event of DERHANSEN\SfEventMgt\Ser...ice::sendAdminMessage() 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

745
                /** @scrutinizer ignore-type */ $registration->getEvent(),
Loading history...
746
                $registration,
747
                $this->settings,
748
                $messageType
749
            );
750
751
            // Confirm registrations depending on main registration if necessary
752
            if ($registration->getAmountOfRegistrations() > 1) {
753
                $this->registrationService->confirmDependingRegistrations($registration);
754
            }
755
        }
756
757
        // Redirect to payment provider if payment/redirect is enabled.
758
        // Skip if the registration is a waitlist registration, since it is not sure, if the user will participate.
759
        $paymentPid = (int)($this->settings['paymentPid'] ?? 0);
760
        $paymentRedirectResponse = null;
761
        $processRedirect = !$failed &&
762
            $paymentPid > 0 &&
763
            $registration &&
764
            !$registration->getWaitlist() &&
765
            $this->registrationService->redirectPaymentEnabled($registration);
766
        if ($processRedirect) {
767
            $paymentRedirectResponse = $this->getRedirectToPaymentResponse($paymentPid, $registration);
768
        }
769
770
        if ($paymentRedirectResponse instanceof ResponseInterface) {
771
            return $paymentRedirectResponse;
772
        }
773
774
        $modifyConfirmRegistrationViewVariablesEvent = new ModifyConfirmRegistrationViewVariablesEvent(
775
            [
776
                'failed' => $failed,
777
                'messageKey' => $messageKey,
778
                'titleKey' => $titleKey,
779
                'event' => $event,
780
                'registration' => $registration,
781
                'settings' => $this->settings,
782
            ],
783
            $this
784
        );
785
        $this->eventDispatcher->dispatch($modifyConfirmRegistrationViewVariablesEvent);
786
        $variables = $modifyConfirmRegistrationViewVariablesEvent->getVariables();
787
        $this->view->assignMultiple($variables);
788
789
        return $this->htmlResponse();
790
    }
791
792
    /**
793
     * Returns a response object to the given payment PID. Extension authors can use ProcessRedirectToPaymentEvent
794
     * PSR-14 event to intercept the redirect response.
795
     */
796
    private function getRedirectToPaymentResponse(int $paymentPid, Registration $registration): ?ResponseInterface
797
    {
798
        $processRedirectToPaymentEvent = new ProcessRedirectToPaymentEvent($registration, $this);
799
        $this->eventDispatcher->dispatch($processRedirectToPaymentEvent);
800
        if ($processRedirectToPaymentEvent->getProcessRedirect()) {
801
            $this->uriBuilder->reset()
802
                ->setTargetPageUid($paymentPid);
803
            $uri = $this->uriBuilder->uriFor(
804
                'redirect',
805
                [
806
                    'registration' => $registration,
807
                    'hmac' => $this->hashService->generateHmac('redirectAction-' . $registration->getUid()),
808
                ],
809
                'Payment',
810
                'sfeventmgt',
811
                'Pipayment'
812
            );
813
            return $this->redirectToUri($uri);
814
        }
815
816
        return null;
817
    }
818
819
    /**
820
     * Shows the verify cancel registration view, where the user has to submit a form to finally cancel the registration
821
     */
822
    public function verifyCancelRegistrationAction(int $reguid, string $hmac): ResponseInterface
823
    {
824
        /* @var $registration Registration */
825
        [$failed, $registration, $messageKey, $titleKey] = $this->registrationService->checkCancelRegistration(
826
            $reguid,
827
            $hmac
828
        );
829
830
        $variables = [
831
            'reguid' => $reguid,
832
            'hmac' => $hmac,
833
            'cancellationPossible' => !$failed,
834
            'failed' => $failed,
835
            'messageKey' => $messageKey,
836
            'titleKey' => $titleKey,
837
            'event' => $registration?->getEvent(),
838
            'registration' => $registration,
839
            'settings' => $this->settings,
840
        ];
841
842
        $this->view->assignMultiple($variables);
843
844
        return $this->htmlResponse();
845
    }
846
847
    /**
848
     * Cancels the registration if possible and sends emails to admin and user
849
     */
850
    public function cancelRegistrationAction(int $reguid, string $hmac): ResponseInterface
851
    {
852
        $event = null;
853
854
        /* @var $registration Registration */
855
        [$failed, $registration, $messageKey, $titleKey] = $this->registrationService->checkCancelRegistration(
856
            $reguid,
857
            $hmac
858
        );
859
860
        if ($failed === false) {
861
            $event = $registration->getEvent();
862
863
            // Send notifications (must run before cancelling the registration)
864
            $this->notificationService->sendUserMessage(
865
                $registration->getEvent(),
0 ignored issues
show
Bug introduced by
It seems like $registration->getEvent() can also be of type null; however, parameter $event of DERHANSEN\SfEventMgt\Ser...vice::sendUserMessage() 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

865
                /** @scrutinizer ignore-type */ $registration->getEvent(),
Loading history...
866
                $registration,
867
                $this->settings,
868
                MessageType::REGISTRATION_CANCELLED
869
            );
870
            $this->notificationService->sendAdminMessage(
871
                $registration->getEvent(),
0 ignored issues
show
Bug introduced by
It seems like $registration->getEvent() can also be of type null; however, parameter $event of DERHANSEN\SfEventMgt\Ser...ice::sendAdminMessage() 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

871
                /** @scrutinizer ignore-type */ $registration->getEvent(),
Loading history...
872
                $registration,
873
                $this->settings,
874
                MessageType::REGISTRATION_CANCELLED
875
            );
876
877
            // First cancel depending registrations
878
            $processCancelDependingRegistrations = new ProcessCancelDependingRegistrationsEvent(
879
                $registration,
880
                $registration->getAmountOfRegistrations() > 1
881
            );
882
            $this->eventDispatcher->dispatch($processCancelDependingRegistrations);
883
            if ($processCancelDependingRegistrations->getProcessCancellation()) {
884
                $this->registrationService->cancelDependingRegistrations($registration);
885
            }
886
887
            // Finally cancel registration
888
            $this->registrationRepository->remove($registration);
889
890
            // Persist changes, so following functions can work with $event properties (e.g. amount of registrations)
891
            $this->persistAll();
892
893
            $afterRegistrationCancelledEvent = new AfterRegistrationCancelledEvent($registration, $this);
894
            $this->eventDispatcher->dispatch($afterRegistrationCancelledEvent);
895
896
            // Dispatch event, so waitlist registrations can be moved up and default move up process can be stopped
897
            $waitlistMoveUpEvent = new WaitlistMoveUpEvent($event, $this, true);
0 ignored issues
show
Bug introduced by
It seems like $event can also be of type null; however, parameter $event of DERHANSEN\SfEventMgt\Eve...eUpEvent::__construct() 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

897
            $waitlistMoveUpEvent = new WaitlistMoveUpEvent(/** @scrutinizer ignore-type */ $event, $this, true);
Loading history...
898
            $this->eventDispatcher->dispatch($waitlistMoveUpEvent);
899
900
            // Move up waitlist registrations if configured on event basis and if not disabled by $waitlistMoveUpEvent
901
            if ($waitlistMoveUpEvent->getProcessDefaultMoveUp()) {
902
                $this->registrationService->moveUpWaitlistRegistrations($event, $this->settings);
0 ignored issues
show
Bug introduced by
It seems like $event can also be of type null; however, parameter $event of DERHANSEN\SfEventMgt\Ser...WaitlistRegistrations() 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

902
                $this->registrationService->moveUpWaitlistRegistrations(/** @scrutinizer ignore-type */ $event, $this->settings);
Loading history...
903
            }
904
905
            // Flush page cache for event, since amount of registrations has changed
906
            $this->eventCacheService->flushEventCache($event->getUid(), $event->getPid());
907
        }
908
909
        $modifyCancelRegistrationViewVariablesEvent = new ModifyCancelRegistrationViewVariablesEvent(
910
            [
911
                'failed' => $failed,
912
                'messageKey' => $messageKey,
913
                'titleKey' => $titleKey,
914
                'event' => $event,
915
                'settings' => $this->settings,
916
            ],
917
            $this
918
        );
919
        $this->eventDispatcher->dispatch($modifyCancelRegistrationViewVariablesEvent);
920
        $variables = $modifyCancelRegistrationViewVariablesEvent->getVariables();
921
        $this->view->assignMultiple($variables);
922
923
        return $this->htmlResponse();
924
    }
925
926
    /**
927
     * Set date format for field startDate and endDate
928
     */
929
    public function initializeSearchAction(): void
930
    {
931
        if ($this->settings !== null && ($this->settings['search']['dateFormat'] ?? false)) {
932
            $this->arguments->getArgument('searchDemand')
933
                ->getPropertyMappingConfiguration()->forProperty('startDate')
934
                ->setTypeConverterOption(
935
                    DateTimeConverter::class,
936
                    DateTimeConverter::CONFIGURATION_DATE_FORMAT,
937
                    $this->settings['search']['dateFormat']
938
                );
939
            $this->arguments->getArgument('searchDemand')
940
                ->getPropertyMappingConfiguration()->forProperty('endDate')
941
                ->setTypeConverterOption(
942
                    DateTimeConverter::class,
943
                    DateTimeConverter::CONFIGURATION_DATE_FORMAT,
944
                    $this->settings['search']['dateFormat']
945
                );
946
        }
947
        if ($this->arguments->hasArgument('searchDemand')) {
948
            $propertyMappingConfiguration = $this->arguments->getArgument('searchDemand')
949
                ->getPropertyMappingConfiguration();
950
            $propertyMappingConfiguration->allowAllProperties();
951
            $propertyMappingConfiguration->setTypeConverterOption(
952
                PersistentObjectConverter::class,
953
                PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED,
954
                true
955
            );
956
        }
957
    }
958
959
    /**
960
     * Search view
961
     */
962
    public function searchAction(SearchDemand $searchDemand = null, array $overwriteDemand = []): ResponseInterface
963
    {
964
        $eventDemand = EventDemand::createFromSettings($this->settings);
965
        $eventDemand->setSearchDemand($searchDemand);
966
        $foreignRecordDemand = ForeignRecordDemand::createFromSettings($this->settings);
967
        $categoryDemand = CategoryDemand::createFromSettings($this->settings);
968
969
        if ($searchDemand !== null) {
970
            $searchDemand->setFields($this->settings['search']['fields'] ?? '');
971
972
            $adjustTime = (bool)($this->settings['search']['adjustTime'] ?? false);
973
            if ($adjustTime && $searchDemand->getStartDate() !== null) {
974
                $searchDemand->getStartDate()->setTime(0, 0);
975
            }
976
977
            if ($adjustTime && $searchDemand->getEndDate() !== null) {
978
                $searchDemand->getEndDate()->setTime(23, 59, 59);
979
            }
980
        }
981
982
        if ($this->isOverwriteDemand($overwriteDemand)) {
983
            $eventDemand = $this->overwriteEventDemandObject($eventDemand, $overwriteDemand);
984
        }
985
986
        $categories = $this->categoryRepository->findDemanded($categoryDemand);
987
        $locations = $this->locationRepository->findDemanded($foreignRecordDemand);
988
        $organisators = $this->organisatorRepository->findDemanded($foreignRecordDemand);
989
        $speakers = $this->speakerRepository->findDemanded($foreignRecordDemand);
990
        $events = $this->eventRepository->findDemanded($eventDemand);
991
992
        $modifySearchViewVariablesEvent = new ModifySearchViewVariablesEvent(
993
            [
994
                'events' => $events,
995
                'categories' => $categories,
996
                'locations' => $locations,
997
                'organisators' => $organisators,
998
                'speakers' => $speakers,
999
                'searchDemand' => $searchDemand,
1000
                'overwriteDemand' => $overwriteDemand,
1001
                'settings' => $this->settings,
1002
            ],
1003
            $this
1004
        );
1005
        $this->eventDispatcher->dispatch($modifySearchViewVariablesEvent);
1006
        $variables = $modifySearchViewVariablesEvent->getVariables();
1007
        $this->view->assignMultiple($variables);
1008
1009
        return $this->htmlResponse();
1010
    }
1011
1012
    /**
1013
     * Returns if a demand object can be overwritten with the given overwriteDemand array
1014
     */
1015
    protected function isOverwriteDemand(array $overwriteDemand): bool
1016
    {
1017
        return (int)($this->settings['disableOverrideDemand'] ?? 0) !== 1 && $overwriteDemand !== [];
1018
    }
1019
1020
    /**
1021
     * If no event is given and the singleEvent setting is set, the configured single event is returned
1022
     */
1023
    protected function evaluateSingleEventSetting(?Event $event): ?Event
1024
    {
1025
        if ($event === null && (int)($this->settings['singleEvent'] ?? 0) > 0) {
1026
            $event = $this->eventRepository->findByUid((int)$this->settings['singleEvent']);
1027
        }
1028
1029
        return $event;
1030
    }
1031
1032
    /**
1033
     * If no event is given and the isShortcut setting is set, the event is displayed using the "Insert Record"
1034
     * content element and should be loaded from contect object data
1035
     */
1036
    protected function evaluateIsShortcutSetting(?Event $event): ?Event
1037
    {
1038
        if ($event === null && (bool)($this->settings['detail']['isShortcut'] ?? false)) {
1039
            $eventRawData = $this->request->getAttribute('currentContentObject')->data;
1040
            $event = $this->eventRepository->findByUid($eventRawData['uid']);
1041
        }
1042
1043
        return $event;
1044
    }
1045
1046
    /**
1047
     * If no event is given and the the `event_preview` argument is set, the event is displayed for preview
1048
     */
1049
    protected function evaluateEventPreviewSetting(?Event $event): ?Event
1050
    {
1051
        if ($event === null && $this->request->hasArgument('event_preview')) {
1052
            $context = GeneralUtility::makeInstance(Context::class);
1053
            $hasBackendUser = $context->getPropertyFromAspect('backend.user', 'isLoggedIn');
1054
            $previewEventId = (int)$this->request->getArgument('event_preview');
1055
            if ($previewEventId > 0 && $hasBackendUser) {
1056
                if ($this->settings['previewHiddenRecords'] ?? false) {
1057
                    $event = $this->eventRepository->findByUidIncludeHidden($previewEventId);
1058
                } else {
1059
                    $event = $this->eventRepository->findByUid($previewEventId);
1060
                }
1061
            }
1062
        }
1063
1064
        return $event;
1065
    }
1066
1067
    /**
1068
     * Checks if the event pid could be found in the storagePage settings of the detail plugin and
1069
     * if the pid could not be found it return null instead of the event object.
1070
     */
1071
    protected function checkPidOfEventRecord(Event $event): ?Event
1072
    {
1073
        $allowedStoragePages = GeneralUtility::trimExplode(
1074
            ',',
1075
            PageUtility::extendPidListByChildren(
1076
                $this->settings['storagePage'] ?? '',
1077
                (int)($this->settings['recursive'] ?? 0)
1078
            ),
1079
            true
1080
        );
1081
        if (count($allowedStoragePages) > 0 && !in_array($event->getPid(), $allowedStoragePages)) {
1082
            $this->eventDispatcher->dispatch(new EventPidCheckFailedEvent($event, $this));
1083
            $event = null;
1084
        }
1085
1086
        return $event;
1087
    }
1088
1089
    /**
1090
     * Calls persistAll() of the persistenceManager
1091
     */
1092
    protected function persistAll(): void
1093
    {
1094
        GeneralUtility::makeInstance(PersistenceManager::class)->persistAll();
1095
    }
1096
1097
    /**
1098
     * Returns the language code of the current language
1099
     */
1100
    protected function getCurrentLanguageCode(): string
1101
    {
1102
        if ($this->request->getAttribute('language') instanceof SiteLanguage) {
1103
            /** @var SiteLanguage $siteLanguage */
1104
            $siteLanguage = $this->request->getAttribute('language');
1105
            return $siteLanguage->getLocale()->getLanguageCode();
1106
        }
1107
1108
        return '';
1109
    }
1110
}
1111