Completed
Push — development ( d6c8c1...1ddb4f )
by Torben
11s
created

EventController::initializeSearchAction()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 29

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

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