Completed
Push — typo3-10-compatibility ( b4f2e1...42d8ec )
by Torben
03:17
created

EventController   F

Complexity

Total Complexity 121

Size/Duplication

Total Lines 1050
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 51

Importance

Changes 0
Metric Value
wmc 121
lcom 1
cbo 51
dl 0
loc 1050
rs 1.4
c 0
b 0
f 0

30 Methods

Rating   Name   Duplication   Size   Complexity  
A processRequest() 0 8 2
A handleKnownExceptionsElseThrowAgain() 0 12 3
A initializeListAction() 0 6 2
A injectEventCacheService() 0 4 1
A initializeView() 0 8 2
A initializeAction() 0 12 3
A createEventDemandObjectFromSettings() 0 20 1
A createForeignRecordDemandObjectFromSettings() 0 9 1
A createCategoryDemandObjectFromSettings() 0 11 1
A listAction() 0 32 2
B calendarAction() 0 61 5
A changeEventDemandToFullMonthDateRange() 0 24 1
B detailAction() 0 21 6
B handleEventNotFoundError() 0 33 7
A icalDownloadAction() 0 11 5
B registrationAction() 0 33 8
A removePossibleSpamCheckFieldsFromArguments() 0 20 4
B setRegistrationFieldValuesToArguments() 0 74 9
A initializeSaveRegistrationAction() 0 12 1
C saveRegistrationAction() 0 107 13
C saveRegistrationResultAction() 0 59 11
B confirmRegistrationAction() 0 74 7
A cancelRegistrationAction() 0 53 3
A initializeSearchAction() 0 29 4
B searchAction() 0 45 7
A isOverwriteDemand() 0 4 2
A evaluateSingleEventSetting() 0 8 3
A evaluateIsShortcutSetting() 0 9 3
A checkPidOfEventRecord() 0 17 3
A getSysLanguageUid() 0 6 1

How to fix   Complexity   

Complex Class

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

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

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

1
<?php
2
namespace DERHANSEN\SfEventMgt\Controller;
3
4
/*
5
 * This file is part of the Extension "sf_event_mgt" for TYPO3 CMS.
6
 *
7
 * For the full copyright and license information, please read the
8
 * LICENSE.txt file that was distributed with this source code.
9
 */
10
11
use DERHANSEN\SfEventMgt\Domain\Model\Dto\CategoryDemand;
12
use DERHANSEN\SfEventMgt\Domain\Model\Dto\EventDemand;
13
use DERHANSEN\SfEventMgt\Domain\Model\Dto\ForeignRecordDemand;
14
use DERHANSEN\SfEventMgt\Domain\Model\Dto\SearchDemand;
15
use DERHANSEN\SfEventMgt\Domain\Model\Event;
16
use DERHANSEN\SfEventMgt\Domain\Model\Registration;
17
use DERHANSEN\SfEventMgt\Event\AfterRegistrationConfirmedEvent;
18
use DERHANSEN\SfEventMgt\Event\AfterRegistrationSavedEvent;
19
use DERHANSEN\SfEventMgt\Event\EventPidCheckFailedEvent;
20
use DERHANSEN\SfEventMgt\Event\ModifyCalendarViewVariablesEvent;
21
use DERHANSEN\SfEventMgt\Event\ModifyCancelRegistrationViewVariablesEvent;
22
use DERHANSEN\SfEventMgt\Event\ModifyConfirmRegistrationViewVariablesEvent;
23
use DERHANSEN\SfEventMgt\Event\ModifyCreateDependingRegistrationsEvent;
24
use DERHANSEN\SfEventMgt\Event\ModifyDetailViewVariablesEvent;
25
use DERHANSEN\SfEventMgt\Event\ModifyListViewVariablesEvent;
26
use DERHANSEN\SfEventMgt\Event\ModifyRegistrationViewVariablesEvent;
27
use DERHANSEN\SfEventMgt\Event\ModifySearchViewVariablesEvent;
28
use DERHANSEN\SfEventMgt\Event\WaitlistMoveUpEvent;
29
use DERHANSEN\SfEventMgt\Service\EventCacheService;
30
use DERHANSEN\SfEventMgt\Utility\MessageType;
31
use DERHANSEN\SfEventMgt\Utility\Page;
32
use DERHANSEN\SfEventMgt\Utility\RegistrationResult;
33
use TYPO3\CMS\Core\Context\Context;
34
use TYPO3\CMS\Core\Http\ImmediateResponseException;
35
use TYPO3\CMS\Core\Utility\ArrayUtility;
36
use TYPO3\CMS\Core\Utility\GeneralUtility;
37
use TYPO3\CMS\Core\Utility\HttpUtility;
38
use TYPO3\CMS\Extbase\Annotation as Extbase;
39
use TYPO3\CMS\Extbase\Mvc\RequestInterface;
40
use TYPO3\CMS\Extbase\Mvc\ResponseInterface;
41
use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
42
use TYPO3\CMS\Extbase\Property\TypeConverter\DateTimeConverter;
43
use TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter;
44
use TYPO3\CMS\Fluid\View\StandaloneView;
45
use TYPO3\CMS\Frontend\Controller\ErrorController;
46
47
/**
48
 * EventController
49
 *
50
 * @author Torben Hansen <[email protected]>
51
 */
