Completed
Push — master ( 613ee8...b4d6e2 )
by Torben
03:56 queued 02:19
created

EventController::initializeSearchAction()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 29
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
dl 0
loc 29
ccs 0
cts 0
cp 0
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 22
nc 4
nop 0
crap 20
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 2
                continue;
138
            }
139
            \TYPO3\CMS\Extbase\Reflection\ObjectAccess::setProperty($demand, $propertyName, $propertyValue);
140 2
        }
141 2
142 2
        return $demand;
143 2
    }
144 2
145 2
    /**
146 2
     * Hook into request processing and catch exceptions
147 2
     *
148 2
     * @param RequestInterface $request
149 2
     * @param ResponseInterface $response
150 2
     * @throws \Exception
151 2
     */
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
            throw $exception;
177 2
        }
178
    }
179
180 2
    /**
181 2
     * Initialize list action and set format
182 2
     *
183 2
     * @return void
184 2
     */
185 2
    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
     * @param array $overwriteDemand OverwriteDemand
196 4
     *
197
     * @return void
198 4
     */
199 4
    public function listAction(array $overwriteDemand = [])
200 4
    {
201
        $eventDemand = $this->createEventDemandObjectFromSettings($this->settings);
202 4
        $foreignRecordDemand = $this->createForeignRecordDemandObjectFromSettings($this->settings);
203 4
        $categoryDemand = $this->createCategoryDemandObjectFromSettings($this->settings);
204 2
        if ($this->isOverwriteDemand($overwriteDemand)) {
205
            $eventDemand = $this->overwriteEventDemandObject($eventDemand, $overwriteDemand);
206 4
        }
207 4
        $events = $this->eventRepository->findDemanded($eventDemand);
208 4
        $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
     * Calendar view
227
     *
228
     * @param array $overwriteDemand OverwriteDemand
229
     *
230 6
     * @return void
231
     */
232 6
    public function calendarAction(array $overwriteDemand = [])
233 6
    {
234 6
        $eventDemand = $this->createEventDemandObjectFromSettings($this->settings);
235 6
        $foreignRecordDemand = $this->createForeignRecordDemandObjectFromSettings($this->settings);
236 2
        $categoryDemand = $this->createCategoryDemandObjectFromSettings($this->settings);
237 2
        if ($this->isOverwriteDemand($overwriteDemand)) {
238 6
            $eventDemand = $this->overwriteEventDemandObject($eventDemand, $overwriteDemand);
239 6
        }
240 6
241 6
        // Set month/year to demand if not given
242 6
        if (!$eventDemand->getMonth()) {
243 6
            $currentMonth = date('n');
244 6
            $eventDemand->setMonth($currentMonth);
245 6
        } else {
246
            $currentMonth = $eventDemand->getMonth();
247
        }
248
        if (!$eventDemand->getYear()) {
249
            $currentYear = date('Y');
250
            $eventDemand->setYear($currentYear);
251
        } else {
252
            $currentYear = $eventDemand->getYear();
253
        }
254 2
255
        // Set demand from calendar date range instead of month / year
256 2
        if ((bool)$this->settings['calendar']['includeEventsForEveryDayOfAllCalendarWeeks']) {
257 2
            $eventDemand = $this->changeEventDemandToFullMonthDateRange($eventDemand);
258
        }
259
260
        $events = $this->eventRepository->findDemanded($eventDemand);
261
        $weeks = $this->calendarService->getCalendarArray(
262
            $currentMonth,
263
            $currentYear,
264
            strtotime('today midnight'),
265
            (int)$this->settings['calendar']['firstDayOfWeek'],
266 2
            $events
267
        );
268 2
269 2
        $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
            'overwriteDemand' => $overwriteDemand,
276
            'currentPageId' => $GLOBALS['TSFE']->id,
277
            'firstDayOfMonth' => \DateTime::createFromFormat('d.m.Y', sprintf('1.%s.%s', $currentMonth, $currentYear)),
278
            'previousMonthConfig' => $this->calendarService->getDateConfig($currentMonth, $currentYear, '-1 month'),
279 2
            'nextMonthConfig' => $this->calendarService->getDateConfig($currentMonth, $currentYear, '+1 month')
280
        ];
281 2
282
        $this->signalDispatch(__CLASS__, __FUNCTION__ . 'BeforeRenderView', [&$values, $this]);
283
        $this->view->assignMultiple($values);
284 2
    }
