Completed
Push — development ( 11da13...e9292e )
by Torben
03:28
created

AdministrationController::getErrorFlashMessage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 0
cts 0
cp 0
cc 1
nc 1
nop 0
crap 2
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 TYPO3\CMS\Backend\Template\Components\ButtonBar;
16
use TYPO3\CMS\Backend\Utility\BackendUtility;
17
use TYPO3\CMS\Backend\View\BackendTemplateView;
18
use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
19
use TYPO3\CMS\Core\Imaging\Icon;
20
use TYPO3\CMS\Core\Imaging\IconFactory;
21
use TYPO3\CMS\Core\Messaging\FlashMessage;
22
use TYPO3\CMS\Core\Utility\HttpUtility;
23
use TYPO3\CMS\Core\Utility\VersionNumberUtility;
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
     * The current page uid
77
     *
78
     * @var int
79
     */
80
    protected $pid = 0;
81
82
    /**
83
     * BackendTemplateContainer
84
     *
85
     * @var BackendTemplateView
86
     */
87
    protected $view;
88
89
    /**
90
     * @var IconFactory
91 1
     */
92
    protected $iconFactory = null;
93 1
94 1
    /**
95
     * DI for $customNotificationLogRepository
96
     *
97
     * @param \DERHANSEN\SfEventMgt\Domain\Repository\CustomNotificationLogRepository $customNotificationLogRepository
98
     */
99
    public function injectCustomNotificationLogRepository(
100
        \DERHANSEN\SfEventMgt\Domain\Repository\CustomNotificationLogRepository $customNotificationLogRepository
101 2
    ) {
102
        $this->customNotificationLogRepository = $customNotificationLogRepository;
103 2
    }
104 1
105 1
    /**
106 2
     * DI for $exportService
107 2
     *
108 2
     * @param Service\ExportService $exportService
109 2
     */
110 2
    public function injectExportService(\DERHANSEN\SfEventMgt\Service\ExportService $exportService)
111 2
    {
112 2
        $this->exportService = $exportService;
113 2
    }
114 2
115 2
    /**
116 2
     * DI for $settingsService
117 2
     *
118 2
     * @param Service\SettingsService $settingsService
119 2
     */
120 2
    public function injectSettingsService(\DERHANSEN\SfEventMgt\Service\SettingsService $settingsService)
121
    {
122
        $this->settingsService = $settingsService;
123
    }
124
125
    /**
126
     * DI for $beUserSessionService
127
     *
128
     * @param Service\BeUserSessionService $beUserSessionService
129
     */
130 4
    public function injectBeUserSessionService(\DERHANSEN\SfEventMgt\Service\BeUserSessionService $beUserSessionService)
131
    {
132
        $this->beUserSessionService = $beUserSessionService;
133 4
    }
134
135 4
    /**
136 3
     * DI for $iconFactory
137 3
     *
138 4
     * @param IconFactory $iconFactory
139
     */
140 4
    public function injectIconFactory(IconFactory $iconFactory)
141 2
    {
142 2
        $this->iconFactory = $iconFactory;
143
    }
144 4
145 1
    /**
146 1
     * Set up the doc header properly here
147 1
     *
148 1
     * @param ViewInterface $view
149
     *
150 4
     * @return void
151 4
     */
152 4
    protected function initializeView(ViewInterface $view)
153 4
    {
154
        /** @var BackendTemplateView $view */
155
        parent::initializeView($view);
156
        if ($this->actionMethodName === 'listAction'
157
            || $this->actionMethodName === 'indexNotifyAction'
158
            || $this->actionMethodName === 'settingsErrorAction'
159
        ) {
160
            $this->registerDocHeaderButtons();
161
162 1
            $pageRenderer = $this->view->getModuleTemplate()->getPageRenderer();
163
            $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/DateTimePicker');
164 1
165 1
            $dateFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat'] ?
166
                ['MM-DD-YYYY', 'HH:mm MM-DD-YYYY'] :
167
                ['DD-MM-YYYY', 'HH:mm DD-MM-YYYY'];
168
            $pageRenderer->addInlineSetting('DateTimePicker', 'DateFormat', $dateFormat);
169
170
            $this->view->getModuleTemplate()->setFlashMessageQueue($this->controllerContext->getFlashMessageQueue());
171
            if ($view instanceof BackendTemplateView) {
172
                $view->getModuleTemplate()->getPageRenderer()->addCssFile(
173 1
                    'EXT:sf_event_mgt/Resources/Public/Css/administration.css'
174
                );
175 1
            }
176 1
        }
177 1
    }