52
class EventController extends AbstractController
53
{
54
    /**
55
     * @var EventCacheService
56
     */
57
    protected $eventCacheService = null;
58
59
    /**
60
     * @param EventCacheService $cacheService
61
     */
62
    public function injectEventCacheService(EventCacheService $cacheService)
63
    {
64
        $this->eventCacheService = $cacheService;
65
    }
66
67
    /**
68
     * Assign contentObjectData and pageData to earch view
69
     *
70
     * @param \TYPO3\CMS\Extbase\Mvc\View\ViewInterface $view
71
     */
72
    protected function initializeView(\TYPO3\CMS\Extbase\Mvc\View\ViewInterface $view)
73
    {
74
        $view->assign('contentObjectData', $this->configurationManager->getContentObject()->data);
75
        if (is_object($GLOBALS['TSFE'])) {
76
            $view->assign('pageData', $GLOBALS['TSFE']->page);
77
        }
78
        parent::initializeView($view);
79
    }
80
81
    /**
82
     * Initializes the current action
83
     */
84
    public function initializeAction()
85
    {
86
        $typoScriptFrontendController = $this->getTypoScriptFrontendController();
87
        if ($typoScriptFrontendController !== null) {
88
            static $cacheTagsSet = false;
89
90
            if (!$cacheTagsSet) {
91
                $typoScriptFrontendController->addCacheTags(['tx_sfeventmgt']);
92
                $cacheTagsSet = true;
93
            }
94
        }
95
    }
96
97
    /**
98
     * Creates an event demand object with the given settings
99
     *
100
     * @param array $settings The settings
101
     *
102
     * @return \DERHANSEN\SfEventMgt\Domain\Model\Dto\EventDemand
103
     */
104
    public function createEventDemandObjectFromSettings(array $settings)
105
    {
106
        /** @var \DERHANSEN\SfEventMgt\Domain\Model\Dto\EventDemand $demand */
107
        $demand = $this->objectManager->get(EventDemand::class);
108
        $demand->setDisplayMode($settings['displayMode']);
109
        $demand->setStoragePage(Page::extendPidListByChildren($settings['storagePage'], $settings['recursive']));
110
        $demand->setCategoryConjunction($settings['categoryConjunction']);
111
        $demand->setCategory($settings['category']);
112
        $demand->setIncludeSubcategories($settings['includeSubcategories']);
113
        $demand->setTopEventRestriction((int)$settings['topEventRestriction']);
114
        $demand->setOrderField($settings['orderField']);
115
        $demand->setOrderFieldAllowed($settings['orderFieldAllowed']);
116
        $demand->setOrderDirection($settings['orderDirection']);
117
        $demand->setQueryLimit($settings['queryLimit']);
118
        $demand->setLocation($settings['location']);
119
        $demand->setOrganisator($settings['organisator']);
120
        $demand->setSpeaker($settings['speaker']);
121
122
        return $demand;
123
    }
124
125
    /**
126
     * Creates a foreign record demand object with the given settings
127
     *
128
     * @param array $settings The settings
129
     *
130
     * @return \DERHANSEN\SfEventMgt\Domain\Model\Dto\ForeignRecordDemand
131
     */
132
    public function createForeignRecordDemandObjectFromSettings(array $settings)
133
    {
134
        /** @var \DERHANSEN\SfEventMgt\Domain\Model\Dto\ForeignRecordDemand $demand */
135
        $demand = $this->objectManager->get(ForeignRecordDemand::class);
136
        $demand->setStoragePage(Page::extendPidListByChildren($settings['storagePage'], $settings['recursive']));
137
        $demand->setRestrictForeignRecordsToStoragePage((bool)$settings['restrictForeignRecordsToStoragePage']);
138
139
        return $demand;
140
    }
141
142
    /**
143
     * Creates a category demand object with the given settings
144
     *
145
     * @param array $settings The settings
146
     *
147
     * @return \DERHANSEN\SfEventMgt\Domain\Model\Dto\CategoryDemand
148
     */
149
    public function createCategoryDemandObjectFromSettings(array $settings)
150
    {
151
        /** @var \DERHANSEN\SfEventMgt\Domain\Model\Dto\CategoryDemand $demand */
152
        $demand = $this->objectManager->get(CategoryDemand::class);
153
        $demand->setStoragePage(Page::extendPidListByChildren($settings['storagePage'], $settings['recursive']));
154
        $demand->setRestrictToStoragePage((bool)$settings['restrictForeignRecordsToStoragePage']);
155
        $demand->setCategories($settings['categoryMenu']['categories']);
156
        $demand->setIncludeSubcategories($settings['categoryMenu']['includeSubcategories']);
157
158
        return $demand;
159
    }
160
161
    /**
162
     * Hook into request processing and catch exceptions
163
     *
164
     * @param RequestInterface $request
165
     * @param ResponseInterface $response
166
     * @throws \Exception
167
     */
168
    public function processRequest(RequestInterface $request, ResponseInterface $response)
169
    {
170
        try {
171
            parent::processRequest($request, $response);
172
        } catch (\Exception $exception) {
173
            $this->handleKnownExceptionsElseThrowAgain($exception);
174
        }
175
    }
176
177
    /**
178
     * Handle known exceptions
179
     *
180
     * @param \Exception $exception
181
     * @throws \Exception
182
     */
183
    private function handleKnownExceptionsElseThrowAgain(\Exception $exception)
184
    {
185
        $previousException = $exception->getPrevious();
186
        $actions = ['detailAction', 'registrationAction', 'icalDownloadAction'];
187
        if (in_array($this->actionMethodName, $actions, true)
188
            && $previousException instanceof \TYPO3\CMS\Extbase\Property\Exception
189
        ) {
190
            $this->handleEventNotFoundError($this->settings);
191
        } else {
192
            throw $exception;
193
        }
194
    }
195
196
    /**
197
     * Initialize list action and set format
198
     *
199
     * @return void
200
     */
201
    public function initializeListAction()
202
    {
203
        if (isset($this->settings['list']['format'])) {
204
            $this->request->setFormat($this->settings['list']['format']);
205
        }
206
    }
207
208
    /**
209
     * List view
210
     *
211
     * @param array $overwriteDemand OverwriteDemand
212
     *
213
     * @return void
214
     */
215
    public function listAction(array $overwriteDemand = [])
216
    {
217
        $eventDemand = $this->createEventDemandObjectFromSettings($this->settings);
218
        $foreignRecordDemand = $this->createForeignRecordDemandObjectFromSettings($this->settings);
219
        $categoryDemand = $this->createCategoryDemandObjectFromSettings($this->settings);
220
        if ($this->isOverwriteDemand($overwriteDemand)) {
221
            $eventDemand = $this->overwriteEventDemandObject($eventDemand, $overwriteDemand);
222
        }
223
        $events = $this->eventRepository->findDemanded($eventDemand);
224
        $categories = $this->categoryRepository->findDemanded($categoryDemand);
225
        $locations = $this->locationRepository->findDemanded($foreignRecordDemand);
226
        $organisators = $this->organisatorRepository->findDemanded($foreignRecordDemand);
227
        $speakers = $this->speakerRepository->findDemanded($foreignRecordDemand);
228
229
        $modifyListViewVariablesEvent = new ModifyListViewVariablesEvent(
230
            [
231
                'events' => $events,
232
                'categories' => $categories,
233
                'locations' => $locations,
234
                'organisators' => $organisators,
235
                'speakers' => $speakers,
236
                'overwriteDemand' => $overwriteDemand,
237
                'eventDemand' => $eventDemand
238
            ],
239
            $this
240
        );
241
        $this->eventDispatcher->dispatch($modifyListViewVariablesEvent);
0 ignored issues
show
Documentation introduced by
$modifyListViewVariablesEvent is of type object<DERHANSEN\SfEvent...ListViewVariablesEvent>, but the function expects a object<Psr\EventDispatcher\object>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
242
        $variables = $modifyListViewVariablesEvent->getVariables();
243
        $this->view->assignMultiple($variables);
244
245
        $this->eventCacheService->addPageCacheTagsByEventDemandObject($eventDemand);
246
    }
247
248
    /**
249
     * Calendar view
250
     *
251
     * @param array $overwriteDemand OverwriteDemand
252
     *
253
     * @return void
254
     */
255
    public function calendarAction(array $overwriteDemand = [])
256
    {
257
        $eventDemand = $this->createEventDemandObjectFromSettings($this->settings);
258
        $foreignRecordDemand = $this->createForeignRecordDemandObjectFromSettings($this->settings);
259
        $categoryDemand = $this->createCategoryDemandObjectFromSettings($this->settings);
260
        if ($this->isOverwriteDemand($overwriteDemand)) {
261
            $eventDemand = $this->overwriteEventDemandObject($eventDemand, $overwriteDemand);
262
        }
263
264
        // Set month/year to demand if not given
265
        if (!$eventDemand->getMonth()) {
266
            $currentMonth = date('n');
267
            $eventDemand->setMonth($currentMonth);
268
        } else {
269
            $currentMonth = $eventDemand->getMonth();
270
        }
271
        if (!$eventDemand->getYear()) {
272
            $currentYear = date('Y');
273
            $eventDemand->setYear($currentYear);
274
        } else {
275
            $currentYear = $eventDemand->getYear();
276
        }
277
278
        // Set demand from calendar date range instead of month / year
279
        if ((bool)$this->settings['calendar']['includeEventsForEveryDayOfAllCalendarWeeks']) {
280
            $eventDemand = $this->changeEventDemandToFullMonthDateRange($eventDemand);
281
        }
282
283
        $events = $this->eventRepository->findDemanded($eventDemand);
284
        $weeks = $this->calendarService->getCalendarArray(
285
            $currentMonth,
286
            $currentYear,
287
            strtotime('today midnight'),
288
            (int)$this->settings['calendar']['firstDayOfWeek'],
289
            $events
290
        );
291
292
        $modifyCalendarViewVariablesEvent = new ModifyCalendarViewVariablesEvent(
293
            [
294
                'events' => $events,
295
                'weeks' => $weeks,
296
                'categories' => $this->categoryRepository->findDemanded($categoryDemand),
297
                'locations' => $this->locationRepository->findDemanded($foreignRecordDemand),
298
                'organisators' => $this->organisatorRepository->findDemanded($foreignRecordDemand),
299
                'eventDemand' => $eventDemand,
300
                'overwriteDemand' => $overwriteDemand,
301
                'currentPageId' => $GLOBALS['TSFE']->id,
302
                'firstDayOfMonth' => \DateTime::createFromFormat(
303
                    'd.m.Y',
304
                    sprintf('1.%s.%s', $currentMonth, $currentYear)
305
                ),
306
                'previousMonthConfig' => $this->calendarService->getDateConfig($currentMonth, $currentYear, '-1 month'),
307
                'nextMonthConfig' => $this->calendarService->getDateConfig($currentMonth, $currentYear, '+1 month')
308
            ],
309
            $this
310
        );
311
        $this->eventDispatcher->dispatch($modifyCalendarViewVariablesEvent);
0 ignored issues
show
Documentation introduced by
$modifyCalendarViewVariablesEvent is of type object<DERHANSEN\SfEvent...ndarViewVariablesEvent>, but the function expects a object<Psr\EventDispatcher\object>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
312
        $variables = $modifyCalendarViewVariablesEvent->getVariables();
313
314
        $this->view->assignMultiple($variables);
315
    }
316
317
    /**
318
     * Changes the given event demand object to select a date range for a calendar month including days of the previous
319
     * month for the first week and they days for the next month for the last week
320
     *
321
     * @param EventDemand $eventDemand
322
     * @return EventDemand
323
     */
324
    protected function changeEventDemandToFullMonthDateRange(EventDemand $eventDemand)
325
    {
326
        $calendarDateRange = $this->calendarService->getCalendarDateRange(
327
            $eventDemand->getMonth(),
328
            $eventDemand->getYear(),
329
            $this->settings['calendar']['firstDayOfWeek']
330
        );
331
332
        $eventDemand->setMonth(0);
333
        $eventDemand->setYear(0);
334
335
        $startDate = new \DateTime();
336
        $startDate->setTimestamp($calendarDateRange['firstDayOfCalendar']);
337
        $endDate = new \DateTime();
338
        $endDate->setTimestamp($calendarDateRange['lastDayOfCalendar']);
339
        $endDate->setTime(23, 59, 59);
340
341
        $searchDemand = new SearchDemand();
342
        $searchDemand->setStartDate($startDate);
343
        $searchDemand->setEndDate($endDate);
344
        $eventDemand->setSearchDemand($searchDemand);
345
346
        return $eventDemand;
347
    }
348
349
    /**
350
     * Detail view for an event
351
     *
352
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Event $event Event
353
     * @return mixed string|void
354
     */
355
    public function detailAction(Event $event = null)
356
    {
357
        $event = $this->evaluateSingleEventSetting($event);
358
        $event = $this->evaluateIsShortcutSetting($event);
0 ignored issues
show
Bug introduced by
It seems like $event defined by $this->evaluateIsShortcutSetting($event) on line 358 can also be of type object; however, DERHANSEN\SfEventMgt\Con...uateIsShortcutSetting() does only seem to accept object<DERHANSEN\SfEvent...omain\Model\Event>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
359
        if (is_a($event, Event::class) && $this->settings['detail']['checkPidOfEventRecord']) {
360
            $event = $this->checkPidOfEventRecord($event);
0 ignored issues
show
Documentation introduced by
$event is of type null|object, but the function expects a object<DERHANSEN\SfEventMgt\Domain\Model\Event>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
361
        }
362
363
        if (is_null($event) && isset($this->settings['event']['errorHandling'])) {
364
            return $this->handleEventNotFoundError($this->settings);
365
        }
366
367
        $modifyDetailViewVariablesEvent = new ModifyDetailViewVariablesEvent(['event' => $event], $this);
368
        $this->eventDispatcher->dispatch($modifyDetailViewVariablesEvent);
0 ignored issues
show
Documentation introduced by
$modifyDetailViewVariablesEvent is of type object<DERHANSEN\SfEvent...tailViewVariablesEvent>, but the function expects a object<Psr\EventDispatcher\object>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
369
        $variables = $modifyDetailViewVariablesEvent->getVariables();
370
371
        $this->view->assignMultiple($variables);
372
        if ($event !== null) {
373
            $this->eventCacheService->addCacheTagsByEventRecords([$event]);
374
        }
375
    }
376
377
    /**
378
     * Error handling if event is not found
379
     *
380
     * @param array $settings
381
     * @return string
382
     */
383
    protected function handleEventNotFoundError($settings)
384
    {
385
        if (empty($settings['event']['errorHandling'])) {
386
            return null;
387
        }
388
389
        $configuration = GeneralUtility::trimExplode(',', $settings['event']['errorHandling'], true);
390
391
        switch ($configuration[0]) {
392
            case 'redirectToListView':
393
                $listPid = (int)$settings['listPid'] > 0 ? (int)$settings['listPid'] : 1;
394
                $this->redirect('list', null, null, null, $listPid);
395
                break;
396
            case 'pageNotFoundHandler':
397
                $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
398
                    $GLOBALS['TYPO3_REQUEST'],
399
                    'Event not found.'
400
                );
401
                throw new ImmediateResponseException($response, 1549896549734);
402
                break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
403
            case 'showStandaloneTemplate':
404
                if (isset($configuration[2])) {
405
                    $statusCode = constant(HttpUtility::class . '::HTTP_STATUS_' . $configuration[2]);
406
                    HttpUtility::setResponseCode($statusCode);
407
                }
408
                $standaloneTemplate = $this->objectManager->get(StandaloneView::class);
409
                $standaloneTemplate->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($configuration[1]));
410
411
                return $standaloneTemplate->render();
412
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
413
            default:
414
        }
