Passed
Push — 7.x ( 46400b...fb51d4 )
by Torben
03:19
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
     * Initialize arguments for saveRegistrationAction and ensures, action is only called via POST
479
     */
480
    public function initializeSaveRegistrationAction(): void
481
    {
482
        if ($this->request->getMethod() !== 'POST') {
483
            $response = GeneralUtility::makeInstance(ErrorController::class)->accessDeniedAction(
484
                $this->request,
485
                'HTTP method is not allowed'
486
            );
487
            throw new PropagateResponseException($response, 1726573183);
488
        }
489
490
        $this->arguments->getArgument('registration')
491
            ->getPropertyMappingConfiguration()->forProperty('dateOfBirth')
492
            ->setTypeConverterOption(
493
                DateTimeConverter::class,
494
                DateTimeConverter::CONFIGURATION_DATE_FORMAT,
495
                $this->settings['registration']['formatDateOfBirth'] ?? 'd.m.Y'
496
            );
497
        $this->removePossibleSpamCheckFieldsFromArguments();
498
        $this->setRegistrationFieldValuesToArguments();
499
    }
500
501
    /**
502
     * Saves the registration
503
     *
504
     * @Extbase\Validate("DERHANSEN\SfEventMgt\Validation\Validator\RegistrationFieldValidator", param="registration")
505
     * @Extbase\Validate("DERHANSEN\SfEventMgt\Validation\Validator\RegistrationValidator", param="registration")
506
     */
507
    public function saveRegistrationAction(Registration $registration, Event $event): ResponseInterface
508
    {
509
        if (is_a($event, Event::class) && ($this->settings['registration']['checkPidOfEventRecord'] ?? false)) {
510
            $event = $this->checkPidOfEventRecord($event);
511
        }
512
        if (is_null($event) && isset($this->settings['event']['errorHandling'])) {
513
            return $this->handleEventNotFoundError($this->settings);
514
        }
515
        $autoConfirmation = (bool)($this->settings['registration']['autoConfirmation'] ?? false) ||
516
            $event->getEnableAutoconfirm();
517
        $result = RegistrationResult::REGISTRATION_SUCCESSFUL;
518
        [$success, $result] = $this->registrationService->checkRegistrationSuccess($event, $registration, $result);
519
520
        // Save registration if no errors
521
        $registrationUid = 0;
522
        if ($success) {
523
            $isWaitlistRegistration = $this->registrationService->isWaitlistRegistration(
524
                $event,
525
                $registration->getAmountOfRegistrations()
526
            );
527
            $linkValidity = (int)($this->settings['confirmation']['linkValidity'] ?? 3600);
528
            if ($linkValidity === 0) {
529
                // Use 3600 seconds as default value if not set or zero
530
                $linkValidity = 3600;
531
            }
532
            $confirmationUntil = new DateTime();
533
            $confirmationUntil->add(new DateInterval('PT' . $linkValidity . 'S'));
534
535
            $registration->setEvent($event);
536
            $registration->setPid($event->getPid());
537
            $registration->setRegistrationDate(new DateTime());
538
            $registration->setConfirmationUntil($confirmationUntil);
539
            $registration->setLanguage($this->getCurrentLanguageCode());
540
            $registration->setFeUser($this->registrationService->getCurrentFeUserObject());
541
            $registration->setWaitlist($isWaitlistRegistration);
542
            $this->registrationRepository->add($registration);
543
544
            // Persist registration, so we have an UID
545
            $this->persistAll();
546
            $registrationUid = $registration->getUid();
547
548
            if ($isWaitlistRegistration) {
549
                $messageType = MessageType::REGISTRATION_WAITLIST_NEW;
550
            } else {
551
                $messageType = MessageType::REGISTRATION_NEW;
552
            }
553
554
            $this->eventDispatcher->dispatch(new AfterRegistrationSavedEvent($registration, $this));
555
556
            // Send notifications to user and admin if confirmation link should be sent
557
            if (!$autoConfirmation) {
558
                $this->notificationService->sendUserMessage(
559
                    $event,
560
                    $registration,
561
                    $this->settings,
562
                    $messageType
563
                );
564
                $this->notificationService->sendAdminMessage(
565
                    $event,
566
                    $registration,
567
                    $this->settings,
568
                    $messageType
569
                );
570
            }
571
572
            // Create given amount of registrations if necessary
573
            $modifyCreateDependingRegistrationsEvent = new ModifyCreateDependingRegistrationsEvent(
574
                $registration,
575
                ($registration->getAmountOfRegistrations() > 1),
576
                $this
577
            );
578
            $this->eventDispatcher->dispatch($modifyCreateDependingRegistrationsEvent);
579
            $createDependingRegistrations = $modifyCreateDependingRegistrationsEvent->getCreateDependingRegistrations();
580
            if ($createDependingRegistrations) {
581
                $this->registrationService->createDependingRegistrations($registration);
582
            }
583
584
            // Flush page cache for event, since new registration has been added
585
            $this->eventCacheService->flushEventCache($event->getUid(), $event->getPid());
586
        }
587
588
        if ($autoConfirmation && $success) {
589
            return $this->redirect(
590
                'confirmRegistration',
591
                null,
592
                null,
593
                [
594
                    'reguid' => $registration->getUid(),
595
                    'hmac' => $this->hashService->generateHmac('reg-' . $registration->getUid()),
596
                ]
597
            );
598
        }
599
600
        return $this->redirect(
601
            'saveRegistrationResult',
602
            null,
603
            null,
604
            [
605
                'result' => $result,
606
                'eventuid' => $event->getUid(),
607
                'reguid' => $registrationUid,
608
                'hmac' => $this->hashService->generateHmac('event-' . $event->getUid() . '-reg-' . $registrationUid),
609
            ]
610
        );
611
    }
