Completed
Push — master ( 2700b4...4ccb05 )
by Torben
04:03 queued 02:37
created

AdministrationController::initializeView()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 26
ccs 9
cts 9
cp 1
rs 8.8817
c 0
b 0
f 0
cc 6
nc 5
nop 1
crap 6
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\EventDemand;
12
use DERHANSEN\SfEventMgt\Domain\Model\Dto\SearchDemand;
13
use DERHANSEN\SfEventMgt\Domain\Model\Event;
14
use DERHANSEN\SfEventMgt\Service;
15
use DERHANSEN\SfEventMgt\Utility\MiscUtility;
16
use TYPO3\CMS\Backend\Template\Components\ButtonBar;
17
use TYPO3\CMS\Backend\Utility\BackendUtility;
18
use TYPO3\CMS\Backend\View\BackendTemplateView;
19
use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
20
use TYPO3\CMS\Core\Imaging\Icon;
21
use TYPO3\CMS\Core\Imaging\IconFactory;
22
use TYPO3\CMS\Core\Messaging\FlashMessage;
23
use TYPO3\CMS\Core\Utility\HttpUtility;
24
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
25
use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
26
use TYPO3\CMS\Extbase\Property\TypeConverter\DateTimeConverter;
27
use TYPO3\CMS\Lang\LanguageService;
28
29
/**
30
 * AdministrationController
31
 *
32
 * Several parts are heavily inspired by ext:news from Georg Ringer
33
 *
34
 * @author Torben Hansen <[email protected]>
35
 */
