Completed
Push — development ( 403f43...c0460e )
by Torben
02:28
created

EventController::saveRegistrationAction()   C

Complexity

Conditions 9
Paths 68

Size

Total Lines 92

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 59
CRAP Score 9

Importance

Changes 0
Metric Value
dl 0
loc 92
ccs 59
cts 59
cp 1
rs 6.6189
c 0
b 0
f 0
cc 9
nc 68
nop 2
crap 9

How to fix   Long Method   

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
     * Initializes the current action
60
     */
61
    public function initializeAction()
62
    {
63
        $typoScriptFrontendController = $this->getTypoScriptFrontendController();
64
        if ($typoScriptFrontendController !== null) {
65
            static $cacheTagsSet = false;
66
67
            if (!$cacheTagsSet) {
68
                $typoScriptFrontendController->addCacheTags(['tx_sfeventmgt']);
69
                $cacheTagsSet = true;
70
            }
71
        }
72
    }
73
74
    /**
75
     * Creates an event demand object with the given settings
76
     *
77
     * @param array $settings The settings
78
     *
79
     * @return \DERHANSEN\SfEventMgt\Domain\Model\Dto\EventDemand
80
     */
81
    public function createEventDemandObjectFromSettings(array $settings)
82
    {
83
        /** @var \DERHANSEN\SfEventMgt\Domain\Model\Dto\EventDemand $demand */
84
        $demand = $this->objectManager->get(EventDemand::class);
85
        $demand->setDisplayMode($settings['displayMode']);
86
        $demand->setStoragePage(Page::extendPidListByChildren($settings['storagePage'], $settings['recursive']));
87
        $demand->setCategoryConjunction($settings['categoryConjunction']);
88
        $demand->setCategory($settings['category']);
89
        $demand->setIncludeSubcategories($settings['includeSubcategories']);
90
        $demand->setTopEventRestriction((int)$settings['topEventRestriction']);
91
        $demand->setOrderField($settings['orderField']);
92
        $demand->setOrderFieldAllowed($settings['orderFieldAllowed']);
93
        $demand->setOrderDirection($settings['orderDirection']);
94
        $demand->setQueryLimit($settings['queryLimit']);
95
        $demand->setLocation($settings['location']);
96
        $demand->setOrganisator($settings['organisator']);
97
98
        return $demand;
99
    }
100
101
    /**
102
     * Creates a foreign record demand object with the given settings
103
     *
104
     * @param array $settings The settings
105
     *
106
     * @return \DERHANSEN\SfEventMgt\Domain\Model\Dto\ForeignRecordDemand
107
     */
108
    public function createForeignRecordDemandObjectFromSettings(array $settings)
109
    {
110
        /** @var \DERHANSEN\SfEventMgt\Domain\Model\Dto\ForeignRecordDemand $demand */
111
        $demand = $this->objectManager->get(ForeignRecordDemand::class);
112
        $demand->setStoragePage(Page::extendPidListByChildren($settings['storagePage'], $settings['recursive']));
113
        $demand->setRestrictForeignRecordsToStoragePage((bool)$settings['restrictForeignRecordsToStoragePage']);
114
115
        return $demand;
116
    }
117
118
    /**
119
     * Creates a category demand object with the given settings
120
     *
121
     * @param array $settings The settings
122
     *
123
     * @return \DERHANSEN\SfEventMgt\Domain\Model\Dto\CategoryDemand
124
     */
125
    public function createCategoryDemandObjectFromSettings(array $settings)
126
    {
127
        /** @var \DERHANSEN\SfEventMgt\Domain\Model\Dto\CategoryDemand $demand */
128
        $demand = $this->objectManager->get(CategoryDemand::class);
129
        $demand->setStoragePage(Page::extendPidListByChildren($settings['storagePage'], $settings['recursive']));
130
        $demand->setRestrictToStoragePage((bool)$settings['restrictForeignRecordsToStoragePage']);
131
        $demand->setCategories($settings['categoryMenu']['categories']);
132
        $demand->setIncludeSubcategories($settings['categoryMenu']['includeSubcategories']);
133
134
        return $demand;
135
    }
136
137 1
    /**
138
     * Overwrites a given demand object by an propertyName =>  $propertyValue array
139
     *
140 1
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Dto\EventDemand $demand Demand
141 1
     * @param array $overwriteDemand OwerwriteDemand
142 1
     *
143 1
     * @return \DERHANSEN\SfEventMgt\Domain\Model\Dto\EventDemand
144 1
     */
145 1
    protected function overwriteEventDemandObject(EventDemand $demand, array $overwriteDemand)
