Completed
Push — development ( 613ee8...12e837 )
by Torben
05:58
created

EventController::saveRegistrationResultAction()   C

Complexity

Conditions 11
Paths 20

Size

Total Lines 59
Code Lines 51

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 11

Importance

Changes 0
Metric Value
dl 0
loc 59
rs 6.3545
c 0
b 0
f 0
ccs 12
cts 12
cp 1
cc 11
eloc 51
nc 20
nop 3
crap 11

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Utility\MessageType;
18
use DERHANSEN\SfEventMgt\Utility\Page;
19
use DERHANSEN\SfEventMgt\Utility\RegistrationResult;
20
use TYPO3\CMS\Core\Utility\ArrayUtility;
21
use TYPO3\CMS\Core\Utility\GeneralUtility;
22
use TYPO3\CMS\Core\Utility\HttpUtility;
23
use TYPO3\CMS\Extbase\Mvc\RequestInterface;
24
use TYPO3\CMS\Extbase\Mvc\ResponseInterface;
25
use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
26
use TYPO3\CMS\Extbase\Property\TypeConverter\DateTimeConverter;
27
use TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter;
28
use TYPO3\CMS\Fluid\View\StandaloneView;
29
30
/**
31
 * EventController
32
 *
33
 * @author Torben Hansen <[email protected]>
34
 */