285
286 2
    /**
287 2
     * Changes the given event demand object to select a date range for a calendar month including days of the previous
288 2
     * month for the first week and they days for the next month for the last week
289
     *
290
     * @param EventDemand $eventDemand
291
     * @return EventDemand
292
     */
293
    protected function changeEventDemandToFullMonthDateRange(EventDemand $eventDemand)
294
    {
295 2
        $calendarDateRange = $this->calendarService->getCalendarDateRange(
296
            $eventDemand->getMonth(),
297 2
            $eventDemand->getYear(),
298 2
            $this->settings['calendar']['firstDayOfWeek']
299 2
        );
300 2
301 2
        $eventDemand->setMonth(0);
302 2
        $eventDemand->setYear(0);
303 2
304 2
        $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
        $searchDemand->setStartDate($startDate);
312
        $searchDemand->setEndDate($endDate);
313
        $eventDemand->setSearchDemand($searchDemand);
314
315 22
        return $eventDemand;
316
    }
317 22
318 22
    /**
319 22
     * Detail view for an event
320
     *
321
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Event $event Event
322 22
     * @return mixed string|void
323 8
     */
324 8
    public function detailAction(Event $event = null)
325 8
    {
326 8
        if (is_null($event) && isset($this->settings['event']['errorHandling'])) {
327 8
            return $this->handleEventNotFoundError($this->settings);
328 8
        }
329
        $values = ['event' => $event];
330 8
        $this->signalDispatch(__CLASS__, __FUNCTION__ . 'BeforeRenderView', [&$values, $this]);
331 8
        $this->view->assignMultiple($values);
332 8
    }
333 8
334
    /**
335 8
     * Error handling if event is not found
336 8
     *
337 8
     * @param array $settings
338 8
     * @return string
339 8
     */
340 8
    protected function handleEventNotFoundError($settings)
341 8
    {
342 8
        if (empty($settings['event']['errorHandling'])) {
343
            return null;
344
        }
345 8
346
        $configuration = GeneralUtility::trimExplode(',', $settings['event']['errorHandling'], true);
347
348 8
        switch ($configuration[0]) {
349 2
            case 'redirectToListView':
350 2
                $listPid = (int)$settings['listPid'] > 0 ? (int)$settings['listPid'] : 1;
351 2
                $this->redirect('list', null, null, null, $listPid);
352 6
                break;
353 6
            case 'pageNotFoundHandler':
354
                $GLOBALS['TSFE']->pageNotFoundAndExit('Event not found.');
355 8
                break;
356
            case 'showStandaloneTemplate':
357
                if (isset($configuration[2])) {
358 8
                    $statusCode = constant(HttpUtility::class . '::HTTP_STATUS_' . $configuration[2]);
359 6
                    HttpUtility::setResponseCode($statusCode);
360 6
                }
361 6
                $standaloneTemplate = $this->objectManager->get(StandaloneView::class);
362 6
                $standaloneTemplate->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($configuration[1]));
363
364 6
                return $standaloneTemplate->render();
365 6
                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 6
            default:
367 6
        }
368 6
    }
369
370 6
    /**
371 6
     * Initiates the iCalendar download for the given event
372
     *
373
     * @param Event $event The event
374 8
     *
375 2
     * @return string|false
376 2
     */
377
    public function icalDownloadAction(Event $event = null)
378
    {
379 8
        if (is_null($event) && isset($this->settings['event']['errorHandling'])) {
380 8
            return $this->handleEventNotFoundError($this->settings);
381
        }
382 22
        $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 2
384 2
        return false;
385 2
    }
386 2
387
    /**
388 2
     * Registration view for an event
389 2
     *
390 2
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Event $event Event
391 2
     *
392 2
     * @return mixed string|void
393 20
     */
394 20
    public function registrationAction(Event $event = null)
395 20
    {
396 20
        if (is_null($event) && isset($this->settings['event']['errorHandling'])) {
397 20
            return $this->handleEventNotFoundError($this->settings);
398 20
        }
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 22
            $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
        $values = [
406
            'event' => $event,
407
            'paymentMethods' => $paymentMethods,
408
        ];
409 18
410
        $this->signalDispatch(__CLASS__, __FUNCTION__ . 'BeforeRenderView', [&$values, $this]);
411
        $this->view->assignMultiple($values);
412 18
    }
413 2
414 2
    /**
415 2
     * Processes incoming registrations fields and adds field values to arguments
416 16
     *
417
     * @return void
418
     */