415
    }
416
417
    /**
418
     * Initiates the iCalendar download for the given event
419
     *
420
     * @param Event $event The event
421
     *
422
     * @return string|false
423
     */
424
    public function icalDownloadAction(Event $event = null)
425
    {
426
        if (is_a($event, Event::class) && $this->settings['detail']['checkPidOfEventRecord']) {
427
            $event = $this->checkPidOfEventRecord($event);
0 ignored issues
show
Bug introduced by
It seems like $event defined by $this->checkPidOfEventRecord($event) on line 427 can be null; however, DERHANSEN\SfEventMgt\Con...checkPidOfEventRecord() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
428
        }
429
        if (is_null($event) && isset($this->settings['event']['errorHandling'])) {
430
            return $this->handleEventNotFoundError($this->settings);
431
        }
432
        $this->icalendarService->downloadiCalendarFile($event);
0 ignored issues
show
Bug introduced by
It seems like $event can be null; however, downloadiCalendarFile() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
433
        exit();
434
    }
435
436
    /**
437
     * Registration view for an event
438
     *
439
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Event $event Event
440
     *
441
     * @return mixed string|void
442
     */
443
    public function registrationAction(Event $event = null)
444
    {
445
        // Temporary workaround for https://forge.typo3.org/issues/89434
446
        // @todo: Remove when issue has been fixed
447
        if ($event === null && $this->request->getOriginalRequest()->hasArgument('event')) {
448
            $uid = $this->request->getOriginalRequest()->getArgument('event');
449
            $event = $this->eventRepository->findByUid($uid);
0 ignored issues
show
Documentation introduced by
$uid is of type string|array, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
450
        }
451
452
        $event = $this->evaluateSingleEventSetting($event);
0 ignored issues
show
Bug introduced by
It seems like $event defined by $this->evaluateSingleEventSetting($event) on line 452 can also be of type object; however, DERHANSEN\SfEventMgt\Con...ateSingleEventSetting() does only seem to accept object<DERHANSEN\SfEvent...omain\Model\Event>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
453
        if (is_a($event, Event::class) && $this->settings['registration']['checkPidOfEventRecord']) {
454
            $event = $this->checkPidOfEventRecord($event);
0 ignored issues
show
Documentation introduced by
$event is of type null|object, but the function expects a object<DERHANSEN\SfEventMgt\Domain\Model\Event>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
455
        }
456
        if (is_null($event) && isset($this->settings['event']['errorHandling'])) {
457
            return $this->handleEventNotFoundError($this->settings);
458
        }
459
        if ($event->getRestrictPaymentMethods()) {
460
            $paymentMethods = $this->paymentService->getRestrictedPaymentMethods($event);
0 ignored issues
show
Documentation introduced by
$event is of type object|null, but the function expects a object<DERHANSEN\SfEventMgt\Domain\Model\Event>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
461
        } else {
462
            $paymentMethods = $this->paymentService->getPaymentMethods();
463
        }
464
465
        $modifyRegistrationViewVariablesEvent = new ModifyRegistrationViewVariablesEvent(
466
            [
467
                'event' => $event,
468
                'paymentMethods' => $paymentMethods,
469
            ],
470
            $this
471
        );
472
        $this->eventDispatcher->dispatch($modifyRegistrationViewVariablesEvent);
0 ignored issues
show
Documentation introduced by
$modifyRegistrationViewVariablesEvent is of type object<DERHANSEN\SfEvent...tionViewVariablesEvent>, but the function expects a object<Psr\EventDispatcher\object>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
473
        $variables = $modifyRegistrationViewVariablesEvent->getVariables();
474
        $this->view->assignMultiple($variables);
475
    }