178
179
    /**
180
     * Register docHeaderButtons
181
     *
182
     * @return void
183
     */
184
    protected function registerDocHeaderButtons()
185
    {
186 1
        $buttonBar = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar();
187
188 1
        $uriBuilder = $this->objectManager->get(UriBuilder::class);
189 1
        $uriBuilder->setRequest($this->request);
190 1
191 1
        if ($this->request->getControllerActionName() === 'list') {
192 1
            $buttons = [
193 1
                [
194 1
                    'label' => 'administration.newEvent',
195 1
                    'action' => 'newEvent',
196
                    'icon' => 'ext-sfeventmgt-event',
197
                    'group' => 1
198
                ],
199
                [
200
                    'label' => 'administration.newLocation',
201
                    'action' => 'newLocation',
202
                    'icon' => 'ext-sfeventmgt-location',
203
                    'group' => 1
204
                ],
205 1
                [
206
                    'label' => 'administration.newOrganisator',
207 1
                    'action' => 'newOrganisator',
208 1
                    'icon' => 'ext-sfeventmgt-organisator',
209 1
                    'group' => 1
210 1
                ],
211 1
                [
212
                    'label' => 'administration.newSpeaker',
213 1
                    'action' => 'newSpeaker',
214 1
                    'icon' => 'ext-sfeventmgt-speaker',
215 1
                    'group' => 1
216
                ],
217
                [
218
                    'label' => 'administration.handleExpiredRegistrations',
219
                    'action' => 'handleExpiredRegistrations',
220
                    'icon' => 'ext-sfeventmgt-action-handle-expired',
221
                    'group' => 2
222
                ]
223
            ];
224
            foreach ($buttons as $key => $tableConfiguration) {
225
                $title = $this->getLanguageService()->sL(self::LANG_FILE . $tableConfiguration['label']);
226
                $link = $uriBuilder->reset()->setRequest($this->request)
227
                    ->uriFor($tableConfiguration['action'], [], 'Administration');
228
                $icon = $this->iconFactory->getIcon($tableConfiguration['icon'], Icon::SIZE_SMALL);
229
                $viewButton = $buttonBar->makeLinkButton()
230
                    ->setHref($link)
231
                    ->setDataAttributes([
232
                        'toggle' => 'tooltip',
233
                        'placement' => 'bottom',
234
                        'title' => $title
235
                        ])
236
                    ->setTitle($title)
237
                    ->setIcon($icon);
238
                $buttonBar->addButton($viewButton, ButtonBar::BUTTON_POSITION_LEFT, $tableConfiguration['group']);
239
            }
240
        }
241
    }
242
243
    /**
244
     * Redirect to tceform creating a new record
245
     *
246
     * @param string $table table name
247
     * @return void
248
     */
249
    private function redirectToCreateNewRecord($table)
250
    {
251
        $pid = $this->pid;
252
        $tsConfig = BackendUtility::getPagesTSconfig(0);
253
        if ($pid === 0 && isset($tsConfig['defaultPid.'])
254
            && is_array($tsConfig['defaultPid.'])
255
            && isset($tsConfig['defaultPid.'][$table])
256
        ) {
257
            $pid = (int)$tsConfig['defaultPid.'][$table];
258
        }
259
260
        if (self::isV9up()) {
261
            $returnUrl = 'index.php?route=/web/SfEventMgtTxSfeventmgtM1/';
262
        } else {
263
            $returnUrl = 'index.php?M=web_SfEventMgtTxSfeventmgtM1';
264
        }
265
266
        $returnUrl .= '&id=' . $this->pid . $this->getToken();
267
        $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...
268
            'edit[' . $table . '][' . $pid . ']' => 'new',
269
            'returnUrl' => $returnUrl
270
        ]);
271
272
        HttpUtility::redirect($url);
273
    }
274
275
    /**
276
     * Initialize action
277
     *
278
     * @return void
279
     */
280
    public function initializeAction()
281
    {
282
        $this->pid = (int)\TYPO3\CMS\Core\Utility\GeneralUtility::_GET('id');
283
    }
284
285
    /**
286
     * Set date format for fields startDate and endDate
287
     *
288
     * @return void
289
     */
290
    public function initializeListAction()