146 1
    {
147 1
        foreach ($this->ignoredSettingsForOverwriteDemand as $property) {
148 1
            unset($overwriteDemand[$property]);
149 1
        }
150 1
151
        foreach ($overwriteDemand as $propertyName => $propertyValue) {
152
            if (in_array(strtolower($propertyName), $this->ignoredSettingsForOverwriteDemand, true)) {
153
                continue;
154
            }
155
            \TYPO3\CMS\Extbase\Reflection\ObjectAccess::setProperty($demand, $propertyName, $propertyValue);
156
        }
157
158
        return $demand;
159
    }
160
161
    /**
162
     * Hook into request processing and catch exceptions
163
     *
164
     * @param RequestInterface $request
165
     * @param ResponseInterface $response
166
     * @throws \Exception
167
     */
168
    public function processRequest(RequestInterface $request, ResponseInterface $response)
169
    {
170
        try {
171
            parent::processRequest($request, $response);
172
        } catch (\Exception $exception) {
173
            $this->handleKnownExceptionsElseThrowAgain($exception);
174
        }
175
    }
176 1
177
    /**
178
     * Handle known exceptions
179 1
     *
180 1
     * @param \Exception $exception
181 1
     * @throws \Exception
182 1
     */
183 1
    private function handleKnownExceptionsElseThrowAgain(\Exception $exception)
184 1
    {
185
        $previousException = $exception->getPrevious();
186
        $actions = ['detailAction', 'registrationAction', 'icalDownloadAction'];
187
        if (in_array($this->actionMethodName, $actions, true)
188
            && $previousException instanceof \TYPO3\CMS\Extbase\Property\Exception
189
        ) {
190
            $this->handleEventNotFoundError($this->settings);
191
        } else {
192
            throw $exception;
193
        }
194
    }
195 2
196
    /**
197 2
     * Initialize list action and set format
198 2
     *
199 2
     * @return void
200
     */
201 2
    public function initializeListAction()
202 2
    {
203 2
        if (isset($this->settings['list']['format'])) {
204 2
            $this->request->setFormat($this->settings['list']['format']);
205
        }
206
    }
207
208
    /**
209
     * List view
210
     *
211
     * @param array $overwriteDemand OverwriteDemand
212
     *
213
     * @return void
214
     */
215
    public function listAction(array $overwriteDemand = [])
216
    {
217
        $eventDemand = $this->createEventDemandObjectFromSettings($this->settings);
218
        $foreignRecordDemand = $this->createForeignRecordDemandObjectFromSettings($this->settings);
219
        $categoryDemand = $this->createCategoryDemandObjectFromSettings($this->settings);
220
        if ($this->isOverwriteDemand($overwriteDemand)) {
221
            $eventDemand = $this->overwriteEventDemandObject($eventDemand, $overwriteDemand);
222
        }
223
        $events = $this->eventRepository->findDemanded($eventDemand);
224
        $categories = $this->categoryRepository->findDemanded($categoryDemand);
225
        $locations = $this->locationRepository->findDemanded($foreignRecordDemand);
226 3
        $organisators = $this->organisatorRepository->findDemanded($foreignRecordDemand);
227
228 3
        $values = [
229 3
            'events' => $events,
230 3
            'categories' => $categories,
231 3
            'locations' => $locations,
232 1
            'organisators' => $organisators,
233 1
            'overwriteDemand' => $overwriteDemand,
234 3
            'eventDemand' => $eventDemand
235 3
        ];
236 3
237 3
        $this->signalDispatch(__CLASS__, __FUNCTION__ . 'BeforeRenderView', [&$values, $this]);
238 3
        $this->view->assignMultiple($values);
239 3
240 3
        $this->addPageCacheTagsByEventDemandObject($eventDemand);
241 3
    }
242
243
    /**
244
     * Calendar view
245
     *
246
     * @param array $overwriteDemand OverwriteDemand
247
     *
248
     * @return void
249
     */
250 1
    public function calendarAction(array $overwriteDemand = [])