35
class EventController extends AbstractController
36
{
37
    /**
38
     * Assign contentObjectData and pageData to earch view
39
     *
40
     * @param \TYPO3\CMS\Extbase\Mvc\View\ViewInterface $view
41
     */
42
    protected function initializeView(\TYPO3\CMS\Extbase\Mvc\View\ViewInterface $view)
43
    {
44
        $view->assign('contentObjectData', $this->configurationManager->getContentObject()->data);
45
        if (is_object($GLOBALS['TSFE'])) {
46
            $view->assign('pageData', $GLOBALS['TSFE']->page);
47
        }
48
        parent::initializeView($view);
49
    }
50
51
    /**
52
     * Properties in this array will be ignored by overwriteDemandObject()
53
     *
54
     * @var array
55
     */
56
    protected $ignoredSettingsForOverwriteDemand = ['storagepage', 'orderfieldallowed'];
57
58
    /**
59
     * Creates an event demand object with the given settings
60
     *
61
     * @param array $settings The settings
62
     *
63
     * @return \DERHANSEN\SfEventMgt\Domain\Model\Dto\EventDemand
64
     */
65
    public function createEventDemandObjectFromSettings(array $settings)
66
    {
67
        /** @var \DERHANSEN\SfEventMgt\Domain\Model\Dto\EventDemand $demand */
68
        $demand = $this->objectManager->get(EventDemand::class);
69
        $demand->setDisplayMode($settings['displayMode']);
70
        $demand->setStoragePage(Page::extendPidListByChildren($settings['storagePage'], $settings['recursive']));
71
        $demand->setCategoryConjunction($settings['categoryConjunction']);
72
        $demand->setCategory($settings['category']);
73
        $demand->setIncludeSubcategories($settings['includeSubcategories']);
74
        $demand->setTopEventRestriction((int)$settings['topEventRestriction']);
75
        $demand->setOrderField($settings['orderField']);
76
        $demand->setOrderFieldAllowed($settings['orderFieldAllowed']);
77
        $demand->setOrderDirection($settings['orderDirection']);
78
        $demand->setQueryLimit($settings['queryLimit']);
79
        $demand->setLocation($settings['location']);
80
        $demand->setOrganisator($settings['organisator']);
81
82
        return $demand;
83
    }
84
85
    /**
86
     * Creates a foreign record demand object with the given settings
87
     *
88
     * @param array $settings The settings
89
     *
90
     * @return \DERHANSEN\SfEventMgt\Domain\Model\Dto\ForeignRecordDemand
91
     */
92
    public function createForeignRecordDemandObjectFromSettings(array $settings)
93
    {
94
        /** @var \DERHANSEN\SfEventMgt\Domain\Model\Dto\ForeignRecordDemand $demand */
95
        $demand = $this->objectManager->get(ForeignRecordDemand::class);
96
        $demand->setStoragePage(Page::extendPidListByChildren($settings['storagePage'], $settings['recursive']));
97
        $demand->setRestrictForeignRecordsToStoragePage((bool)$settings['restrictForeignRecordsToStoragePage']);
98
99
        return $demand;
100
    }
101
102
    /**
103
     * Creates a category demand object with the given settings
104
     *
105
     * @param array $settings The settings
106
     *
107
     * @return \DERHANSEN\SfEventMgt\Domain\Model\Dto\CategoryDemand
108
     */
109
    public function createCategoryDemandObjectFromSettings(array $settings)
110
    {
111
        /** @var \DERHANSEN\SfEventMgt\Domain\Model\Dto\CategoryDemand $demand */
112
        $demand = $this->objectManager->get(CategoryDemand::class);
113
        $demand->setStoragePage(Page::extendPidListByChildren($settings['storagePage'], $settings['recursive']));
114
        $demand->setRestrictToStoragePage((bool)$settings['restrictForeignRecordsToStoragePage']);
115
        $demand->setCategories($settings['categoryMenu']['categories']);
116
        $demand->setIncludeSubcategories($settings['categoryMenu']['includeSubcategories']);
117
118
        return $demand;
119
    }
120
121
    /**
122
     * Overwrites a given demand object by an propertyName =>  $propertyValue array
123
     *
124
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Dto\EventDemand $demand Demand
125
     * @param array $overwriteDemand OwerwriteDemand
126
     *
127
     * @return \DERHANSEN\SfEventMgt\Domain\Model\Dto\EventDemand
128
     */
129
    protected function overwriteEventDemandObject(EventDemand $demand, array $overwriteDemand)
130
    {
131
        foreach ($this->ignoredSettingsForOverwriteDemand as $property) {
132
            unset($overwriteDemand[$property]);
133
        }
134
135
        foreach ($overwriteDemand as $propertyName => $propertyValue) {
136
            if (in_array(strtolower($propertyName), $this->ignoredSettingsForOverwriteDemand, true)) {
137 1
                continue;
138
            }
139
            \TYPO3\CMS\Extbase\Reflection\ObjectAccess::setProperty($demand, $propertyName, $propertyValue);
140 1
        }
141 1
142 1
        return $demand;
143 1
    }
144 1
145 1
    /**
146 1
     * Hook into request processing and catch exceptions
147 1
     *
148 1
     * @param RequestInterface $request
149 1
     * @param ResponseInterface $response
150 1
     * @throws \Exception
151
     */
152
    public function processRequest(RequestInterface $request, ResponseInterface $response)
153
    {
154
        try {
155
            parent::processRequest($request, $response);
156
        } catch (\Exception $exception) {
157
            $this->handleKnownExceptionsElseThrowAgain($exception);
158
        }
159
    }
160
161
    /**
162
     * Handle known exceptions
163
     *
164
     * @param \Exception $exception
165
     * @throws \Exception
166
     */
167
    private function handleKnownExceptionsElseThrowAgain(\Exception $exception)
168
    {
169
        $previousException = $exception->getPrevious();
170
        $actions = ['detailAction', 'registrationAction', 'icalDownloadAction'];
171
        if (in_array($this->actionMethodName, $actions, true)
172
            && $previousException instanceof \TYPO3\CMS\Extbase\Property\Exception
173
        ) {
174
            $this->handleEventNotFoundError($this->settings);
175
        } else {
176 1
            throw $exception;
177
        }
178
    }
179 1
180 1
    /**
181 1
     * Initialize list action and set format
182 1
     *
183 1
     * @return void
184 1
     */
185
    public function initializeListAction()
186
    {
187
        if (isset($this->settings['list']['format'])) {
188
            $this->request->setFormat($this->settings['list']['format']);
189
        }
190
    }
191
192
    /**
193
     * List view
194
     *
195 2
     * @param array $overwriteDemand OverwriteDemand
196
     *
197 2
     * @return void
198 2
     */
199 2
    public function listAction(array $overwriteDemand = [])
200
    {
201 2
        $eventDemand = $this->createEventDemandObjectFromSettings($this->settings);
202 2
        $foreignRecordDemand = $this->createForeignRecordDemandObjectFromSettings($this->settings);
203 2
        $categoryDemand = $this->createCategoryDemandObjectFromSettings($this->settings);
204 2
        if ($this->isOverwriteDemand($overwriteDemand)) {
205
            $eventDemand = $this->overwriteEventDemandObject($eventDemand, $overwriteDemand);
206
        }
207
        $events = $this->eventRepository->findDemanded($eventDemand);
208
        $categories = $this->categoryRepository->findDemanded($categoryDemand);
209
        $locations = $this->locationRepository->findDemanded($foreignRecordDemand);
210
        $organisators = $this->organisatorRepository->findDemanded($foreignRecordDemand);
211
212
        $values = [
213
            'events' => $events,
214
            'categories' => $categories,
215
            'locations' => $locations,
216
            'organisators' => $organisators,
217
            'overwriteDemand' => $overwriteDemand,
218
            'eventDemand' => $eventDemand
219
        ];
220
221
        $this->signalDispatch(__CLASS__, __FUNCTION__ . 'BeforeRenderView', [&$values, $this]);
222
        $this->view->assignMultiple($values);
223
    }
224
225
    /**
226 3
     * Calendar view
227
     *
228 3
     * @param array $overwriteDemand OverwriteDemand
229 3
     *
230 3
     * @return void
231 3
     */
232 1
    public function calendarAction(array $overwriteDemand = [])
233 1
    {
234 3
        $eventDemand = $this->createEventDemandObjectFromSettings($this->settings);
235 3
        $foreignRecordDemand = $this->createForeignRecordDemandObjectFromSettings($this->settings);
236 3
        $categoryDemand = $this->createCategoryDemandObjectFromSettings($this->settings);
237 3
        if ($this->isOverwriteDemand($overwriteDemand)) {
238 3
            $eventDemand = $this->overwriteEventDemandObject($eventDemand, $overwriteDemand);
239 3
        }
240 3
241 3
        // Set month/year to demand if not given
242
        if (!$eventDemand->getMonth()) {
243
            $currentMonth = date('n');
244
            $eventDemand->setMonth($currentMonth);
245
        } else {
246
            $currentMonth = $eventDemand->getMonth();
247
        }
248
        if (!$eventDemand->getYear()) {
249
            $currentYear = date('Y');
250 1
            $eventDemand->setYear($currentYear);
251
        } else {
252 1
            $currentYear = $eventDemand->getYear();
253 1
        }
254
255
        // Set demand from calendar date range instead of month / year
256
        if ((bool)$this->settings['calendar']['includeEventsForEveryDayOfAllCalendarWeeks']) {
257
            $eventDemand = $this->changeEventDemandToFullMonthDateRange($eventDemand);
258
        }
259
260
        $events = $this->eventRepository->findDemanded($eventDemand);
261
        $weeks = $this->calendarService->getCalendarArray(
262 1
            $currentMonth,
263
            $currentYear,
264 1
            strtotime('today midnight'),
265 1
            (int)$this->settings['calendar']['firstDayOfWeek'],
266
            $events
267
        );
268
269
        $values = [
270
            'weeks' => $weeks,
271
            'categories' => $this->categoryRepository->findDemanded($categoryDemand),
272
            'locations' => $this->locationRepository->findDemanded($foreignRecordDemand),
273
            'organisators' => $this->organisatorRepository->findDemanded($foreignRecordDemand),
274
            'eventDemand' => $eventDemand,
275 1
            'overwriteDemand' => $overwriteDemand,
276
            'currentPageId' => $GLOBALS['TSFE']->id,
277 1
            'firstDayOfMonth' => \DateTime::createFromFormat('d.m.Y', sprintf('1.%s.%s', $currentMonth, $currentYear)),
278
            'previousMonthConfig' => $this->calendarService->getDateConfig($currentMonth, $currentYear, '-1 month'),
279
            'nextMonthConfig' => $this->calendarService->getDateConfig($currentMonth, $currentYear, '+1 month')
280 1
        ];
281
282 1
        $this->signalDispatch(__CLASS__, __FUNCTION__ . 'BeforeRenderView', [&$values, $this]);
283 1
        $this->view->assignMultiple($values);
284 1
    }
285
286
    /**
287
     * Changes the given event demand object to select a date range for a calendar month including days of the previous
288
     * month for the first week and they days for the next month for the last week
289
     *
290
     * @param EventDemand $eventDemand
291 1
     * @return EventDemand
292
     */
293 1
    protected function changeEventDemandToFullMonthDateRange(EventDemand $eventDemand)
294 1
    {
295 1
        $calendarDateRange = $this->calendarService->getCalendarDateRange(
296 1
            $eventDemand->getMonth(),
297 1
            $eventDemand->getYear(),
298 1
            $this->settings['calendar']['firstDayOfWeek']
299 1
        );
300 1
301
        $eventDemand->setMonth(0);
302
        $eventDemand->setYear(0);
303
304
        $startDate = new \DateTime();
305
        $startDate->setTimestamp($calendarDateRange['firstDayOfCalendar']);
306
        $endDate = new \DateTime();
307
        $endDate->setTimestamp($calendarDateRange['lastDayOfCalendar']);
308
        $endDate->setTime(23, 59, 59);
309
310
        $searchDemand = new SearchDemand();
311 11
        $searchDemand->setStartDate($startDate);
312
        $searchDemand->setEndDate($endDate);
313 11
        $eventDemand->setSearchDemand($searchDemand);
314 11
315 11
        return $eventDemand;
316
    }
317
318 11
    /**
319 4
     * Detail view for an event
320 4
     *
321 4
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Event $event Event
322 4
     * @return mixed string|void
323 4
     */
324 4
    public function detailAction(Event $event = null)
325
    {
326 4
        if (is_null($event) && isset($this->settings['event']['errorHandling'])) {
327 4
            return $this->handleEventNotFoundError($this->settings);
328 4
        }
329 4
        $values = ['event' => $event];
330
        $this->signalDispatch(__CLASS__, __FUNCTION__ . 'BeforeRenderView', [&$values, $this]);
331 4
        $this->view->assignMultiple($values);
332 4
    }
333 4
334 4
    /**
335 4
     * Error handling if event is not found
336 4
     *
337 4
     * @param array $settings
338 4
     * @return string
339
     */
340
    protected function handleEventNotFoundError($settings)
341 4
    {
342
        if (empty($settings['event']['errorHandling'])) {
343
            return null;
344 4
        }
345 1
346 1
        $configuration = GeneralUtility::trimExplode(',', $settings['event']['errorHandling'], true);
347 1
348 3
        switch ($configuration[0]) {
349 3
            case 'redirectToListView':
350
                $listPid = (int)$settings['listPid'] > 0 ? (int)$settings['listPid'] : 1;
351 4
                $this->redirect('list', null, null, null, $listPid);
352
                break;
353
            case 'pageNotFoundHandler':
354 4
                $GLOBALS['TSFE']->pageNotFoundAndExit('Event not found.');
355 3
                break;
356 3
            case 'showStandaloneTemplate':
357 3
                if (isset($configuration[2])) {
358 3
                    $statusCode = constant(HttpUtility::class . '::HTTP_STATUS_' . $configuration[2]);
359
                    HttpUtility::setResponseCode($statusCode);
360 3
                }
361 3
                $standaloneTemplate = $this->objectManager->get(StandaloneView::class);
362 3
                $standaloneTemplate->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($configuration[1]));
363 3
364 3
                return $standaloneTemplate->render();
365
                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...
366 3
            default:
367 3
        }
368
    }