476
477
    /**
478
     * Removes all possible spamcheck fields (which do not belong to the domain model) from arguments.
479
     *
480
     * @return void
481
     */
482
    protected function removePossibleSpamCheckFieldsFromArguments()
483
    {
484
        $arguments = $this->request->getArguments();
485
        if (!isset($arguments['event'])) {
486
            return;
487
        }
488
489
        // Remove a possible honeypot field
490
        $honeypotField = 'hp' . (int)$arguments['event'];
491
        if (isset($arguments['registration'][$honeypotField])) {
492
            unset($arguments['registration'][$honeypotField]);
493
        }
494
495
        // Remove a possible challenge/response field
496
        if (isset($arguments['registration']['cr-response'])) {
497
            unset($arguments['registration']['cr-response']);
498
        }
499
500
        $this->request->setArguments($arguments);
501
    }
502
503
    /**
504
     * Processes incoming registrations fields and adds field values to arguments
505
     *
506
     * @return void
507
     */
508
    protected function setRegistrationFieldValuesToArguments()
509
    {
510
        $arguments = $this->request->getArguments();
511
        if (!isset($arguments['event'])) {
512
            return;
513
        }
514
515
        /** @var Event $event */
516
        $event = $this->eventRepository->findByUid((int)$this->request->getArgument('event'));
517
        if (!$event || $event->getRegistrationFields()->count() === 0) {
518
            return;
519
        }
520
521
        $registrationMvcArgument = $this->arguments->getArgument('registration');
522
        $propertyMapping = $registrationMvcArgument->getPropertyMappingConfiguration();
523
        $propertyMapping->allowProperties('fieldValues');
524
        $propertyMapping->allowCreationForSubProperty('fieldValues');
525
        $propertyMapping->allowModificationForSubProperty('fieldValues');
526
527
        // allow creation of new objects (for validation)
528
        $propertyMapping->setTypeConverterOptions(
529
            PersistentObjectConverter::class,
530
            [
531
                PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => true,
532
                PersistentObjectConverter::CONFIGURATION_MODIFICATION_ALLOWED => true
533
            ]
534
        );
535
536
        // Set event to registration (required for validation)
537
        $propertyMapping->allowProperties('event');
538
        $propertyMapping->allowCreationForSubProperty('event');
539
        $propertyMapping->allowModificationForSubProperty('event');
540
        $arguments['registration']['event'] = (int)$this->request->getArgument('event');
541
542
        $index = 0;
543
        foreach ((array)$arguments['registration']['fields'] as $fieldUid => $value) {
544
            // Only accept registration fields of the current event
545
            if (!in_array((int)$fieldUid, $event->getRegistrationFieldsUids(), true)) {
546
                continue;
547
            }
548
549
            // allow subvalues in new property mapper
550
            $propertyMapping->forProperty('fieldValues')->allowProperties($index);
551
            $propertyMapping->forProperty('fieldValues.' . $index)->allowAllProperties();
552
            $propertyMapping->allowCreationForSubProperty('fieldValues.' . $index);
553
            $propertyMapping->allowModificationForSubProperty('fieldValues.' . $index);
554
555
            if (is_array($value)) {
556
                if (empty($value)) {
557
                    $value = '';
558
                } else {
559
                    $value = json_encode($value);
560
                }
561
            }
562
563
            /** @var Registration\Field $field */
564
            $field = $this->fieldRepository->findByUid((int)$fieldUid);
565
566
            $arguments['registration']['fieldValues'][$index] = [
567
                'pid' => $field->getPid(),
568
                'value' => $value,
569
                'field' => strval($fieldUid),
570
                'valueType' => $field->getValueType()
571
            ];
572
573
            $index++;
574
        }
575
576
        // Remove temporary "fields" field
577
        if (isset($arguments['registration']['fields'])) {
578
            $arguments = ArrayUtility::removeByPath($arguments, 'registration/fields');
579
        }
580
        $this->request->setArguments($arguments);
581
    }