251
    {
252 1
        $eventDemand = $this->createEventDemandObjectFromSettings($this->settings);
253 1
        $foreignRecordDemand = $this->createForeignRecordDemandObjectFromSettings($this->settings);
254
        $categoryDemand = $this->createCategoryDemandObjectFromSettings($this->settings);
255
        if ($this->isOverwriteDemand($overwriteDemand)) {
256
            $eventDemand = $this->overwriteEventDemandObject($eventDemand, $overwriteDemand);
257
        }
258
259
        // Set month/year to demand if not given
260
        if (!$eventDemand->getMonth()) {
261
            $currentMonth = date('n');
262 1
            $eventDemand->setMonth($currentMonth);
263
        } else {
264 1
            $currentMonth = $eventDemand->getMonth();
265 1
        }
266
        if (!$eventDemand->getYear()) {
267
            $currentYear = date('Y');
268
            $eventDemand->setYear($currentYear);
269
        } else {
270
            $currentYear = $eventDemand->getYear();
271
        }
272
273
        // Set demand from calendar date range instead of month / year
274
        if ((bool)$this->settings['calendar']['includeEventsForEveryDayOfAllCalendarWeeks']) {
275 1
            $eventDemand = $this->changeEventDemandToFullMonthDateRange($eventDemand);
276
        }
277 1
278
        $events = $this->eventRepository->findDemanded($eventDemand);
279
        $weeks = $this->calendarService->getCalendarArray(
280 1
            $currentMonth,
281
            $currentYear,
282 1
            strtotime('today midnight'),
283 1
            (int)$this->settings['calendar']['firstDayOfWeek'],
284 1
            $events
285
        );
286
287
        $values = [
288
            'weeks' => $weeks,
289
            'categories' => $this->categoryRepository->findDemanded($categoryDemand),
290
            'locations' => $this->locationRepository->findDemanded($foreignRecordDemand),
291 1
            'organisators' => $this->organisatorRepository->findDemanded($foreignRecordDemand),
292
            'eventDemand' => $eventDemand,
293 1
            'overwriteDemand' => $overwriteDemand,
294 1
            'currentPageId' => $GLOBALS['TSFE']->id,
295 1
            'firstDayOfMonth' => \DateTime::createFromFormat('d.m.Y', sprintf('1.%s.%s', $currentMonth, $currentYear)),
296 1
            'previousMonthConfig' => $this->calendarService->getDateConfig($currentMonth, $currentYear, '-1 month'),
297 1
            'nextMonthConfig' => $this->calendarService->getDateConfig($currentMonth, $currentYear, '+1 month')
298 1
        ];
299 1
300 1
        $this->signalDispatch(__CLASS__, __FUNCTION__ . 'BeforeRenderView', [&$values, $this]);
301
        $this->view->assignMultiple($values);
302
    }
303
304
    /**
305
     * Changes the given event demand object to select a date range for a calendar month including days of the previous
306
     * month for the first week and they days for the next month for the last week
307
     *
308
     * @param EventDemand $eventDemand
309
     * @return EventDemand
310
     */
311 11
    protected function changeEventDemandToFullMonthDateRange(EventDemand $eventDemand)
312
    {
313 11
        $calendarDateRange = $this->calendarService->getCalendarDateRange(
314 11
            $eventDemand->getMonth(),
315 11
            $eventDemand->getYear(),
316
            $this->settings['calendar']['firstDayOfWeek']
317
        );
318 11
319 4
        $eventDemand->setMonth(0);
320 4
        $eventDemand->setYear(0);
321 4
322 4
        $startDate = new \DateTime();
323 4
        $startDate->setTimestamp($calendarDateRange['firstDayOfCalendar']);
324 4
        $endDate = new \DateTime();
325
        $endDate->setTimestamp($calendarDateRange['lastDayOfCalendar']);
326 4
        $endDate->setTime(23, 59, 59);
327 4
328 4
        $searchDemand = new SearchDemand();
329 4
        $searchDemand->setStartDate($startDate);
330
        $searchDemand->setEndDate($endDate);
331 4
        $eventDemand->setSearchDemand($searchDemand);
332 4
333 4
        return $eventDemand;
334 4
    }
335 4
336 4
    /**
337 4
     * Detail view for an event
338 4
     *
339
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Event $event Event
340
     * @return mixed string|void
341 4
     */
342
    public function detailAction(Event $event = null)
343
    {
344 4
        $event = $this->evaluateSingleEventSetting($event);
345 1
        if (is_null($event) && isset($this->settings['event']['errorHandling'])) {
346 1
            return $this->handleEventNotFoundError($this->settings);
347 1
        }
348 3
        $values = ['event' => $event];
349 3
        $this->signalDispatch(__CLASS__, __FUNCTION__ . 'BeforeRenderView', [&$values, $this]);
350
        $this->view->assignMultiple($values);
351 4
        if ($event !== null) {
352
            $this->addCacheTagsByEventRecords([$event]);
353
        }
354 4
    }
355 3
356 3
    /**
357 3
     * Error handling if event is not found
358 3
     *
359
     * @param array $settings
360 3
     * @return string
361 3
     */
362 3
    protected function handleEventNotFoundError($settings)
363 3
    {
364 3
        if (empty($settings['event']['errorHandling'])) {
365
            return null;
366 3
        }
367 3
368
        $configuration = GeneralUtility::trimExplode(',', $settings['event']['errorHandling'], true);
369
370 4
        switch ($configuration[0]) {
371 1
            case 'redirectToListView':
372 1
                $listPid = (int)$settings['listPid'] > 0 ? (int)$settings['listPid'] : 1;
373
                $this->redirect('list', null, null, null, $listPid);
374
                break;
375 4
            case 'pageNotFoundHandler':
376 4
                $GLOBALS['TSFE']->pageNotFoundAndExit('Event not found.');
377
                break;
378 11
            case 'showStandaloneTemplate':
379 1
                if (isset($configuration[2])) {
380 1
                    $statusCode = constant(HttpUtility::class . '::HTTP_STATUS_' . $configuration[2]);
381 1
                    HttpUtility::setResponseCode($statusCode);
382 1
                }
383
                $standaloneTemplate = $this->objectManager->get(StandaloneView::class);
384 1
                $standaloneTemplate->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($configuration[1]));
385 1
386 1
                return $standaloneTemplate->render();
387 1
                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...
388 1
            default:
389 10
        }