369
370 4
    /**
371 1
     * Initiates the iCalendar download for the given event
372 1
     *
373
     * @param Event $event The event
374
     *
375 4
     * @return string|false
376 4
     */
377
    public function icalDownloadAction(Event $event = null)
378 11
    {
379 1
        if (is_null($event) && isset($this->settings['event']['errorHandling'])) {
380 1
            return $this->handleEventNotFoundError($this->settings);
381 1
        }
382 1
        $this->icalendarService->downloadiCalendarFile($event);
0 ignored issues
show
Bug introduced by
It seems like $event defined by parameter $event on line 377 can be null; however, DERHANSEN\SfEventMgt\Ser...downloadiCalendarFile() 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...
383
384 1
        return false;
385 1
    }
386 1
387 1
    /**
388 1
     * Registration view for an event
389 10
     *
390 10
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Event $event Event
391 10
     *
392 10
     * @return mixed string|void
393 10
     */
394 10
    public function registrationAction(Event $event = null)
395
    {
396 11
        if (is_null($event) && isset($this->settings['event']['errorHandling'])) {
397
            return $this->handleEventNotFoundError($this->settings);
398
        }
399
        if ($event->getRestrictPaymentMethods()) {
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...
400
            $paymentMethods = $this->paymentService->getRestrictedPaymentMethods($event);
0 ignored issues
show
Bug introduced by
It seems like $event defined by parameter $event on line 394 can be null; however, DERHANSEN\SfEventMgt\Ser...trictedPaymentMethods() 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...
401
        } else {
402
            $paymentMethods = $this->paymentService->getPaymentMethods();
403
        }
404
405 9
        $values = [
406
            'event' => $event,
407
            'paymentMethods' => $paymentMethods,
408 9
        ];
409 1
410 1
        $this->signalDispatch(__CLASS__, __FUNCTION__ . 'BeforeRenderView', [&$values, $this]);
411 1
        $this->view->assignMultiple($values);
412 8
    }
