Completed
Push — 4.x ( a36c9f...e4382f )
by Torben
02:26
created

getNotificationRecipients()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

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