582
583
    /**
584
     * Set date format for field dateOfBirth
585
     *
586
     * @return void
587
     */
588
    public function initializeSaveRegistrationAction()
589
    {
590
        $this->arguments->getArgument('registration')
591
            ->getPropertyMappingConfiguration()->forProperty('dateOfBirth')
592
            ->setTypeConverterOption(
593
                DateTimeConverter::class,
594
                DateTimeConverter::CONFIGURATION_DATE_FORMAT,
595
                $this->settings['registration']['formatDateOfBirth']
596
            );
597
        $this->removePossibleSpamCheckFieldsFromArguments();
598
        $this->setRegistrationFieldValuesToArguments();
599
    }
600
601
    /**
602
     * Saves the registration
603
     *
604
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Registration $registration Registration
605
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Event $event Event
606
     * @Extbase\Validate("DERHANSEN\SfEventMgt\Validation\Validator\RegistrationFieldValidator", param="registration")
607
     * @Extbase\Validate("DERHANSEN\SfEventMgt\Validation\Validator\RegistrationValidator", param="registration")
608
     *
609
     * @return mixed string|void
610
     */
611
    public function saveRegistrationAction(Registration $registration, Event $event)
612
    {
613
        if (is_a($event, Event::class) && $this->settings['registration']['checkPidOfEventRecord']) {
614
            $event = $this->checkPidOfEventRecord($event);
615
        }
616
        if (is_null($event) && isset($this->settings['event']['errorHandling'])) {
617
            return $this->handleEventNotFoundError($this->settings);
618
        }
619
        $autoConfirmation = (bool)$this->settings['registration']['autoConfirmation'] || $event->getEnableAutoconfirm();
0 ignored issues
show
Bug introduced by
It seems like $event is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
620
        $result = RegistrationResult::REGISTRATION_SUCCESSFUL;
621
        list($success, $result) = $this->registrationService->checkRegistrationSuccess($event, $registration, $result);
0 ignored issues
show
Bug introduced by
It seems like $event can be null; however, checkRegistrationSuccess() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
622
623
        // Save registration if no errors
624
        if ($success) {
625
            $isWaitlistRegistration = $this->registrationService->isWaitlistRegistration(
626
                $event,
0 ignored issues
show
Bug introduced by
It seems like $event defined by $this->checkPidOfEventRecord($event) on line 614 can be null; however, DERHANSEN\SfEventMgt\Ser...sWaitlistRegistration() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
627
                $registration->getAmountOfRegistrations()
628
            );
629
            $linkValidity = (int)$this->settings['confirmation']['linkValidity'];
630
            if ($linkValidity === 0) {
631
                // Use 3600 seconds as default value if not set
632
                $linkValidity = 3600;
633
            }
634
            $confirmationUntil = new \DateTime();
635
            $confirmationUntil->add(new \DateInterval('PT' . $linkValidity . 'S'));
636
637
            $registration->setEvent($event);
0 ignored issues
show
Bug introduced by
It seems like $event defined by $this->checkPidOfEventRecord($event) on line 614 can be null; however, DERHANSEN\SfEventMgt\Dom...egistration::setEvent() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
638
            $registration->setPid($event->getPid());
639
            $registration->setConfirmationUntil($confirmationUntil);
640
            $registration->setLanguage($GLOBALS['TSFE']->config['config']['language']);
641
            $registration->setFeUser($this->registrationService->getCurrentFeUserObject());
0 ignored issues
show
Documentation introduced by
$this->registrationServi...etCurrentFeUserObject() is of type object|null, but the function expects a object<TYPO3\CMS\Extbase...ain\Model\FrontendUser>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
642
            $registration->setWaitlist($isWaitlistRegistration);
643
            $registration->_setProperty('_languageUid', $this->getSysLanguageUid());
644
            $this->registrationRepository->add($registration);
645
646
            // Persist registration, so we have an UID
647
            $this->objectManager->get(PersistenceManager::class)->persistAll();
648
649
            if ($isWaitlistRegistration) {
650
                $messageType = MessageType::REGISTRATION_WAITLIST_NEW;
651
            } else {
652
                $messageType = MessageType::REGISTRATION_NEW;
653
            }
654
655
            // Fix event in registration for language other than default language
656
            $this->registrationService->fixRegistrationEvent($registration, $event);
0 ignored issues
show
Bug introduced by
It seems like $event defined by $this->checkPidOfEventRecord($event) on line 614 can be null; however, DERHANSEN\SfEventMgt\Ser...:fixRegistrationEvent() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
657
658
            // Fix language of registration fields if other than default language
659
            $this->registrationService->fixRegistationFieldValueLanguage($registration, $event);
0 ignored issues
show
Bug introduced by
It seems like $event defined by $this->checkPidOfEventRecord($event) on line 614 can be null; however, DERHANSEN\SfEventMgt\Ser...ionFieldValueLanguage() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
660
661
            $this->eventDispatcher->dispatch(new AfterRegistrationSavedEvent($registration, $this));
0 ignored issues
show
Documentation introduced by
new \DERHANSEN\SfEventMg...t($registration, $this) is of type object<DERHANSEN\SfEvent...RegistrationSavedEvent>, but the function expects a object<Psr\EventDispatcher\object>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
662
663
            // Send notifications to user and admin if confirmation link should be sent
664
            if (!$autoConfirmation) {
665
                $this->notificationService->sendUserMessage(
666
                    $event,
0 ignored issues
show
Bug introduced by
It seems like $event defined by $this->checkPidOfEventRecord($event) on line 614 can be null; however, DERHANSEN\SfEventMgt\Ser...vice::sendUserMessage() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
667
                    $registration,
668
                    $this->settings,
669
                    $messageType
670
                );
671
                $this->notificationService->sendAdminMessage(
672
                    $event,
0 ignored issues
show
Bug introduced by
It seems like $event defined by $this->checkPidOfEventRecord($event) on line 614 can be null; however, DERHANSEN\SfEventMgt\Ser...ice::sendAdminMessage() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
673
                    $registration,
674
                    $this->settings,
675
                    $messageType
676
                );
677
            }
678
679
            // Create given amount of registrations if necessary
680
            $modifyCreateDependingRegistrationsEvent = new ModifyCreateDependingRegistrationsEvent(
681
                $registration,
682
                ($registration->getAmountOfRegistrations() > 1),
683
                $this
684
            );
685
            $this->eventDispatcher->dispatch($modifyCreateDependingRegistrationsEvent);
0 ignored issues
show
Documentation introduced by
$modifyCreateDependingRegistrationsEvent is of type object<DERHANSEN\SfEvent...dingRegistrationsEvent>, but the function expects a object<Psr\EventDispatcher\object>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
686
            $createDependingRegistrations = $modifyCreateDependingRegistrationsEvent->getCreateDependingRegistrations();
687
            if ($createDependingRegistrations) {
688
                $this->registrationService->createDependingRegistrations($registration);
689
            }
690
691
            // Flush page cache for event, since new registration has been added
692
            $this->eventCacheService->flushEventCache($event->getUid(), $event->getPid());
693
        }
694
695
        if ($autoConfirmation && $success) {
696
            $this->redirect(
697
                'confirmRegistration',
698
                null,
699
                null,
700
                [
701
                    'reguid' => $registration->getUid(),
702
                    'hmac' => $this->hashService->generateHmac('reg-' . $registration->getUid())
703
                ]
704
            );
705
        } else {
706
            $this->redirect(
707
                'saveRegistrationResult',
708
                null,
709
                null,
710
                [
711
                    'result' => $result,
712
                    'eventuid' => $event->getUid(),
713
                    'hmac' => $this->hashService->generateHmac('event-' . $event->getUid())
714
                ]
715
            );
716
        }
717
    }