413
414
    /**
415
     * Processes incoming registrations fields and adds field values to arguments
416 8
     *
417 1
     * @return void
418 1
     */
419 1
    protected function setRegistrationFieldValuesToArguments()
420 7
    {
421 1
        $arguments = $this->request->getArguments();
422 1
        if (!isset($arguments['registration']['fields']) || !isset($arguments['event'])) {
423 1
            return;
424 6
        }
425 1
426 1
        $registrationMvcArgument = $this->arguments->getArgument('registration');
427 1
        $propertyMapping = $registrationMvcArgument->getPropertyMappingConfiguration();
428 5
        $propertyMapping->allowProperties('fieldValues');
429 1
        $propertyMapping->allowCreationForSubProperty('fieldValues');
430 1
        $propertyMapping->allowModificationForSubProperty('fieldValues');
431 1
432 4
        // allow creation of new objects (for validation)
433 1
        $propertyMapping->setTypeConverterOptions(
434 1
            PersistentObjectConverter::class,
435 1
            [
436 3
                PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => true,
437 1
                PersistentObjectConverter::CONFIGURATION_MODIFICATION_ALLOWED => true
438 1
            ]
439 1
        );
440 2
441 1
        // Set event to registration (required for validation)
442 1
        $event = $this->eventRepository->findByUid((int)$this->request->getArgument('event'));
443 1
        $propertyMapping->allowProperties('event');
444 1
        $propertyMapping->allowCreationForSubProperty('event');
445 1
        $propertyMapping->allowModificationForSubProperty('event');
446 1
        $arguments['registration']['event'] = (int)$this->request->getArgument('event');
447 1
448
        $index = 0;
449 9
        foreach ((array)$arguments['registration']['fields'] as $fieldUid => $value) {
450 9
            // Only accept registration fields of the current event
451 9
            if (!in_array((int)$fieldUid, $event->getRegistrationFieldsUids(), true)) {
452
                continue;
453
            }
454
455
            // allow subvalues in new property mapper
456
            $propertyMapping->forProperty('fieldValues')->allowProperties($index);
457
            $propertyMapping->forProperty('fieldValues.' . $index)->allowAllProperties();
458
            $propertyMapping->allowCreationForSubProperty('fieldValues.' . $index);
459
            $propertyMapping->allowModificationForSubProperty('fieldValues.' . $index);
460
461 3
            if (is_array($value)) {
462
                if (empty($value)) {
463
                    $value = '';
464 3
                } else {
465
                    $value = json_encode($value);
466 3
                }
467 2
            }
468 2
469
            /** @var Registration\Field $field */
470 2
            $field = $this->fieldRepository->findByUid((int)$fieldUid);
471 2
472 1
            $arguments['registration']['fieldValues'][$index] = [
473 1
                'value' => $value,
474
                'field' => strval($fieldUid),
475
                'valueType' => $field->getValueType()
476 2
            ];
477 2
478 2
            $index++;
479 2
        }
480
481 2
        // Remove temporary "fields" field
482 2
        $arguments = ArrayUtility::removeByPath($arguments, 'registration/fields');
483 2
        $this->request->setArguments($arguments);
484 2
    }