390 10
    }
391 10
392 10
    /**
393 10
     * Initiates the iCalendar download for the given event
394 10
     *
395
     * @param Event $event The event
396 11
     *
397
     * @return string|false
398
     */
399
    public function icalDownloadAction(Event $event = null)
400
    {
401
        if (is_null($event) && isset($this->settings['event']['errorHandling'])) {
402
            return $this->handleEventNotFoundError($this->settings);
403
        }
404
        $this->icalendarService->downloadiCalendarFile($event);
0 ignored issues
show
Bug introduced by
It seems like $event defined by parameter $event on line 399 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...
405 9
406
        return false;
407
    }
408 9
409 1
    /**
410 1
     * Registration view for an event
411 1
     *
412 8
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Event $event Event
413
     *
414
     * @return mixed string|void
415
     */
416 8
    public function registrationAction(Event $event = null)
417 1
    {
418 1
        $event = $this->evaluateSingleEventSetting($event);
419 1
        if (is_null($event) && isset($this->settings['event']['errorHandling'])) {
420 7
            return $this->handleEventNotFoundError($this->settings);
421 1
        }
422 1
        if ($event->getRestrictPaymentMethods()) {
423 1
            $paymentMethods = $this->paymentService->getRestrictedPaymentMethods($event);
0 ignored issues
show
Documentation introduced by
$event is of type object|null, but the function expects a object<DERHANSEN\SfEventMgt\Domain\Model\Event>.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
424 6
        } else {
425 1
            $paymentMethods = $this->paymentService->getPaymentMethods();
426 1
        }
427 1
428 5
        $values = [
429 1
            'event' => $event,
430 1
            'paymentMethods' => $paymentMethods,
431 1
        ];
432 4
433 1
        $this->signalDispatch(__CLASS__, __FUNCTION__ . 'BeforeRenderView', [&$values, $this]);
434 1
        $this->view->assignMultiple($values);
435 1
    }
436 3
437 1
    /**
438 1
     * Processes incoming registrations fields and adds field values to arguments
439 1
     *
440 2
     * @return void
441 1
     */
442 1
    protected function setRegistrationFieldValuesToArguments()
443 1
    {
444 1
        $arguments = $this->request->getArguments();
445 1
        if (!isset($arguments['registration']['fields']) || !isset($arguments['event'])) {
446 1
            return;
447 1
        }
448
449 9
        $registrationMvcArgument = $this->arguments->getArgument('registration');
450 9
        $propertyMapping = $registrationMvcArgument->getPropertyMappingConfiguration();
451 9
        $propertyMapping->allowProperties('fieldValues');
452
        $propertyMapping->allowCreationForSubProperty('fieldValues');
453
        $propertyMapping->allowModificationForSubProperty('fieldValues');
454
455
        // allow creation of new objects (for validation)
456
        $propertyMapping->setTypeConverterOptions(
457
            PersistentObjectConverter::class,
458
            [
459
                PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED => true,
460
                PersistentObjectConverter::CONFIGURATION_MODIFICATION_ALLOWED => true
461 3
            ]
462
        );
463
464 3
        // Set event to registration (required for validation)
465
        $event = $this->eventRepository->findByUid((int)$this->request->getArgument('event'));
466 3
        $propertyMapping->allowProperties('event');
467 2
        $propertyMapping->allowCreationForSubProperty('event');
468 2
        $propertyMapping->allowModificationForSubProperty('event');
469
        $arguments['registration']['event'] = (int)$this->request->getArgument('event');
470 2
471 2
        $index = 0;
472 1
        foreach ((array)$arguments['registration']['fields'] as $fieldUid => $value) {
473 1
            // Only accept registration fields of the current event
474
            if (!in_array((int)$fieldUid, $event->getRegistrationFieldsUids(), true)) {
475
                continue;
476 2
            }
477 2
478 2
            // allow subvalues in new property mapper
479 2
            $propertyMapping->forProperty('fieldValues')->allowProperties($index);
480
            $propertyMapping->forProperty('fieldValues.' . $index)->allowAllProperties();
481 2
            $propertyMapping->allowCreationForSubProperty('fieldValues.' . $index);
482 2
            $propertyMapping->allowModificationForSubProperty('fieldValues.' . $index);
483 2
484 2
            if (is_array($value)) {
485 2
                if (empty($value)) {
486
                    $value = '';
487 2
                } else {
488
                    $value = json_encode($value);
489
                }
490 2
            }
491 2
492 2
            /** @var Registration\Field $field */
493 2
            $field = $this->fieldRepository->findByUid((int)$fieldUid);
494
495
            $arguments['registration']['fieldValues'][$index] = [
496 3
                'pid' => $field->getPid(),
497 3
                'value' => $value,
498
                'field' => strval($fieldUid),
499
                'valueType' => $field->getValueType()
500
            ];
501
502
            $index++;
503
        }
504
505
        // Remove temporary "fields" field
506
        $arguments = ArrayUtility::removeByPath($arguments, 'registration/fields');
507
        $this->request->setArguments($arguments);
508
    }