718
719
    /**
720
     * Shows the result of the saveRegistrationAction
721
     *
722
     * @param int $result Result
723
     * @param int $eventuid
724
     * @param string $hmac
725
     *
726
     * @return void
727
     */
728
    public function saveRegistrationResultAction($result, $eventuid, $hmac)
729
    {
730
        $event = null;
731
732
        switch ($result) {
733
            case RegistrationResult::REGISTRATION_SUCCESSFUL:
734
                $messageKey = 'event.message.registrationsuccessful';
735
                $titleKey = 'registrationResult.title.successful';
736
                break;
737
            case RegistrationResult::REGISTRATION_SUCCESSFUL_WAITLIST:
738
                $messageKey = 'event.message.registrationwaitlistsuccessful';
739
                $titleKey = 'registrationWaitlistResult.title.successful';
740
                break;
741
            case RegistrationResult::REGISTRATION_FAILED_EVENT_EXPIRED:
742
                $messageKey = 'event.message.registrationfailedeventexpired';
743
                $titleKey = 'registrationResult.title.failed';
744
                break;
745
            case RegistrationResult::REGISTRATION_FAILED_MAX_PARTICIPANTS:
746
                $messageKey = 'event.message.registrationfailedmaxparticipants';
747
                $titleKey = 'registrationResult.title.failed';
748
                break;
749
            case RegistrationResult::REGISTRATION_NOT_ENABLED:
750
                $messageKey = 'event.message.registrationfailednotenabled';
751
                $titleKey = 'registrationResult.title.failed';
752
                break;
753
            case RegistrationResult::REGISTRATION_FAILED_DEADLINE_EXPIRED:
754
                $messageKey = 'event.message.registrationfaileddeadlineexpired';
755
                $titleKey = 'registrationResult.title.failed';
756
                break;
757
            case RegistrationResult::REGISTRATION_FAILED_NOT_ENOUGH_FREE_PLACES:
758
                $messageKey = 'event.message.registrationfailednotenoughfreeplaces';
759
                $titleKey = 'registrationResult.title.failed';
760
                break;
761
            case RegistrationResult::REGISTRATION_FAILED_MAX_AMOUNT_REGISTRATIONS_EXCEEDED:
762
                $messageKey = 'event.message.registrationfailedmaxamountregistrationsexceeded';
763
                $titleKey = 'registrationResult.title.failed';
764
                break;
765
            case RegistrationResult::REGISTRATION_FAILED_EMAIL_NOT_UNIQUE:
766
                $messageKey = 'event.message.registrationfailedemailnotunique';
767
                $titleKey = 'registrationResult.title.failed';
768
                break;
769
            default:
770
                $messageKey = '';
771
                $titleKey = '';
772
        }
773
774
        if (!$this->hashService->validateHmac('event-' . $eventuid, $hmac)) {
775
            $messageKey = 'event.message.registrationsuccessfulwrongeventhmac';
776
            $titleKey = 'registrationResult.title.failed';
777
        } else {
778
            $event = $this->eventRepository->findByUid((int)$eventuid);
779
        }
780
781
        $this->view->assignMultiple([
782
            'messageKey' => $messageKey,
783
            'titleKey' => $titleKey,
784
            'event' => $event,
785
        ]);
786
    }
787
788
    /**
789
     * Confirms the registration if possible and sends e-mails to admin and user
790
     *
791
     * @param int $reguid UID of registration
792
     * @param string $hmac HMAC for parameters
793
     *
794
     * @return void
795
     */
796
    public function confirmRegistrationAction($reguid, $hmac)