485 2
486
    /**
487 2
     * Set date format for field dateOfBirth
488
     *
489
     * @return void
490 2
     */
491 2
    public function initializeSaveRegistrationAction()
492 2
    {
493 2
        $this->arguments->getArgument('registration')
494
            ->getPropertyMappingConfiguration()->forProperty('dateOfBirth')
495
            ->setTypeConverterOption(
496 3
                DateTimeConverter::class,
497 3
                DateTimeConverter::CONFIGURATION_DATE_FORMAT,
498
                $this->settings['registration']['formatDateOfBirth']
499
            );
500
        $this->setRegistrationFieldValuesToArguments();
501
    }
502
503
    /**
504
     * Saves the registration
505
     *
506
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Registration $registration Registration
507
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Event $event Event
508
     * @validate $registration \DERHANSEN\SfEventMgt\Validation\Validator\RegistrationFieldValidator
509
     * @validate $registration \DERHANSEN\SfEventMgt\Validation\Validator\RegistrationValidator
510
     *
511
     * @return void
512
     */
513
    public function saveRegistrationAction(Registration $registration, Event $event)
514 3
    {
515 3
        $autoConfirmation = (bool)$this->settings['registration']['autoConfirmation'] || $event->getEnableAutoconfirm();
516 3
        $result = RegistrationResult::REGISTRATION_SUCCESSFUL;
517
        $success = $this->registrationService->checkRegistrationSuccess($event, $registration, $result);
518
519
        // Save registration if no errors
520
        if ($success) {
521
            $isWaitlistRegistration = $this->registrationService->isWaitlistRegistration(
522
                $event,
523
                $registration->getAmountOfRegistrations()
524
            );
525
            $linkValidity = (int)$this->settings['confirmation']['linkValidity'];
526 2
            if ($linkValidity === 0) {
527
                // Use 3600 seconds as default value if not set
528
                $linkValidity = 3600;
529 2
            }
530
            $confirmationUntil = new \DateTime();
531 2
            $confirmationUntil->add(new \DateInterval('PT' . $linkValidity . 'S'));
532
533 1
            $registration->setEvent($event);
534 1
            $registration->setPid($event->getPid());
535 1
            $registration->setConfirmationUntil($confirmationUntil);
536 1
            $registration->setLanguage($GLOBALS['TSFE']->config['config']['language']);
537
            $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...
538 1
            $registration->setWaitlist($isWaitlistRegistration);
539 1
            $registration->_setProperty('_languageUid', $GLOBALS['TSFE']->sys_language_uid);
540 1
            $this->registrationRepository->add($registration);
541 1
542 1
            // Persist registration, so we have an UID
543
            $this->objectManager->get(PersistenceManager::class)->persistAll();
544 1
545
            // Add new registration (or waitlist registration) to event
546
            if ($isWaitlistRegistration) {
547 1
                $event->addRegistrationWaitlist($registration);
548 1
                $messageType = MessageType::REGISTRATION_WAITLIST_NEW;
549 1
            } else {
550
                $event->addRegistration($registration);
551
                $messageType = MessageType::REGISTRATION_NEW;
552 1
            }
553
            $this->eventRepository->update($event);
554
555 1
            $this->signalDispatch(__CLASS__, __FUNCTION__ . 'AfterRegistrationSaved', [$registration, $this]);
556 1
557 2
            // Send notifications to user and admin if confirmation link should be sent
558 2
            if (!$autoConfirmation) {
559 2
                $this->notificationService->sendUserMessage(
560
                    $event,
561
                    $registration,
562
                    $this->settings,
563
                    $messageType
564
                );
565
                $this->notificationService->sendAdminMessage(
566 1
                    $event,
567
                    $registration,
568 1
                    $this->settings,
569 1
                    $messageType
570 1
                );
571 1
            }
572 1
573 1
            // Create given amount of registrations if necessary
574 1
            if ($registration->getAmountOfRegistrations() > 1) {
575 1
                $this->registrationService->createDependingRegistrations($registration);
576 1
            }
577 1
578 1
            // Clear cache for configured pages
579 1
            $this->utilityService->clearCacheForConfiguredUids($this->settings);
580 1
        }
581 1
582 1
        if ($autoConfirmation && $success) {
583 1
            $this->redirect(
584 1
                'confirmRegistration',
585
                null,
586
                null,
587
                [
588
                    'reguid' => $registration->getUid(),
589
                    'hmac' => $this->hashService->generateHmac('reg-' . $registration->getUid())
590
                ]
591
            );
592
        } else {
593
            $this->redirect(
594 6
                'saveRegistrationResult',
595
                null,
596 6
                null,
597 6
                [
598 6
                    'result' => $result,
599 6
                    'eventuid' => $event->getUid(),
600
                    'hmac' => $this->hashService->generateHmac('event-' . $event->getUid())
601 6
                ]
602 5
            );
603
        }
604 5
    }