291
    {
292
        if ($this->settings === null || empty($this->settings)) {
293
            $this->redirect('settingsError');
294
        }
295
        $this->arguments->getArgument('searchDemand')
296
            ->getPropertyMappingConfiguration()->forProperty('startDate')
297
            ->setTypeConverterOption(
298
                DateTimeConverter::class,
299
                DateTimeConverter::CONFIGURATION_DATE_FORMAT,
300
                $this->settings['search']['dateFormat']
301
            );
302
        $this->arguments->getArgument('searchDemand')
303
            ->getPropertyMappingConfiguration()->forProperty('endDate')
304
            ->setTypeConverterOption(
305
                DateTimeConverter::class,
306
                DateTimeConverter::CONFIGURATION_DATE_FORMAT,
307
                $this->settings['search']['dateFormat']
308
            );
309
    }
310
311
    /**
312
     * List action for backend module
313
     *
314
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Dto\SearchDemand $searchDemand SearchDemand
315
     * @param array $overwriteDemand OverwriteDemand
316
     *
317
     * @return void
318
     */
319
    public function listAction(SearchDemand $searchDemand = null, array $overwriteDemand = [])
320
    {
321
        /** @var EventDemand $eventDemand */
322
        $eventDemand = $this->objectManager->get(EventDemand::class);
323
        $eventDemand = $this->overwriteEventDemandObject($eventDemand, $overwriteDemand);
324
        $eventDemand->setOrderFieldAllowed($this->settings['orderFieldAllowed']);
325
326
        if ($searchDemand !== null) {
327
            $searchDemand->setFields($this->settings['search']['fields']);
328
329
            $sessionData = [];
330
            $sessionData['searchDemand'] = $searchDemand;
331
            $sessionData['overwriteDemand'] = $overwriteDemand;
332
            $this->beUserSessionService->saveSessionData($sessionData);
333
        } else {
334
            // Try to restore search demand from Session
335
            $searchDemand = $this->beUserSessionService->getSessionDataByKey('searchDemand');
336
            $overwriteDemand = $this->beUserSessionService->getSessionDataByKey('overwriteDemand');
337
        }
338
339
        $eventDemand->setSearchDemand($searchDemand);
340
        $eventDemand->setStoragePage($this->pid);
341
342
        $this->view->assignMultiple([
343
            'pid' => $this->pid,
344
            'events' => $this->eventRepository->findDemanded($eventDemand),
345
            'searchDemand' => $searchDemand,
346
            'csvExportPossible' => $this->getBackendUser()->getDefaultUploadTemporaryFolder() !== null,
347
            'orderByFields' => $this->getOrderByFields(),
348
            'orderDirections' => $this->getOrderDirections(),
349
            'overwriteDemand' => $overwriteDemand,
350
        ]);
351
    }
352
353
    /**
354
     * Export registrations for a given event
355
     *
356
     * @param int $eventUid Event UID
357
     *
358
     * @return void
359
     */
360
    public function exportAction($eventUid)
361
    {
362
        $this->exportService->downloadRegistrationsCsv($eventUid, $this->settings['csvExport']);
363
        exit();
364
    }
365
366
    /**
367
     * Calls the handleExpiredRegistrations Service
368
     *
369
     * @return void
370
     */
371
    public function handleExpiredRegistrationsAction()
372
    {
373
        $this->registrationService->handleExpiredRegistrations(
374
            $this->settings['registration']['deleteExpiredRegistrations']
375
        );
376
377
        $this->addFlashMessage(
378
            $this->getLanguageService()->sL(self::LANG_FILE . 'administration.message-1.content'),
379
            $this->getLanguageService()->sL(self::LANG_FILE . 'administration.message-1.title'),
380
            FlashMessage::OK
381
        );
382
383
        $this->redirect('list');
384
    }
385
386
    /**
387
     * The index notify action
388
     *
389
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Event $event Event
390
     *
391
     * @return void
392
     */
393
    public function indexNotifyAction(Event $event)
394
    {
395
        $customNotifications = $this->settingsService->getCustomNotifications($this->settings);
396
        $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...
397
        $this->view->assignMultiple([
398
            'event' => $event,
399
            'customNotifications' => $customNotifications,
400
            'logEntries' => $logEntries,
401
        ]);
402
    }
403
404
    /**
405
     * Create new event action
406
     */
407
    public function newEventAction()
408
    {
409
        $this->redirectToCreateNewRecord('tx_sfeventmgt_domain_model_event');
410
    }
411
412
    /**
413
     * Create new location action
414
     */
415
    public function newLocationAction()