419
    protected function setRegistrationFieldValuesToArguments()
420 16
    {
421 2
        $arguments = $this->request->getArguments();
422 2
        if (!isset($arguments['registration']['fields']) || !isset($arguments['event'])) {
423 2
            return;
424 14
        }
425 2
426 2
        $registrationMvcArgument = $this->arguments->getArgument('registration');
427 2
        $propertyMapping = $registrationMvcArgument->getPropertyMappingConfiguration();
428 12
        $propertyMapping->allowProperties('fieldValues');
429 2
        $propertyMapping->allowCreationForSubProperty('fieldValues');
430 2
        $propertyMapping->allowModificationForSubProperty('fieldValues');
431 2
432 10
        // allow creation of new objects (for validation)
433 2
        $propertyMapping->setTypeConverterOptions(
434 2
            PersistentObjectConverter::class,
435 2
            [
436 8
                PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => true,
437 2
                PersistentObjectConverter::CONFIGURATION_MODIFICATION_ALLOWED => true
438 2
            ]
439 2
        );
440 6
441 2
        // Set event to registration (required for validation)
442 2
        $event = $this->eventRepository->findByUid((int)$this->request->getArgument('event'));
443 2
        $propertyMapping->allowProperties('event');
444 4
        $propertyMapping->allowCreationForSubProperty('event');
445 2
        $propertyMapping->allowModificationForSubProperty('event');
446 2
        $arguments['registration']['event'] = (int)$this->request->getArgument('event');
447 2
448 2
        $index = 0;
449 2
        foreach ((array)$arguments['registration']['fields'] as $fieldUid => $value) {
450 2
            // Only accept registration fields of the current event
451 2
            if (!in_array((int)$fieldUid, $event->getRegistrationFieldsUids(), true)) {
452
                continue;
453 18
            }
454 18
455 18
            // 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
            if (is_array($value)) {
462
                if (empty($value)) {
463
                    $value = '';
464
                } else {
465 6
                    $value = json_encode($value);
466
                }
467
            }
468 6
469
            /** @var Registration\Field $field */
470 6
            $field = $this->fieldRepository->findByUid((int)$fieldUid);
471 4
472 4
            $arguments['registration']['fieldValues'][$index] = [
473
                'value' => $value,
474 4
                'field' => strval($fieldUid),
475 4
                'valueType' => $field->getValueType()
476 2
            ];
477 2
478
            $index++;
479
        }
480 4
481 4
        // Remove temporary "fields" field
482 4
        $arguments = ArrayUtility::removeByPath($arguments, 'registration/fields');
483 4
        $this->request->setArguments($arguments);
484
    }
485 4
486 4
    /**
487 4
     * Set date format for field dateOfBirth
488 4
     *
489 4
     * @return void
490
     */
491 4
    public function initializeSaveRegistrationAction()