612
613
    /**
614
     * Shows the result of the saveRegistrationAction
615
     */
616
    public function saveRegistrationResultAction(int $result, int $eventuid, string $hmac): ResponseInterface
617
    {
618
        $reguid = $this->request->hasArgument('reguid') ? (int)$this->request->getArgument('reguid') : 0;
619
620
        $event = null;
621
        $registration = null;
622
        $failed = true;
623
624
        switch ($result) {
625
            case RegistrationResult::REGISTRATION_SUCCESSFUL:
626
                $messageKey = 'event.message.registrationsuccessful';
627
                $titleKey = 'registrationResult.title.successful';
628
                $failed = false;
629
                break;
630
            case RegistrationResult::REGISTRATION_SUCCESSFUL_WAITLIST:
631
                $messageKey = 'event.message.registrationwaitlistsuccessful';
632
                $titleKey = 'registrationWaitlistResult.title.successful';
633
                $failed = false;
634
                break;
635
            case RegistrationResult::REGISTRATION_FAILED_EVENT_EXPIRED:
636
                $messageKey = 'event.message.registrationfailedeventexpired';
637
                $titleKey = 'registrationResult.title.failed';
638
                break;
639
            case RegistrationResult::REGISTRATION_FAILED_EVENT_ENDED:
640
                $messageKey = 'event.message.registrationfailedeventended';
641
                $titleKey = 'registrationResult.title.failed';
642
                break;
643
            case RegistrationResult::REGISTRATION_FAILED_MAX_PARTICIPANTS:
644
                $messageKey = 'event.message.registrationfailedmaxparticipants';
645
                $titleKey = 'registrationResult.title.failed';
646
                break;
647
            case RegistrationResult::REGISTRATION_NOT_ENABLED:
648
                $messageKey = 'event.message.registrationfailednotenabled';
649
                $titleKey = 'registrationResult.title.failed';
650
                break;
651
            case RegistrationResult::REGISTRATION_FAILED_DEADLINE_EXPIRED:
652
                $messageKey = 'event.message.registrationfaileddeadlineexpired';
653
                $titleKey = 'registrationResult.title.failed';
654
                break;
655
            case RegistrationResult::REGISTRATION_FAILED_NOT_ENOUGH_FREE_PLACES:
656
                $messageKey = 'event.message.registrationfailednotenoughfreeplaces';
657
                $titleKey = 'registrationResult.title.failed';
658
                break;
659
            case RegistrationResult::REGISTRATION_FAILED_MAX_AMOUNT_REGISTRATIONS_EXCEEDED:
660
                $messageKey = 'event.message.registrationfailedmaxamountregistrationsexceeded';
661
                $titleKey = 'registrationResult.title.failed';
662
                break;
663
            case RegistrationResult::REGISTRATION_FAILED_EMAIL_NOT_UNIQUE:
664
                $messageKey = 'event.message.registrationfailedemailnotunique';
665
                $titleKey = 'registrationResult.title.failed';
666
                break;
667
            default:
668
                $messageKey = '';
669
                $titleKey = '';
670
        }
671
672
        if (!$this->hashService->validateHmac('event-' . $eventuid . '-reg-' . $reguid, $hmac)) {
673
            $messageKey = 'event.message.registrationsuccessfulwrongeventhmac';
674
            $titleKey = 'registrationResult.title.failed';
675
        } else {
676
            $event = $this->eventRepository->findByUid($eventuid);
677
            $registration = $this->registrationRepository->findByUid($reguid);
678
        }
679
680
        $this->view->assignMultiple([
681
            'messageKey' => $messageKey,
682
            'titleKey' => $titleKey,
683
            'event' => $event,
684
            'registration' => $registration,
685
            'result' => $result,
686
            'failed' => $failed,
687
        ]);
688
689
        return $this->htmlResponse();
690
    }