605 1
606 1
    /**
607
     * Shows the result of the saveRegistrationAction
608 5
     *
609 1
     * @param int $result Result
610 1
     * @param int $eventuid
611 5
     * @param string $hmac
612
     *
613 6
     * @return void
614 1
     */
615 1
    public function saveRegistrationResultAction($result, $eventuid, $hmac)
616
    {
617 6
        $event = null;
618 6
619
        switch ($result) {
620 6
            case RegistrationResult::REGISTRATION_SUCCESSFUL:
621
                $messageKey = 'event.message.registrationsuccessful';
622 6
                $titleKey = 'registrationResult.title.successful';
623 6
                break;
624 6
            case RegistrationResult::REGISTRATION_SUCCESSFUL_WAITLIST:
625 6
                $messageKey = 'event.message.registrationwaitlistsuccessful';
626 6
                $titleKey = 'registrationWaitlistResult.title.successful';
627 6
                break;
628
            case RegistrationResult::REGISTRATION_FAILED_EVENT_EXPIRED:
629
                $messageKey = 'event.message.registrationfailedeventexpired';
630
                $titleKey = 'registrationResult.title.failed';
631
                break;
632
            case RegistrationResult::REGISTRATION_FAILED_MAX_PARTICIPANTS:
633
                $messageKey = 'event.message.registrationfailedmaxparticipants';
634
                $titleKey = 'registrationResult.title.failed';
635 9
                break;
636
            case RegistrationResult::REGISTRATION_NOT_ENABLED:
637 9
                $messageKey = 'event.message.registrationfailednotenabled';
638
                $titleKey = 'registrationResult.title.failed';
639
                break;
640
            case RegistrationResult::REGISTRATION_FAILED_DEADLINE_EXPIRED:
641
                $messageKey = 'event.message.registrationfaileddeadlineexpired';
642
                $titleKey = 'registrationResult.title.failed';
643
                break;
644
            case RegistrationResult::REGISTRATION_FAILED_NOT_ENOUGH_FREE_PLACES:
645
                $messageKey = 'event.message.registrationfailednotenoughfreeplaces';
646
                $titleKey = 'registrationResult.title.failed';
647
                break;
648
            case RegistrationResult::REGISTRATION_FAILED_MAX_AMOUNT_REGISTRATIONS_EXCEEDED:
649
                $messageKey = 'event.message.registrationfailedmaxamountregistrationsexceeded';
650
                $titleKey = 'registrationResult.title.failed';
651
                break;
652
            case RegistrationResult::REGISTRATION_FAILED_EMAIL_NOT_UNIQUE:
653
                $messageKey = 'event.message.registrationfailedemailnotunique';
654
                $titleKey = 'registrationResult.title.failed';
655
                break;
656
            default:
657
                $messageKey = '';
658
                $titleKey = '';
659
        }
660
661
        if (!$this->hashService->validateHmac('event-' . $eventuid, $hmac)) {
662
            $messageKey = 'event.message.registrationsuccessfulwrongeventhmac';
663
            $titleKey = 'registrationResult.title.failed';
664
        } else {
665
            $event = $this->eventRepository->findByUid((int)$eventuid);
666
        }
667
668
        $this->view->assignMultiple([
669
            'messageKey' => $messageKey,
670
            'titleKey' => $titleKey,
671
            'event' => $event,
672
        ]);
673
    }