797
    {
798
        $event = null;
799
800
        /* @var $registration Registration */
801
        list($failed, $registration, $messageKey, $titleKey) = $this->registrationService->checkConfirmRegistration(
802
            $reguid,
803
            $hmac
804
        );
805
806
        if ($failed === false) {
807
            $registration->setConfirmed(true);
808
            $event = $registration->getEvent();
809
            $this->registrationRepository->update($registration);
810
811
            $this->eventDispatcher->dispatch(new AfterRegistrationConfirmedEvent($registration, $this));
0 ignored issues
show
Documentation introduced by
new \DERHANSEN\SfEventMg...t($registration, $this) is of type object<DERHANSEN\SfEvent...strationConfirmedEvent>, but the function expects a object<Psr\EventDispatcher\object>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
812
813
            $messageType = MessageType::REGISTRATION_CONFIRMED;
814
            if ($registration->getWaitlist()) {
815
                $messageType = MessageType::REGISTRATION_WAITLIST_CONFIRMED;
816
            }
817
818
            // Send notifications to user and admin
819
            $this->notificationService->sendUserMessage(
820
                $registration->getEvent(),
821
                $registration,
822
                $this->settings,
823
                $messageType
824
            );
825
            $this->notificationService->sendAdminMessage(
826
                $registration->getEvent(),
827
                $registration,
828
                $this->settings,
829
                $messageType
830
            );
831
832
            // Confirm registrations depending on main registration if necessary
833
            if ($registration->getAmountOfRegistrations() > 1) {
834
                $this->registrationService->confirmDependingRegistrations($registration);
835
            }
836
        }
837
838
        // Redirect to payment provider if payment/redirect is enabled
839
        $paymentPid = (int)$this->settings['paymentPid'];
840
        if (!$failed && $paymentPid > 0 && $this->registrationService->redirectPaymentEnabled($registration)) {
841
            $this->uriBuilder->reset()
842
                ->setTargetPageUid($paymentPid);
843
            $uri = $this->uriBuilder->uriFor(
844
                'redirect',
845
                [
846
                    'registration' => $registration,
847
                    'hmac' => $this->hashService->generateHmac('redirectAction-' . $registration->getUid())
848
                ],
849
                'Payment',
850
                'sfeventmgt',
851
                'Pipayment'
852
            );
853
            $this->redirectToUri($uri);
854
        }
855
856
        $modifyConfirmRegistrationViewVariablesEvent = new ModifyConfirmRegistrationViewVariablesEvent(
857
            [
858
                'failed' => $failed,
859
                'messageKey' => $messageKey,
860
                'titleKey' => $titleKey,
861
                'event' => $event,
862
                'registration' => $registration,
863
            ],
864
            $this
865
        );
866
        $this->eventDispatcher->dispatch($modifyConfirmRegistrationViewVariablesEvent);
0 ignored issues
show
Documentation introduced by
$modifyConfirmRegistrationViewVariablesEvent is of type object<DERHANSEN\SfEvent...tionViewVariablesEvent>, but the function expects a object<Psr\EventDispatcher\object>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
867
        $variables = $modifyConfirmRegistrationViewVariablesEvent->getVariables();
868
        $this->view->assignMultiple($variables);
869
    }
870
871
    /**
872
     * Cancels the registration if possible and sends e-mails to admin and user
873
     *
874
     * @param int $reguid UID of registration
875
     * @param string $hmac HMAC for parameters
876
     *
877
     * @return void
878
     */
879
    public function cancelRegistrationAction($reguid, $hmac)
880
    {
881
        $event = null;
882
883
        /* @var $registration Registration */
884
        list($failed, $registration, $messageKey, $titleKey) =
885
            $this->registrationService->checkCancelRegistration($reguid, $hmac);
886
887
        if ($failed === false) {
888
            $event = $registration->getEvent();
889
890
            // Send notifications (must run before cancelling the registration)
891
            $this->notificationService->sendUserMessage(
892
                $registration->getEvent(),
893
                $registration,
894
                $this->settings,
895
                MessageType::REGISTRATION_CANCELLED
896
            );
897
            $this->notificationService->sendAdminMessage(
898
                $registration->getEvent(),
899
                $registration,
900
                $this->settings,
901
                MessageType::REGISTRATION_CANCELLED
902
            );
903
904
            // First cancel depending registrations
905
            if ($registration->getAmountOfRegistrations() > 1) {
906
                $this->registrationService->cancelDependingRegistrations($registration);
907
            }
908
909
            // Finally cancel registration
910
            $this->registrationRepository->remove($registration);
911
912
            // Dispatch event, so waitlist registrations can be moved up
913
            $this->eventDispatcher->dispatch(new WaitlistMoveUpEvent($event, $this));
0 ignored issues
show
Documentation introduced by
new \DERHANSEN\SfEventMg...eUpEvent($event, $this) is of type object<DERHANSEN\SfEvent...nt\WaitlistMoveUpEvent>, but the function expects a object<Psr\EventDispatcher\object>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
914
915
            // Flush page cache for event, since new registration has been added
916
            $this->eventCacheService->flushEventCache($event->getUid(), $event->getPid());
917
        }
918
919
        $modifyCancelRegistrationViewVariablesEvent = new ModifyCancelRegistrationViewVariablesEvent(
920
            [
921
                'failed' => $failed,
922
                'messageKey' => $messageKey,
923
                'titleKey' => $titleKey,
924
                'event' => $event,
925
            ],
926
            $this
927
        );
928
        $this->eventDispatcher->dispatch($modifyCancelRegistrationViewVariablesEvent);
0 ignored issues
show
Documentation introduced by
$modifyCancelRegistrationViewVariablesEvent is of type object<DERHANSEN\SfEvent...tionViewVariablesEvent>, but the function expects a object<Psr\EventDispatcher\object>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
929
        $variables = $modifyCancelRegistrationViewVariablesEvent->getVariables();
930
        $this->view->assignMultiple($variables);
931
    }
932
933
    /**
934
     * Set date format for field startDate and endDate
935
     *
936
     * @return void
937
     */
938
    public function initializeSearchAction()