509
510
    /**
511
     * Set date format for field dateOfBirth
512
     *
513
     * @return void
514 3
     */
515 3
    public function initializeSaveRegistrationAction()
516 3
    {
517
        $this->arguments->getArgument('registration')
518
            ->getPropertyMappingConfiguration()->forProperty('dateOfBirth')
519
            ->setTypeConverterOption(
520
                DateTimeConverter::class,
521
                DateTimeConverter::CONFIGURATION_DATE_FORMAT,
522
                $this->settings['registration']['formatDateOfBirth']
523
            );
524
        $this->setRegistrationFieldValuesToArguments();
525
    }
526 2
527
    /**
528
     * Saves the registration
529 2
     *
530
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Registration $registration Registration
531 2
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Event $event Event
532
     * @validate $registration \DERHANSEN\SfEventMgt\Validation\Validator\RegistrationFieldValidator
533 1
     * @validate $registration \DERHANSEN\SfEventMgt\Validation\Validator\RegistrationValidator
534 1
     *
535 1
     * @return void
536 1
     */
537
    public function saveRegistrationAction(Registration $registration, Event $event)
538 1
    {
539 1
        $autoConfirmation = (bool)$this->settings['registration']['autoConfirmation'] || $event->getEnableAutoconfirm();
540 1
        $result = RegistrationResult::REGISTRATION_SUCCESSFUL;
541 1
        $success = $this->registrationService->checkRegistrationSuccess($event, $registration, $result);
542 1
543
        // Save registration if no errors
544 1
        if ($success) {
545
            $isWaitlistRegistration = $this->registrationService->isWaitlistRegistration(
546
                $event,
547 1
                $registration->getAmountOfRegistrations()
548 1
            );
549 1
            $linkValidity = (int)$this->settings['confirmation']['linkValidity'];
550
            if ($linkValidity === 0) {
551
                // Use 3600 seconds as default value if not set
552 1
                $linkValidity = 3600;
553
            }
554
            $confirmationUntil = new \DateTime();
555 1
            $confirmationUntil->add(new \DateInterval('PT' . $linkValidity . 'S'));
556 1
557 2
            $registration->setEvent($event);
558 2
            $registration->setPid($event->getPid());
559 2
            $registration->setConfirmationUntil($confirmationUntil);
560
            $registration->setLanguage($GLOBALS['TSFE']->config['config']['language']);
561
            $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...
562
            $registration->setWaitlist($isWaitlistRegistration);
563
            $registration->_setProperty('_languageUid', $GLOBALS['TSFE']->sys_language_uid);
564
            $this->registrationRepository->add($registration);
565
566 1
            // Persist registration, so we have an UID
567
            $this->objectManager->get(PersistenceManager::class)->persistAll();
568 1
569 1
            // Add new registration (or waitlist registration) to event
570 1
            if ($isWaitlistRegistration) {
571 1
                $event->addRegistrationWaitlist($registration);
572 1
                $messageType = MessageType::REGISTRATION_WAITLIST_NEW;
573 1
            } else {
574 1
                $event->addRegistration($registration);
575 1
                $messageType = MessageType::REGISTRATION_NEW;
576 1
            }
577 1
            $this->eventRepository->update($event);
578 1
579 1
            $this->signalDispatch(__CLASS__, __FUNCTION__ . 'AfterRegistrationSaved', [$registration, $this]);
580 1
581 1
            // Send notifications to user and admin if confirmation link should be sent
582 1
            if (!$autoConfirmation) {
583 1
                $this->notificationService->sendUserMessage(
584 1
                    $event,
585
                    $registration,
586
                    $this->settings,
587
                    $messageType
588
                );
589
                $this->notificationService->sendAdminMessage(
590
                    $event,
591
                    $registration,
592
                    $this->settings,
593
                    $messageType
594 6
                );
595
            }
596 6
597 6
            // Create given amount of registrations if necessary
598 6
            if ($registration->getAmountOfRegistrations() > 1) {
599 6
                $this->registrationService->createDependingRegistrations($registration);
600
            }
601 6
602 5
            // Clear cache for configured pages
603
            $this->utilityService->clearCacheForConfiguredUids($this->settings);
604 5
        }
605 1
606 1
        if ($autoConfirmation && $success) {
607
            $this->redirect(
608 5
                'confirmRegistration',
609 1
                null,
610 1
                null,
611 5
                [
612
                    'reguid' => $registration->getUid(),
613 6
                    'hmac' => $this->hashService->generateHmac('reg-' . $registration->getUid())
614 1
                ]
615 1
            );
616
        } else {
617 6
            $this->redirect(
618 6
                'saveRegistrationResult',
619
                null,
620 6
                null,
621
                [
622 6
                    'result' => $result,
623 6
                    'eventuid' => $event->getUid(),
624 6
                    'hmac' => $this->hashService->generateHmac('event-' . $event->getUid())
625 6
                ]
626 6
            );
627 6
        }
628
    }