691
692
    /**
693
     * Shows the verify confirmation registration view, where the user has to submit a form to finally confirm the registration
694
     */
695
    public function verifyConfirmRegistrationAction(int $reguid, string $hmac): ResponseInterface
696
    {
697
        /* @var $registration Registration */
698
        [$failed, $registration, $messageKey, $titleKey] = $this->registrationService->checkConfirmRegistration(
699
            $reguid,
700
            $hmac
701
        );
702
703
        $variables = [
704
            'reguid' => $reguid,
705
            'hmac' => $hmac,
706
            'confirmationPossible' => $registration && !$registration->getConfirmed(),
707
            'failed' => $failed,
708
            'messageKey' => $messageKey,
709
            'titleKey' => $titleKey,
710
            'event' => $registration?->getEvent(),
711
            'registration' => $registration,
712
            'settings' => $this->settings,
713
        ];
714
715
        $this->view->assignMultiple($variables);
716
717
        return $this->htmlResponse();
718
    }
719
720
    /**
721
     * Confirms the registration if possible and sends emails to admin and user
722
     */
723
    public function confirmRegistrationAction(int $reguid, string $hmac): ResponseInterface
724
    {
725
        $event = null;
726
727
        /* @var $registration Registration */
728
        [$failed, $registration, $messageKey, $titleKey] = $this->registrationService->checkConfirmRegistration(
729
            $reguid,
730
            $hmac
731
        );
732
733
        if ($failed === false) {
734
            $registration->setConfirmed(true);
735
            $event = $registration->getEvent();
736
            $this->registrationRepository->update($registration);
737
738
            $this->eventDispatcher->dispatch(new AfterRegistrationConfirmedEvent($registration, $this));
739
740
            $messageType = MessageType::REGISTRATION_CONFIRMED;
741
            if ($registration->getWaitlist()) {
742
                $messageType = MessageType::REGISTRATION_WAITLIST_CONFIRMED;
743
            }
744
745
            // Send notifications to user and admin
746
            $this->notificationService->sendUserMessage(
747
                $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

747
                /** @scrutinizer ignore-type */ $registration->getEvent(),
Loading history...
748
                $registration,
749
                $this->settings,
750
                $messageType
751
            );
752
            $this->notificationService->sendAdminMessage(
753
                $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

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

873
                /** @scrutinizer ignore-type */ $registration->getEvent(),
Loading history...
874
                $registration,
875
                $this->settings,
876
                MessageType::REGISTRATION_CANCELLED
877
            );
878
            $this->notificationService->sendAdminMessage(
879
                $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

879
                /** @scrutinizer ignore-type */ $registration->getEvent(),
Loading history...
880
                $registration,
881
                $this->settings,
882
                MessageType::REGISTRATION_CANCELLED
883
            );
884
885
            // First cancel depending registrations
886
            $processCancelDependingRegistrations = new ProcessCancelDependingRegistrationsEvent(
887
                $registration,
888
                $registration->getAmountOfRegistrations() > 1
889
            );
890
            $this->eventDispatcher->dispatch($processCancelDependingRegistrations);
891
            if ($processCancelDependingRegistrations->getProcessCancellation()) {
892
                $this->registrationService->cancelDependingRegistrations($registration);
893
            }
894
895
            // Finally cancel registration
896
            $this->registrationRepository->remove($registration);
897
898
            // Persist changes, so following functions can work with $event properties (e.g. amount of registrations)
899
            $this->persistAll();
900
901
            $afterRegistrationCancelledEvent = new AfterRegistrationCancelledEvent($registration, $this);
902
            $this->eventDispatcher->dispatch($afterRegistrationCancelledEvent);
903
904
            // Dispatch event, so waitlist registrations can be moved up and default move up process can be stopped
905
            $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

905
            $waitlistMoveUpEvent = new WaitlistMoveUpEvent(/** @scrutinizer ignore-type */ $event, $this, true);
Loading history...
906
            $this->eventDispatcher->dispatch($waitlistMoveUpEvent);
907
908
            // Move up waitlist registrations if configured on event basis and if not disabled by $waitlistMoveUpEvent
909
            if ($waitlistMoveUpEvent->getProcessDefaultMoveUp()) {
910
                $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

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