674
675
    /**
676
     * Confirms the registration if possible and sends e-mails to admin and user
677
     *
678
     * @param int $reguid UID of registration
679
     * @param string $hmac HMAC for parameters
680
     *
681
     * @return void
682
     */
683
    public function confirmRegistrationAction($reguid, $hmac)
684
    {
685
        $event = null;
686
687
        /* @var $registration Registration */
688
        list($failed, $registration, $messageKey, $titleKey) = $this->registrationService->checkConfirmRegistration(
689
            $reguid,
690
            $hmac
691
        );
692
693
        if ($failed === false) {
694
            $registration->setConfirmed(true);
695
            $event = $registration->getEvent();
696
            $this->registrationRepository->update($registration);
697
698
            $messageType = MessageType::REGISTRATION_CONFIRMED;
699
            if ($registration->getWaitlist()) {
700
                $messageType = MessageType::REGISTRATION_WAITLIST_CONFIRMED;
701
            }
702
703
            // Send notifications to user and admin
704
            $this->notificationService->sendUserMessage(
705
                $registration->getEvent(),
706
                $registration,
707
                $this->settings,
708
                $messageType
709
            );
710
            $this->notificationService->sendAdminMessage(
711
                $registration->getEvent(),
712
                $registration,
713
                $this->settings,
714
                $messageType
715
            );
716
717
            // Confirm registrations depending on main registration if necessary
718
            if ($registration->getAmountOfRegistrations() > 1) {
719
                $this->registrationService->confirmDependingRegistrations($registration);
720
            }
721
        }
722
723
        // Redirect to payment provider if payment/redirect is enabled
724
        $paymentPid = (int)$this->settings['paymentPid'];
725
        if (!$failed && $paymentPid > 0 && $this->registrationService->redirectPaymentEnabled($registration)) {
726
            $this->uriBuilder->reset()
727
                ->setTargetPageUid($paymentPid)
728
                ->setUseCacheHash(false);
729
            $uri = $this->uriBuilder->uriFor(
730
                'redirect',
731
                [
732
                    'registration' => $registration,
733
                    'hmac' => $this->hashService->generateHmac('redirectAction-' . $registration->getUid())
734
                ],
735
                'Payment',
736
                'sfeventmgt',
737
                'Pipayment'
738
            );
739
            $this->redirectToUri($uri);
740
        }
741
742
        $values = [
743
            'messageKey' => $messageKey,
744
            'titleKey' => $titleKey,
745
            'event' => $event,
746
        ];
747
748
        $this->signalDispatch(__CLASS__, __FUNCTION__ . 'BeforeRenderView', [&$values, $this]);
749
        $this->view->assignMultiple($values);
750
    }
751
752
    /**
753
     * Cancels the registration if possible and sends e-mails to admin and user
754
     *
755
     * @param int $reguid UID of registration
756
     * @param string $hmac HMAC for parameters
757
     *
758
     * @return void
759
     */
760
    public function cancelRegistrationAction($reguid, $hmac)
761
    {
762
        $event = null;
763
764
        /* @var $registration Registration */
765
        list($failed, $registration, $messageKey, $titleKey) = $this->registrationService->checkCancelRegistration($reguid, $hmac);
766
767
        if ($failed === false) {
768
            $event = $registration->getEvent();
769
770
            // Send notifications (must run before cancelling the registration)
771
            $this->notificationService->sendUserMessage(
772
                $registration->getEvent(),
773
                $registration,
774
                $this->settings,
775
                MessageType::REGISTRATION_CANCELLED
776
            );
777
            $this->notificationService->sendAdminMessage(
778
                $registration->getEvent(),
779
                $registration,
780
                $this->settings,
781
                MessageType::REGISTRATION_CANCELLED
782
            );
783
784
            // First cancel depending registrations
785
            if ($registration->getAmountOfRegistrations() > 1) {
786
                $this->registrationService->cancelDependingRegistrations($registration);
787
            }
788
789
            // Finally cancel registration
790
            $this->registrationRepository->remove($registration);
791
792
            // Clear cache for configured pages
793
            $this->utilityService->clearCacheForConfiguredUids($this->settings);
794
        }
795
796
        $values = [
797
            'messageKey' => $messageKey,
798
            'titleKey' => $titleKey,
799
            'event' => $event,
800
        ];
801
802
        $this->signalDispatch(__CLASS__, __FUNCTION__ . 'BeforeRenderView', [&$values, $this]);
803
        $this->view->assignMultiple($values);
804
    }