629
630
    /**
631
     * Shows the result of the saveRegistrationAction
632
     *
633
     * @param int $result Result
634
     * @param int $eventuid
635 9
     * @param string $hmac
636
     *
637 9
     * @return void
638
     */
639
    public function saveRegistrationResultAction($result, $eventuid, $hmac)
640
    {
641
        $event = null;
642
643
        switch ($result) {
644
            case RegistrationResult::REGISTRATION_SUCCESSFUL:
645
                $messageKey = 'event.message.registrationsuccessful';
646
                $titleKey = 'registrationResult.title.successful';
647
                break;
648
            case RegistrationResult::REGISTRATION_SUCCESSFUL_WAITLIST:
649
                $messageKey = 'event.message.registrationwaitlistsuccessful';
650
                $titleKey = 'registrationWaitlistResult.title.successful';
651
                break;
652
            case RegistrationResult::REGISTRATION_FAILED_EVENT_EXPIRED:
653
                $messageKey = 'event.message.registrationfailedeventexpired';
654
                $titleKey = 'registrationResult.title.failed';
655
                break;
656
            case RegistrationResult::REGISTRATION_FAILED_MAX_PARTICIPANTS:
657
                $messageKey = 'event.message.registrationfailedmaxparticipants';
658
                $titleKey = 'registrationResult.title.failed';
659
                break;
660
            case RegistrationResult::REGISTRATION_NOT_ENABLED:
661
                $messageKey = 'event.message.registrationfailednotenabled';
662
                $titleKey = 'registrationResult.title.failed';
663
                break;
664
            case RegistrationResult::REGISTRATION_FAILED_DEADLINE_EXPIRED:
665
                $messageKey = 'event.message.registrationfaileddeadlineexpired';
666
                $titleKey = 'registrationResult.title.failed';
667
                break;
668
            case RegistrationResult::REGISTRATION_FAILED_NOT_ENOUGH_FREE_PLACES:
669
                $messageKey = 'event.message.registrationfailednotenoughfreeplaces';
670
                $titleKey = 'registrationResult.title.failed';
671
                break;
672
            case RegistrationResult::REGISTRATION_FAILED_MAX_AMOUNT_REGISTRATIONS_EXCEEDED:
673
                $messageKey = 'event.message.registrationfailedmaxamountregistrationsexceeded';
674
                $titleKey = 'registrationResult.title.failed';
675
                break;
676
            case RegistrationResult::REGISTRATION_FAILED_EMAIL_NOT_UNIQUE:
677
                $messageKey = 'event.message.registrationfailedemailnotunique';
678
                $titleKey = 'registrationResult.title.failed';
679
                break;
680
            default:
681
                $messageKey = '';
682
                $titleKey = '';
683
        }
684
685
        if (!$this->hashService->validateHmac('event-' . $eventuid, $hmac)) {
686
            $messageKey = 'event.message.registrationsuccessfulwrongeventhmac';
687
            $titleKey = 'registrationResult.title.failed';
688
        } else {
689
            $event = $this->eventRepository->findByUid((int)$eventuid);
690
        }
691
692
        $this->view->assignMultiple([
693
            'messageKey' => $messageKey,
694
            'titleKey' => $titleKey,
695
            'event' => $event,
696
        ]);
697
    }
698
699
    /**
700
     * Confirms the registration if possible and sends e-mails to admin and user
701
     *
702
     * @param int $reguid UID of registration
703
     * @param string $hmac HMAC for parameters
704
     *
705
     * @return void
706
     */
707
    public function confirmRegistrationAction($reguid, $hmac)