36
class AdministrationController extends AbstractController
37
{
38
    const LANG_FILE = 'LLL:EXT:sf_event_mgt/Resources/Private/Language/locallang_be.xlf:';
39
40
    /**
41
     * Backend Template Container
42
     *
43
     * @var string
44
     */
45
    protected $defaultViewObjectName = \TYPO3\CMS\Backend\View\BackendTemplateView::class;
46
47
    /**
48
     * CustomNotificationLogRepository
49
     *
50
     * @var \DERHANSEN\SfEventMgt\Domain\Repository\CustomNotificationLogRepository
51
     */
52
    protected $customNotificationLogRepository = null;
53
54
    /**
55
     * ExportService
56
     *
57
     * @var \DERHANSEN\SfEventMgt\Service\ExportService
58
     */
59
    protected $exportService = null;
60
61
    /**
62
     * SettingsService
63
     *
64
     * @var \DERHANSEN\SfEventMgt\Service\SettingsService
65
     */
66
    protected $settingsService = null;
67
68
    /**
69
     * Backend User Session Service
70
     *
71
     * @var \DERHANSEN\SfEventMgt\Service\BeUserSessionService
72
     */
73
    protected $beUserSessionService = null;
74
75
    /**
76
     * @var \DERHANSEN\SfEventMgt\Service\MaintenanceService
77
     */
78
    protected $maintenanceService = null;
79
80
    /**
81
     * The current page uid
82
     *
83
     * @var int
84
     */
85
    protected $pid = 0;
86
87
    /**
88
     * BackendTemplateContainer
89
     *
90
     * @var BackendTemplateView
91 2
     */
92
    protected $view;
93 2
94 2
    /**
95
     * @var IconFactory
96
     */
97
    protected $iconFactory = null;
98
99
    /**
100
     * DI for $customNotificationLogRepository
101 4
     *
102
     * @param \DERHANSEN\SfEventMgt\Domain\Repository\CustomNotificationLogRepository $customNotificationLogRepository
103 4
     */
104 2
    public function injectCustomNotificationLogRepository(
105 2
        \DERHANSEN\SfEventMgt\Domain\Repository\CustomNotificationLogRepository $customNotificationLogRepository
106 4
    ) {
107 4
        $this->customNotificationLogRepository = $customNotificationLogRepository;
108 4
    }
109 4
110 4
    /**
111 4
     * DI for $exportService
112 4
     *
113 4
     * @param Service\ExportService $exportService
114 4
     */
115 4
    public function injectExportService(\DERHANSEN\SfEventMgt\Service\ExportService $exportService)
116 4
    {
117 4
        $this->exportService = $exportService;
118 4
    }
119 4
120 4
    /**
121
     * DI for $settingsService
122
     *
123
     * @param Service\SettingsService $settingsService
124
     */
125
    public function injectSettingsService(\DERHANSEN\SfEventMgt\Service\SettingsService $settingsService)
126
    {
127
        $this->settingsService = $settingsService;
128
    }
129
130 8
    /**
131
     * DI for $beUserSessionService
132
     *
133 8
     * @param Service\BeUserSessionService $beUserSessionService
134
     */
135 8
    public function injectBeUserSessionService(\DERHANSEN\SfEventMgt\Service\BeUserSessionService $beUserSessionService)
136 6
    {
137 6
        $this->beUserSessionService = $beUserSessionService;
138 8
    }
139
140 8
    /**
141 4
     * DI for $iconFactory
142 4
     *
143
     * @param IconFactory $iconFactory
144 8
     */
145 2
    public function injectIconFactory(IconFactory $iconFactory)
146 2
    {
147 2
        $this->iconFactory = $iconFactory;
148 2
    }
149
150 8
    /**
151 8
     * @param Service\MaintenanceService $maintenanceService
152 8
     */
153 8
    public function injectMaintenanceService(\DERHANSEN\SfEventMgt\Service\MaintenanceService $maintenanceService)
154
    {
155
        $this->maintenanceService = $maintenanceService;
156
    }
157
158
    /**
159
     * Set up the doc header properly here
160
     *
161
     * @param ViewInterface $view
162 2
     *
163
     * @return void
164 2
     */
165 2
    protected function initializeView(ViewInterface $view)
166
    {
167
        /** @var BackendTemplateView $view */
168
        parent::initializeView($view);
169
        if ($this->actionMethodName === 'listAction'
170
            || $this->actionMethodName === 'indexNotifyAction'
171
            || $this->actionMethodName === 'settingsErrorAction'
172
        ) {
173 2
            $this->registerDocHeaderButtons();
174
175 2
            $pageRenderer = $this->view->getModuleTemplate()->getPageRenderer();
176 2
            $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/DateTimePicker');
177 2
178
            $dateFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat'] ?
179
                ['MM-DD-YYYY', 'HH:mm MM-DD-YYYY'] :
180
                ['DD-MM-YYYY', 'HH:mm DD-MM-YYYY'];
181
            $pageRenderer->addInlineSetting('DateTimePicker', 'DateFormat', $dateFormat);
182
183
            $this->view->getModuleTemplate()->setFlashMessageQueue($this->controllerContext->getFlashMessageQueue());
184
            if ($view instanceof BackendTemplateView) {
185
                $view->getModuleTemplate()->getPageRenderer()->addCssFile(
186 2
                    'EXT:sf_event_mgt/Resources/Public/Css/administration.css'
187
                );
188 2
            }
189 2
        }
190 2
    }
191 2
192 2
    /**
193 2
     * Register docHeaderButtons
194 2
     *
195 2
     * @return void
196
     */
197
    protected function registerDocHeaderButtons()
198
    {
199
        $buttonBar = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar();
200
201
        $uriBuilder = $this->objectManager->get(UriBuilder::class);
202
        $uriBuilder->setRequest($this->request);
203
204
        if ($this->request->getControllerActionName() === 'list') {
205 2
            $buttons = [
206
                [
207 2
                    'label' => 'administration.newEvent',
208 2
                    'action' => 'newEvent',
209 2
                    'icon' => 'ext-sfeventmgt-event',
210 2
                    'group' => 1
211 2
                ],
212
                [
213 2
                    'label' => 'administration.newLocation',
214 2
                    'action' => 'newLocation',
215 2
                    'icon' => 'ext-sfeventmgt-location',
216
                    'group' => 1
217
                ],
218
                [
219
                    'label' => 'administration.newOrganisator',
220
                    'action' => 'newOrganisator',
221
                    'icon' => 'ext-sfeventmgt-organisator',
222
                    'group' => 1
223
                ],
224
                [
225
                    'label' => 'administration.newSpeaker',
226
                    'action' => 'newSpeaker',
227
                    'icon' => 'ext-sfeventmgt-speaker',
228
                    'group' => 1
229
                ],
230
                [
231
                    'label' => 'administration.handleExpiredRegistrations',
232
                    'action' => 'handleExpiredRegistrations',
233
                    'icon' => 'ext-sfeventmgt-action-handle-expired',
234
                    'group' => 2
235
                ]
236
            ];
237
            foreach ($buttons as $key => $tableConfiguration) {
238
                $title = $this->getLanguageService()->sL(self::LANG_FILE . $tableConfiguration['label']);
239
                $link = $uriBuilder->reset()->setRequest($this->request)
240
                    ->uriFor($tableConfiguration['action'], [], 'Administration');
241
                $icon = $this->iconFactory->getIcon($tableConfiguration['icon'], Icon::SIZE_SMALL);
242
                $viewButton = $buttonBar->makeLinkButton()
243
                    ->setHref($link)
244
                    ->setDataAttributes([
245
                        'toggle' => 'tooltip',
246
                        'placement' => 'bottom',
247
                        'title' => $title
248
                        ])
249
                    ->setTitle($title)
250
                    ->setIcon($icon);
251
                $buttonBar->addButton($viewButton, ButtonBar::BUTTON_POSITION_LEFT, $tableConfiguration['group']);
252
            }
253
        }
254
    }
255
256
    /**
257
     * Redirect to tceform creating a new record
258
     *
259
     * @param string $table table name
260
     * @return void
261
     */
262
    private function redirectToCreateNewRecord($table)
263
    {
264
        $pid = $this->pid;
265
        $tsConfig = BackendUtility::getPagesTSconfig(0);
266
        if ($pid === 0 && isset($tsConfig['defaultPid.'])
267
            && is_array($tsConfig['defaultPid.'])
268
            && isset($tsConfig['defaultPid.'][$table])
269
        ) {
270
            $pid = (int)$tsConfig['defaultPid.'][$table];
271
        }
272
273
        if (MiscUtility::isV9Lts()) {
274
            $returnUrl = 'index.php?route=/web/SfEventMgtTxSfeventmgtM1/';
275
        } else {
276
            $returnUrl = 'index.php?M=web_SfEventMgtTxSfeventmgtM1';
277
        }
278
279
        $returnUrl .= '&id=' . $this->pid . $this->getToken();
280
        $url = BackendUtility::getModuleUrl('record_edit', [
0 ignored issues
show
Deprecated Code introduced by
The method TYPO3\CMS\Backend\Utilit...Utility::getModuleUrl() has been deprecated with message: since TYPO3 v9, will be removed in TYPO3 v10.0. Use UriBuilder instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
281
            'edit[' . $table . '][' . $pid . ']' => 'new',
282
            'returnUrl' => $returnUrl
283
        ]);
284
285
        HttpUtility::redirect($url);
286
    }
287
288
    /**
289
     * Initialize action
290
     *
291
     * @return void
292
     */
293
    public function initializeAction()
294
    {
295
        $this->pid = (int)\TYPO3\CMS\Core\Utility\GeneralUtility::_GET('id');
296
    }
297
298
    /**
299
     * Set date format for fields startDate and endDate
300
     *
301
     * @return void
302
     */
303
    public function initializeListAction()
304
    {
305
        if ($this->settings === null || empty($this->settings)) {
306
            $this->redirect('settingsError');
307
        }
308
        $this->arguments->getArgument('searchDemand')
309
            ->getPropertyMappingConfiguration()->forProperty('startDate')
310
            ->setTypeConverterOption(
311
                DateTimeConverter::class,
312
                DateTimeConverter::CONFIGURATION_DATE_FORMAT,
313
                $this->settings['search']['dateFormat']
314
            );
315
        $this->arguments->getArgument('searchDemand')
316
            ->getPropertyMappingConfiguration()->forProperty('endDate')
317
            ->setTypeConverterOption(
318
                DateTimeConverter::class,
319
                DateTimeConverter::CONFIGURATION_DATE_FORMAT,
320
                $this->settings['search']['dateFormat']
321
            );
322
    }
323
324
    /**
325
     * List action for backend module
326
     *
327
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Dto\SearchDemand $searchDemand SearchDemand
328
     * @param array $overwriteDemand OverwriteDemand
329
     *
330
     * @return void
331
     */
332
    public function listAction(SearchDemand $searchDemand = null, array $overwriteDemand = [])
333
    {
334
        /** @var EventDemand $eventDemand */
335
        $eventDemand = $this->objectManager->get(EventDemand::class);
336
        $eventDemand = $this->overwriteEventDemandObject($eventDemand, $overwriteDemand);
337
        $eventDemand->setOrderFieldAllowed($this->settings['orderFieldAllowed']);
338
339
        if ($searchDemand !== null) {
340
            $searchDemand->setFields($this->settings['search']['fields']);
341
342
            $sessionData = [];
343
            $sessionData['searchDemand'] = $searchDemand;
344
            $sessionData['overwriteDemand'] = $overwriteDemand;
345
            $this->beUserSessionService->saveSessionData($sessionData);
346
        } else {
347
            // Try to restore search demand from Session
348
            $searchDemand = $this->beUserSessionService->getSessionDataByKey('searchDemand');
349
            $overwriteDemand = $this->beUserSessionService->getSessionDataByKey('overwriteDemand');
350
        }
351
352
        $eventDemand->setSearchDemand($searchDemand);
353
        $eventDemand->setStoragePage($this->pid);
354
355
        $this->view->assignMultiple([
356
            'pid' => $this->pid,
357
            'events' => $this->eventRepository->findDemanded($eventDemand),
358
            'searchDemand' => $searchDemand,
359
            'csvExportPossible' => $this->getBackendUser()->getDefaultUploadTemporaryFolder() !== null,
360
            'orderByFields' => $this->getOrderByFields(),
361
            'orderDirections' => $this->getOrderDirections(),
362
            'overwriteDemand' => $overwriteDemand,
363
        ]);
364
    }
365
366
    /**
367
     * Export registrations for a given event
368
     *
369
     * @param int $eventUid Event UID
370
     *
371
     * @return void
372
     */
373
    public function exportAction($eventUid)
374
    {
375
        $this->exportService->downloadRegistrationsCsv($eventUid, $this->settings['csvExport']);
376
        exit();
377
    }
378
379
    /**
380
     * Handles expired registrations
381
     *
382
     * @return void
383
     */
384
    public function handleExpiredRegistrationsAction()
385
    {
386
        $delete = (bool)$this->settings['registration']['deleteExpiredRegistrations'];
387
        $this->maintenanceService->handleExpiredRegistrations($delete);
388
389
        $this->addFlashMessage(
390
            $this->getLanguageService()->sL(self::LANG_FILE . 'administration.message-1.content'),
391
            $this->getLanguageService()->sL(self::LANG_FILE . 'administration.message-1.title'),
392
            FlashMessage::OK
393
        );
394
395
        $this->redirect('list');
396
    }
397
398
    /**
399
     * The index notify action
400
     *
401
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Event $event Event
402
     *
403
     * @return void
404
     */
405
    public function indexNotifyAction(Event $event)
406
    {
407
        $customNotifications = $this->settingsService->getCustomNotifications($this->settings);
408
        $logEntries = $this->customNotificationLogRepository->findByEvent($event);
0 ignored issues
show
Documentation Bug introduced by
The method findByEvent does not exist on object<DERHANSEN\SfEvent...ificationLogRepository>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
409
        $this->view->assignMultiple([
410
            'event' => $event,
411
            'customNotifications' => $customNotifications,
412
            'logEntries' => $logEntries,
413
        ]);
414
    }
415
416
    /**
417
     * Create new event action
418
     */
419
    public function newEventAction()
420
    {
421
        $this->redirectToCreateNewRecord('tx_sfeventmgt_domain_model_event');
422
    }
423
424
    /**
425
     * Create new location action
426
     */
427
    public function newLocationAction()
428
    {
429
        $this->redirectToCreateNewRecord('tx_sfeventmgt_domain_model_location');
430
    }
431
432
    /**
433
     * Create new organisator action
434
     */
435
    public function newOrganisatorAction()
436
    {
437
        $this->redirectToCreateNewRecord('tx_sfeventmgt_domain_model_organisator');
438
    }
439
440
    /**
441
     * Create new speaker action
442
     */
443
    public function newSpeakerAction()
444
    {
445
        $this->redirectToCreateNewRecord('tx_sfeventmgt_domain_model_speaker');
446
    }
447
448
    /**
449
     * Notify action
450
     *
451
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Event $event Event
452
     * @param string $customNotification CustomNotification
453
     *
454
     * @return void
455
     */
456
    public function notifyAction(Event $event, $customNotification)
457
    {
458
        $customNotifications = $this->settingsService->getCustomNotifications($this->settings);
459
        $result = $this->notificationService->sendCustomNotification($event, $customNotification, $this->settings);
460
        $this->notificationService->createCustomNotificationLogentry(
461
            $event,
462
            $customNotifications[$customNotification],
463
            $result
464
        );
465
        $this->addFlashMessage(
466
            $this->getLanguageService()->sL(self::LANG_FILE . 'administration.message-2.content'),
467
            $this->getLanguageService()->sL(self::LANG_FILE . 'administration.message-2.title'),
468
            FlashMessage::OK
469
        );
470
        $this->redirect('list');
471
    }
472
473
    /**
474
     * Shows the settings error view
475
     *
476
     * @return void
477
     */
478
    public function settingsErrorAction()
479
    {
480
    }
481
482
    /**
483
     * Suppress default validation messages
484
     *
485
     * @return bool
486
     */
487
    protected function getErrorFlashMessage()
488
    {
489
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type of the parent method TYPO3\CMS\Extbase\Mvc\Co...r::getErrorFlashMessage of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
490
    }
491
492
    /**
493
     * Get a CSRF token
494
     *
495
     * @param bool $tokenOnly Set it to TRUE to get only the token, otherwise including the &moduleToken= as prefix
496
     * @return string
497
     */
498
    protected function getToken(bool $tokenOnly = false): string
499
    {
500
        if (MiscUtility::isV9Lts()) {
501
            $tokenParameterName = 'token';
502
            $token = FormProtectionFactory::get('backend')->generateToken('route', 'web_SfEventMgtTxSfeventmgtM1');
503
        } else {
504
            $tokenParameterName = 'moduleToken';
505
            $token = FormProtectionFactory::get()->generateToken('moduleCall', 'web_SfEventMgtTxSfeventmgtM1');
506
        }
507
508
        if ($tokenOnly) {
509
            return $token;
510
        }
511
512
        return '&' . $tokenParameterName . '=' . $token;
513
    }
514
515
    /**
516
     * Returns the LanguageService
517
     *
518
     * @return LanguageService
519
     */
520
    protected function getLanguageService(): LanguageService
521
    {
522
        return $GLOBALS['LANG'];
523
    }
524
525
    /**
526
     * Returns current backendUser object
527
     *
528
     * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
529
     */
530
    protected function getBackendUser()
531
    {
532
        return $GLOBALS['BE_USER'];
533
    }
534
535
    /**
536
     * Returns an array with possible order directions
537
     *
538
     * @return array
539
     */
540
    public function getOrderDirections()
541
    {
542
        return [
543
            'asc' => $this->getLanguageService()->sL(self::LANG_FILE . 'administration.sortOrder.asc'),
544
            'desc' => $this->getLanguageService()->sL(self::LANG_FILE . 'administration.sortOrder.desc')
545
        ];
546
    }
547
548
    /**
549
     * Returns an array with possible orderBy fields
550
     *
551
     * @return array
552
     */
553
    public function getOrderByFields()
554
    {
555
        return [
556
            'title' => $this->getLanguageService()->sL(self::LANG_FILE . 'administration.orderBy.title'),
557
            'startdate' => $this->getLanguageService()->sL(self::LANG_FILE . 'administration.orderBy.startdate'),
558
            'enddate' => $this->getLanguageService()->sL(self::LANG_FILE . 'administration.orderBy.enddate')
559
        ];
560
    }
561
}
562