805
806
    /**
807
     * Set date format for field startDate and endDate
808
     *
809
     * @return void
810
     */
811
    public function initializeSearchAction()
812
    {
813
        if ($this->settings !== null && $this->settings['search']['dateFormat']) {
814
            $this->arguments->getArgument('searchDemand')
815
                ->getPropertyMappingConfiguration()->forProperty('startDate')
816
                ->setTypeConverterOption(
817
                    DateTimeConverter::class,
818
                    DateTimeConverter::CONFIGURATION_DATE_FORMAT,
819
                    $this->settings['search']['dateFormat']
820
                );
821
            $this->arguments->getArgument('searchDemand')
822
                ->getPropertyMappingConfiguration()->forProperty('endDate')
823
                ->setTypeConverterOption(
824
                    DateTimeConverter::class,
825
                    DateTimeConverter::CONFIGURATION_DATE_FORMAT,
826
                    $this->settings['search']['dateFormat']
827
                );
828
        }
829
        if ($this->arguments->hasArgument('searchDemand')) {
830
            $propertyMappingConfiguration = $this->arguments->getArgument('searchDemand')
831
                ->getPropertyMappingConfiguration();
832
            $propertyMappingConfiguration->allowAllProperties();
833
            $propertyMappingConfiguration->setTypeConverterOption(
834
                PersistentObjectConverter::class,
835
                PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED,
836
                true
837
            );
838
        }
839
    }
840
841
    /**
842
     * Search view
843
     *
844
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Dto\SearchDemand $searchDemand SearchDemand
845
     * @param array $overwriteDemand OverwriteDemand
846
     *
847
     * @return void
848
     */
849
    public function searchAction(SearchDemand $searchDemand = null, array $overwriteDemand = [])
850
    {
851
        $eventDemand = $this->createEventDemandObjectFromSettings($this->settings);
852
        $eventDemand->setSearchDemand($searchDemand);
0 ignored issues
show
Bug introduced by
It seems like $searchDemand defined by parameter $searchDemand on line 849 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...
853
        $foreignRecordDemand = $this->createForeignRecordDemandObjectFromSettings($this->settings);
854
        $categoryDemand = $this->createCategoryDemandObjectFromSettings($this->settings);
855
856
        if ($searchDemand !== null) {
857
            $searchDemand->setFields($this->settings['search']['fields']);
858
859
            if ($this->settings['search']['adjustTime'] && $searchDemand->getStartDate() !== null) {
860
                $searchDemand->getStartDate()->setTime(0, 0, 0);
861
            }
862
863
            if ($this->settings['search']['adjustTime'] && $searchDemand->getEndDate() !== null) {
864
                $searchDemand->getEndDate()->setTime(23, 59, 59);
865
            }
866
        }
867
868
        if ($this->isOverwriteDemand($overwriteDemand)) {
869
            $eventDemand = $this->overwriteEventDemandObject($eventDemand, $overwriteDemand);
870
        }
871
872
        $categories = $this->categoryRepository->findDemanded($categoryDemand);
873
        $locations = $this->locationRepository->findDemanded($foreignRecordDemand);
874
        $organisators = $this->organisatorRepository->findDemanded($foreignRecordDemand);
875
        $events = $this->eventRepository->findDemanded($eventDemand);
876
877
        $values = [
878
            'events' => $events,
879
            'categories' => $categories,
880
            'locations' => $locations,
881
            'organisators' => $organisators,
882
            'searchDemand' => $searchDemand,
883
            'overwriteDemand' => $overwriteDemand,
884
        ];
885
886
        $this->signalDispatch(__CLASS__, __FUNCTION__ . 'BeforeRenderView', [&$values, $this]);
887
        $this->view->assignMultiple($values);
888
    }
889
890
    /**
891
     * Returns if a demand object can be overwritten with the given overwriteDemand array
892
     *
893
     * @param array $overwriteDemand
894
     * @return bool
895
     */
896
    protected function isOverwriteDemand($overwriteDemand)
897
    {
898
        return $this->settings['disableOverrideDemand'] != 1 && $overwriteDemand !== [];
899
    }
900
}
901