708
    {
709
        $event = null;
710
711
        /* @var $registration Registration */
712
        list($failed, $registration, $messageKey, $titleKey) = $this->registrationService->checkConfirmRegistration(
713
            $reguid,
714
            $hmac
715
        );
716
717
        if ($failed === false) {
718
            $registration->setConfirmed(true);
719
            $event = $registration->getEvent();
720
            $this->registrationRepository->update($registration);
721
722
            $messageType = MessageType::REGISTRATION_CONFIRMED;
723
            if ($registration->getWaitlist()) {
724
                $messageType = MessageType::REGISTRATION_WAITLIST_CONFIRMED;
725
            }
726
727
            // Send notifications to user and admin
728
            $this->notificationService->sendUserMessage(
729
                $registration->getEvent(),
730
                $registration,
731
                $this->settings,
732
                $messageType
733
            );
734
            $this->notificationService->sendAdminMessage(
735
                $registration->getEvent(),
736
                $registration,
737
                $this->settings,
738
                $messageType
739
            );
740
741
            // Confirm registrations depending on main registration if necessary
742
            if ($registration->getAmountOfRegistrations() > 1) {
743
                $this->registrationService->confirmDependingRegistrations($registration);
744
            }
745
        }
746
747
        // Redirect to payment provider if payment/redirect is enabled
748
        $paymentPid = (int)$this->settings['paymentPid'];
749
        if (!$failed && $paymentPid > 0 && $this->registrationService->redirectPaymentEnabled($registration)) {
750
            $this->uriBuilder->reset()
751
                ->setTargetPageUid($paymentPid)
752
                ->setUseCacheHash(false);
753
            $uri = $this->uriBuilder->uriFor(
754
                'redirect',
755
                [
756
                    'registration' => $registration,
757
                    'hmac' => $this->hashService->generateHmac('redirectAction-' . $registration->getUid())
758
                ],
759
                'Payment',
760
                'sfeventmgt',
761
                'Pipayment'
762
            );
763
            $this->redirectToUri($uri);
764
        }
765
766
        $values = [
767
            'messageKey' => $messageKey,
768
            'titleKey' => $titleKey,
769
            'event' => $event,
770
        ];
771
772
        $this->signalDispatch(__CLASS__, __FUNCTION__ . 'BeforeRenderView', [&$values, $this]);
773
        $this->view->assignMultiple($values);
774
    }
775
776
    /**
777
     * Cancels the registration if possible and sends e-mails to admin and user
778
     *
779
     * @param int $reguid UID of registration
780
     * @param string $hmac HMAC for parameters
781
     *
782
     * @return void
783
     */
784
    public function cancelRegistrationAction($reguid, $hmac)
785
    {
786
        $event = null;
787
788
        /* @var $registration Registration */
789
        list($failed, $registration, $messageKey, $titleKey) = $this->registrationService->checkCancelRegistration($reguid, $hmac);
790
791
        if ($failed === false) {
792
            $event = $registration->getEvent();
793
794
            // Send notifications (must run before cancelling the registration)
795
            $this->notificationService->sendUserMessage(
796
                $registration->getEvent(),
797
                $registration,
798
                $this->settings,
799
                MessageType::REGISTRATION_CANCELLED
800
            );
801
            $this->notificationService->sendAdminMessage(
802
                $registration->getEvent(),
803
                $registration,
804
                $this->settings,
805
                MessageType::REGISTRATION_CANCELLED
806
            );
807
808
            // First cancel depending registrations
809
            if ($registration->getAmountOfRegistrations() > 1) {
810
                $this->registrationService->cancelDependingRegistrations($registration);
811
            }
812
813
            // Finally cancel registration
814
            $this->registrationRepository->remove($registration);
815
816
            // Clear cache for configured pages
817
            $this->utilityService->clearCacheForConfiguredUids($this->settings);
818
        }
819
820
        $values = [
821
            'messageKey' => $messageKey,
822
            'titleKey' => $titleKey,
823
            'event' => $event,
824
        ];
825
826
        $this->signalDispatch(__CLASS__, __FUNCTION__ . 'BeforeRenderView', [&$values, $this]);
827
        $this->view->assignMultiple($values);
828
    }
829
830
    /**
831
     * Set date format for field startDate and endDate
832
     *
833
     * @return void
834
     */
835
    public function initializeSearchAction()
836
    {
837
        if ($this->settings !== null && $this->settings['search']['dateFormat']) {
838
            $this->arguments->getArgument('searchDemand')
839
                ->getPropertyMappingConfiguration()->forProperty('startDate')
840
                ->setTypeConverterOption(
841
                    DateTimeConverter::class,
842
                    DateTimeConverter::CONFIGURATION_DATE_FORMAT,
843
                    $this->settings['search']['dateFormat']
844
                );
845
            $this->arguments->getArgument('searchDemand')
846
                ->getPropertyMappingConfiguration()->forProperty('endDate')
847
                ->setTypeConverterOption(
848
                    DateTimeConverter::class,
849
                    DateTimeConverter::CONFIGURATION_DATE_FORMAT,
850
                    $this->settings['search']['dateFormat']
851
                );
852
        }
853
        if ($this->arguments->hasArgument('searchDemand')) {
854
            $propertyMappingConfiguration = $this->arguments->getArgument('searchDemand')
855
                ->getPropertyMappingConfiguration();
856
            $propertyMappingConfiguration->allowAllProperties();
857
            $propertyMappingConfiguration->setTypeConverterOption(
858
                PersistentObjectConverter::class,
859
                PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED,
860
                true
861
            );
862
        }
863
    }