416
    {
417
        $this->redirectToCreateNewRecord('tx_sfeventmgt_domain_model_location');
418
    }
419
420
    /**
421
     * Create new organisator action
422
     */
423
    public function newOrganisatorAction()
424
    {
425
        $this->redirectToCreateNewRecord('tx_sfeventmgt_domain_model_organisator');
426
    }
427
428
    /**
429
     * Create new speaker action
430
     */
431
    public function newSpeakerAction()
432
    {
433
        $this->redirectToCreateNewRecord('tx_sfeventmgt_domain_model_speaker');
434
    }
435
436
    /**
437
     * Notify action
438
     *
439
     * @param \DERHANSEN\SfEventMgt\Domain\Model\Event $event Event
440
     * @param string $customNotification CustomNotification
441
     *
442
     * @return void
443
     */
444
    public function notifyAction(Event $event, $customNotification)
445
    {
446
        $customNotifications = $this->settingsService->getCustomNotifications($this->settings);
447
        $result = $this->notificationService->sendCustomNotification($event, $customNotification, $this->settings);
448
        $this->notificationService->createCustomNotificationLogentry(
449
            $event,
450
            $customNotifications[$customNotification],
451
            $result
452
        );
453
        $this->addFlashMessage(
454
            $this->getLanguageService()->sL(self::LANG_FILE . 'administration.message-2.content'),
455
            $this->getLanguageService()->sL(self::LANG_FILE . 'administration.message-2.title'),
456
            FlashMessage::OK
457
        );
458
        $this->redirect('list');
459
    }
460
461
    /**
462
     * Shows the settings error view
463
     *
464
     * @return void
465
     */
466
    public function settingsErrorAction()
467
    {
468
    }
469
470
    /**
471
     * Suppress default validation messages
472
     *
473
     * @return bool
474
     */
475
    protected function getErrorFlashMessage()
476
    {
477
        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...
478
    }
479
480
    /**
481
     * Get a CSRF token
482
     *
483
     * @param bool $tokenOnly Set it to TRUE to get only the token, otherwise including the &moduleToken= as prefix
484
     * @return string
485
     */
486
    protected function getToken(bool $tokenOnly = false): string
487
    {
488
        if (self::isV9up()) {
489
            $tokenParameterName = 'token';
490
            $token = FormProtectionFactory::get('backend')->generateToken('route', 'web_SfEventMgtTxSfeventmgtM1');
491
        } else {
492
            $tokenParameterName = 'moduleToken';
493
            $token = FormProtectionFactory::get()->generateToken('moduleCall', 'web_SfEventMgtTxSfeventmgtM1');
494
        }
495
496
        if ($tokenOnly) {
497
            return $token;
498
        }
499
500
        return '&' . $tokenParameterName . '=' . $token;
501
    }
502
503
    /**
504
     * Returns if the current TYPO3 version is v9 or greater
505
     *
506
     * @return bool
507
     */
508
    private function isV9up(): bool
509
    {
510
        return VersionNumberUtility::convertVersionNumberToInteger(TYPO3_version) >= 9000000;
511
    }
512
513
    /**
514
     * Returns the LanguageService
515
     *
516
     * @return LanguageService
517
     */
518
    protected function getLanguageService(): LanguageService
519
    {
520
        return $GLOBALS['LANG'];
521
    }
522
523
    /**
524
     * Returns current backendUser object
525
     *
526
     * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
527
     */
528
    protected function getBackendUser()
529
    {
530
        return $GLOBALS['BE_USER'];
531
    }
532
533
    /**
534
     * Returns an array with possible order directions
535
     *
536
     * @return array
537
     */
538
    private function getOrderDirections()
539
    {
540
        return [
541
            'asc' => $this->getLanguageService()->sL(self::LANG_FILE . 'administration.sortOrder.asc'),
542
            'desc' => $this->getLanguageService()->sL(self::LANG_FILE . 'administration.sortOrder.desc')
543
        ];
544
    }
545
546
    /**
547
     * Returns an array with possible orderBy fields
548
     *
549
     * @return array
550
     */
551
    private function getOrderByFields()
552
    {
553
        return [
554
            'title' => $this->getLanguageService()->sL(self::LANG_FILE . 'administration.orderBy.title'),
555
            'startdate' => $this->getLanguageService()->sL(self::LANG_FILE . 'administration.orderBy.startdate'),
556
            'enddate' => $this->getLanguageService()->sL(self::LANG_FILE . 'administration.orderBy.enddate')
557
        ];
558
    }
559
}
560