492
    {
493
        $this->arguments->getArgument('registration')
494 4
            ->getPropertyMappingConfiguration()->forProperty('dateOfBirth')
495 4
            ->setTypeConverterOption(
496 4
                DateTimeConverter::class,
497 4
                DateTimeConverter::CONFIGURATION_DATE_FORMAT,
498
                $this->settings['registration']['formatDateOfBirth']
499
            );
500 6
        $this->setRegistrationFieldValuesToArguments();
501 6
    }
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
    {
515
        $autoConfirmation = (bool)$this->settings['registration']['autoConfirmation'] || $event->getEnableAutoconfirm();
516
        $result = RegistrationResult::REGISTRATION_SUCCESSFUL;
517
        $success = $this->registrationService->checkRegistrationSuccess($event, $registration, $result);
518 6
519 6
        // Save registration if no errors
520 6
        if ($success) {
521
            $isWaitlistRegistration = $this->registrationService->isWaitlistRegistration(
522
                $event,
523
                $registration->getAmountOfRegistrations()
524
            );
525
            $linkValidity = (int)$this->settings['confirmation']['linkValidity'];
526
            if ($linkValidity === 0) {
527
                // Use 3600 seconds as default value if not set
528
                $linkValidity = 3600;
529
            }
530 4
            $confirmationUntil = new \DateTime();
531
            $confirmationUntil->add(new \DateInterval('PT' . $linkValidity . 'S'));
532
533 4
            $registration->setEvent($event);
534
            $registration->setPid($event->getPid());
535 4
            $registration->setConfirmationUntil($confirmationUntil);
536
            $registration->setLanguage($GLOBALS['TSFE']->config['config']['language']);
537 2
            $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 2
            $registration->setWaitlist($isWaitlistRegistration);
539 2
            $registration->_setProperty('_languageUid', $GLOBALS['TSFE']->sys_language_uid);
540 2
            $this->registrationRepository->add($registration);
541
542 2
            // Persist registration, so we have an UID
543 2
            $this->objectManager->get(PersistenceManager::class)->persistAll();
544 2
545 2
            // Add new registration (or waitlist registration) to event
546 2
            if ($isWaitlistRegistration) {
547
                $event->addRegistrationWaitlist($registration);
548 2
                $messageType = MessageType::REGISTRATION_WAITLIST_NEW;
549
            } else {
550
                $event->addRegistration($registration);
551 2
                $messageType = MessageType::REGISTRATION_NEW;
552 2
            }
553 2
            $this->eventRepository->update($event);
554
555
            $this->signalDispatch(__CLASS__, __FUNCTION__ . 'AfterRegistrationSaved', [$registration, $this]);
556 2
557
            // Send notifications to user and admin if confirmation link should be sent
558
            if (!$autoConfirmation) {
559 2
                $this->notificationService->sendUserMessage(
560 2
                    $event,
561 4
                    $registration,
562 4
                    $this->settings,
563 4
                    $messageType
564
                );
565
                $this->notificationService->sendAdminMessage(
566
                    $event,
567
                    $registration,
568
                    $this->settings,
569
                    $messageType
570 2
                );
571
            }
572 2
573 2
            // Create given amount of registrations if necessary
574 2
            if ($registration->getAmountOfRegistrations() > 1) {
575 2
                $this->registrationService->createDependingRegistrations($registration);
576 2
            }
577 2
578 2
            // Clear cache for configured pages
579 2
            $this->utilityService->clearCacheForConfiguredUids($this->settings);
580 2
        }
581 2
582 2
        if ($autoConfirmation && $success) {
583 2
            $this->redirect(
584 2
                'confirmRegistration',
585 2
                null,
586 2
                null,
587 2
                [
588 2
                    'reguid' => $registration->getUid(),
589
                    'hmac' => $this->hashService->generateHmac('reg-' . $registration->getUid())
590
                ]
591
            );
592
        } else {
593
            $this->redirect(
594
                'saveRegistrationResult',
595
                null,
596
                null,
597
                [
598 12
                    'result' => $result,
599
                    'eventuid' => $event->getUid(),
600 12
                    'hmac' => $this->hashService->generateHmac('event-' . $event->getUid())
601 12
                ]
602 12
            );
603 12
        }
604
    }
605 12
606 10
    /**
607
     * Shows the result of the saveRegistrationAction
608 10
     *
609 2
     * @param int $result Result
610 2
     * @param int $eventuid
611
     * @param string $hmac
612 10
     *
613 2
     * @return void
614 2
     */
615 10
    public function saveRegistrationResultAction($result, $eventuid, $hmac)
616
    {
617 12
        $event = null;
618 2
619 2
        switch ($result) {
620
            case RegistrationResult::REGISTRATION_SUCCESSFUL:
621 12
                $messageKey = 'event.message.registrationsuccessful';
622 12
                $titleKey = 'registrationResult.title.successful';
623
                break;
624 12
            case RegistrationResult::REGISTRATION_SUCCESSFUL_WAITLIST:
625
                $messageKey = 'event.message.registrationwaitlistsuccessful';
626 12
                $titleKey = 'registrationWaitlistResult.title.successful';
627 12
                break;
628 12
            case RegistrationResult::REGISTRATION_FAILED_EVENT_EXPIRED:
629 12
                $messageKey = 'event.message.registrationfailedeventexpired';
630 12
                $titleKey = 'registrationResult.title.failed';
631 12
                break;
632
            case RegistrationResult::REGISTRATION_FAILED_MAX_PARTICIPANTS:
633
                $messageKey = 'event.message.registrationfailedmaxparticipants';
634
                $titleKey = 'registrationResult.title.failed';
635
                break;
636
            case RegistrationResult::REGISTRATION_NOT_ENABLED:
637
                $messageKey = 'event.message.registrationfailednotenabled';
638
                $titleKey = 'registrationResult.title.failed';
639 18
                break;
640
            case RegistrationResult::REGISTRATION_FAILED_DEADLINE_EXPIRED:
641 18
                $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