864
865
    /**
866
     * Search view
867
     *
868
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Dto\SearchDemand $searchDemand SearchDemand
869
     * @param array $overwriteDemand OverwriteDemand
870
     *
871
     * @return void
872
     */
873
    public function searchAction(SearchDemand $searchDemand = null, array $overwriteDemand = [])
874
    {
875
        $eventDemand = $this->createEventDemandObjectFromSettings($this->settings);
876
        $eventDemand->setSearchDemand($searchDemand);
0 ignored issues
show
Bug introduced by
It seems like $searchDemand defined by parameter $searchDemand on line 873 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...
877
        $foreignRecordDemand = $this->createForeignRecordDemandObjectFromSettings($this->settings);
878
        $categoryDemand = $this->createCategoryDemandObjectFromSettings($this->settings);
879
880
        if ($searchDemand !== null) {
881
            $searchDemand->setFields($this->settings['search']['fields']);
882
883
            if ($this->settings['search']['adjustTime'] && $searchDemand->getStartDate() !== null) {
884
                $searchDemand->getStartDate()->setTime(0, 0, 0);
885
            }
886
887
            if ($this->settings['search']['adjustTime'] && $searchDemand->getEndDate() !== null) {
888
                $searchDemand->getEndDate()->setTime(23, 59, 59);
889
            }
890
        }
891
892
        if ($this->isOverwriteDemand($overwriteDemand)) {
893
            $eventDemand = $this->overwriteEventDemandObject($eventDemand, $overwriteDemand);
894
        }
895
896
        $categories = $this->categoryRepository->findDemanded($categoryDemand);
897
        $locations = $this->locationRepository->findDemanded($foreignRecordDemand);
898
        $organisators = $this->organisatorRepository->findDemanded($foreignRecordDemand);
899
        $events = $this->eventRepository->findDemanded($eventDemand);
900
901
        $values = [
902
            'events' => $events,
903
            'categories' => $categories,
904
            'locations' => $locations,
905
            'organisators' => $organisators,
906
            'searchDemand' => $searchDemand,
907
            'overwriteDemand' => $overwriteDemand,
908
        ];
909
910
        $this->signalDispatch(__CLASS__, __FUNCTION__ . 'BeforeRenderView', [&$values, $this]);
911
        $this->view->assignMultiple($values);
912
    }
913
914
    /**
915
     * Returns if a demand object can be overwritten with the given overwriteDemand array
916
     *
917
     * @param array $overwriteDemand
918
     * @return bool
919
     */
920
    protected function isOverwriteDemand($overwriteDemand)
921
    {
922
        return $this->settings['disableOverrideDemand'] != 1 && $overwriteDemand !== [];
923
    }
924
925
    /**
926
     * If no event is given and the singleEvent setting is set, the configured single event is returned
927
     *
928
     * @param Event|null $event
929
     * @return Event|null
930
     */
931
    protected function evaluateSingleEventSetting($event)
932
    {
933
        if ($event === null && (int)$this->settings['singleEvent'] > 0) {
934
            $event = $this->eventRepository->findByUid((int)$this->settings['singleEvent']);
935
        }
936
        return $event;
937
    }
938
939
    /**
940
     * Adds cache tags to page cache by event records.
941
     *
942
     * Following cache tags will be added to tsfe:
943
     * "tx_sfeventmgt_uid_[event:uid]"
944
     *
945
     * @param array $eventRecords array with event records
946
     */
947
    public function addCacheTagsByEventRecords(array $eventRecords)
948
    {
949
        $cacheTags = [];
950
        foreach ($eventRecords as $event) {
951
            // cache tag for each news record
952
            $cacheTags[] = 'tx_sfeventmgt_uid_' . $event->getUid();
953
        }
954
        if (count($cacheTags) > 0) {
955
            $this->getTypoScriptFrontendController()->addCacheTags($cacheTags);
956
        }
957
    }
958
959
    /**
960
     * Adds page cache tags by used storagePages.
961
     * This adds tags with the scheme tx_sfeventmgt_pid_[event:pid]
962
     *
963
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Dto\EventDemand $demand
964
     */
965
    public function addPageCacheTagsByEventDemandObject(\DERHANSEN\SfEventMgt\Domain\Model\Dto\EventDemand $demand)
966
    {
967
        $cacheTags = [];
968
        if ($demand->getStoragePage()) {
969
            // Add cache tags for each storage page
970
            foreach (GeneralUtility::trimExplode(',', $demand->getStoragePage()) as $pageId) {
971
                $cacheTags[] = 'tx_sfeventmgt_pid_' . $pageId;
972
            }
973
        }
974
        if (count($cacheTags) > 0) {
975
            $this->getTypoScriptFrontendController()->addCacheTags($cacheTags);
976
        }
977
    }
978
}
979