939
    {
940
        if ($this->settings !== null && $this->settings['search']['dateFormat']) {
941
            $this->arguments->getArgument('searchDemand')
942
                ->getPropertyMappingConfiguration()->forProperty('startDate')
943
                ->setTypeConverterOption(
944
                    DateTimeConverter::class,
945
                    DateTimeConverter::CONFIGURATION_DATE_FORMAT,
946
                    $this->settings['search']['dateFormat']
947
                );
948
            $this->arguments->getArgument('searchDemand')
949
                ->getPropertyMappingConfiguration()->forProperty('endDate')
950
                ->setTypeConverterOption(
951
                    DateTimeConverter::class,
952
                    DateTimeConverter::CONFIGURATION_DATE_FORMAT,
953
                    $this->settings['search']['dateFormat']
954
                );
955
        }
956
        if ($this->arguments->hasArgument('searchDemand')) {
957
            $propertyMappingConfiguration = $this->arguments->getArgument('searchDemand')
958
                ->getPropertyMappingConfiguration();
959
            $propertyMappingConfiguration->allowAllProperties();
960
            $propertyMappingConfiguration->setTypeConverterOption(
961
                PersistentObjectConverter::class,
962
                PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED,
963
                true
964
            );
965
        }
966
    }
967
968
    /**
969
     * Search view
970
     *
971
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Dto\SearchDemand $searchDemand SearchDemand
972
     * @param array $overwriteDemand OverwriteDemand
973
     *
974
     * @return void
975
     */
976
    public function searchAction(SearchDemand $searchDemand = null, array $overwriteDemand = [])
977
    {
978
        $eventDemand = $this->createEventDemandObjectFromSettings($this->settings);
979
        $eventDemand->setSearchDemand($searchDemand);
0 ignored issues
show
Bug introduced by
It seems like $searchDemand defined by parameter $searchDemand on line 976 can be null; however, DERHANSEN\SfEventMgt\Dom...mand::setSearchDemand() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
980
        $foreignRecordDemand = $this->createForeignRecordDemandObjectFromSettings($this->settings);
981
        $categoryDemand = $this->createCategoryDemandObjectFromSettings($this->settings);
982
983
        if ($searchDemand !== null) {
984
            $searchDemand->setFields($this->settings['search']['fields']);
985
986
            if ($this->settings['search']['adjustTime'] && $searchDemand->getStartDate() !== null) {
987
                $searchDemand->getStartDate()->setTime(0, 0, 0);
988
            }
989
990
            if ($this->settings['search']['adjustTime'] && $searchDemand->getEndDate() !== null) {
991
                $searchDemand->getEndDate()->setTime(23, 59, 59);
992
            }
993
        }
994
995
        if ($this->isOverwriteDemand($overwriteDemand)) {
996
            $eventDemand = $this->overwriteEventDemandObject($eventDemand, $overwriteDemand);
997
        }
998
999
        $categories = $this->categoryRepository->findDemanded($categoryDemand);
1000
        $locations = $this->locationRepository->findDemanded($foreignRecordDemand);
1001
        $organisators = $this->organisatorRepository->findDemanded($foreignRecordDemand);
1002
        $speakers = $this->speakerRepository->findDemanded($foreignRecordDemand);
1003
        $events = $this->eventRepository->findDemanded($eventDemand);
1004
1005
        $modifySearchViewVariablesEvent = new ModifySearchViewVariablesEvent(
1006
            [
1007
                'events' => $events,
1008
                'categories' => $categories,
1009
                'locations' => $locations,
1010
                'organisators' => $organisators,
1011
                'speakers' => $speakers,
1012
                'searchDemand' => $searchDemand,
1013
                'overwriteDemand' => $overwriteDemand,
1014
            ],
1015
            $this
1016
        );
1017
        $this->eventDispatcher->dispatch($modifySearchViewVariablesEvent);
0 ignored issues
show
Documentation introduced by
$modifySearchViewVariablesEvent is of type object<DERHANSEN\SfEvent...archViewVariablesEvent>, but the function expects a object<Psr\EventDispatcher\object>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1018
        $variables = $modifySearchViewVariablesEvent->getVariables();
1019
        $this->view->assignMultiple($variables);
1020
    }
1021
1022
    /**
1023
     * Returns if a demand object can be overwritten with the given overwriteDemand array
1024
     *
1025
     * @param array $overwriteDemand
1026
     * @return bool
1027
     */
1028
    protected function isOverwriteDemand($overwriteDemand)
1029
    {
1030
        return $this->settings['disableOverrideDemand'] != 1 && $overwriteDemand !== [];
1031
    }
1032
1033
    /**
1034
     * If no event is given and the singleEvent setting is set, the configured single event is returned
1035
     *
1036
     * @param Event|null $event
1037
     * @return Event|null
1038
     */
1039
    protected function evaluateSingleEventSetting($event)
1040
    {
1041
        if ($event === null && (int)$this->settings['singleEvent'] > 0) {
1042
            $event = $this->eventRepository->findByUid((int)$this->settings['singleEvent']);
1043
        }
1044
1045
        return $event;
1046
    }
1047
1048
    /**
1049
     * If no event is given and the isShortcut setting is set, the event is displayed using the "Insert Record"
1050
     * content element and should be loaded from contect object data
1051
     *
1052
     * @param Event|null $event
1053
     * @return Event|null
1054
     */
1055
    protected function evaluateIsShortcutSetting($event)
1056
    {
1057
        if ($event === null && (bool)$this->settings['detail']['isShortcut']) {
1058
            $eventRawData = $this->configurationManager->getContentObject()->data;
1059
            $event = $this->eventRepository->findByUid($eventRawData['uid']);
1060
        }
1061
1062
        return $event;
1063
    }
1064
1065
    /**
1066
     * Checks if the event pid could be found in the storagePage settings of the detail plugin and
1067
     * if the pid could not be found it return null instead of the event object.
1068
     *
1069
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Event $event
1070
     * @return null|\DERHANSEN\SfEventMgt\Domain\Model\Event
1071
     */
1072
    protected function checkPidOfEventRecord(Event $event)
1073
    {
1074
        $allowedStoragePages = GeneralUtility::trimExplode(
1075
            ',',
1076
            Page::extendPidListByChildren(
1077
                $this->settings['storagePage'],
1078
                $this->settings['recursive']
1079
            ),
1080
            true
1081
        );
1082
        if (count($allowedStoragePages) > 0 && !in_array($event->getPid(), $allowedStoragePages)) {
1083
            $this->eventDispatcher->dispatch(new EventPidCheckFailedEvent($event, $this));
0 ignored issues
show
Documentation introduced by
new \DERHANSEN\SfEventMg...ledEvent($event, $this) is of type object<DERHANSEN\SfEvent...entPidCheckFailedEvent>, but the function expects a object<Psr\EventDispatcher\object>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1084
            $event = null;
1085
        }
1086
1087
        return $event;
1088
    }
1089
1090
    /**
1091
     * Returns the current sys_language_uid
1092
     *
1093
     * @return int
1094
     */
1095
    protected function getSysLanguageUid()
1096
    {
1097
        $languageAspect = GeneralUtility::makeInstance(Context::class)->getAspect('language');
1098
1099
        return $languageAspect->getId();
1100
    }
1101
}
1102