Passed
Push — master ( af9933...6d2375 )
by Torben
04:41 queued 01:21
created

NotificationService   C

Complexity

Total Complexity 55

Size/Duplication

Total Lines 469
Duplicated Lines 0 %

Test Coverage

Coverage 94.27%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 244
dl 0
loc 469
ccs 148
cts 157
cp 0.9427
rs 6
c 2
b 0
f 0
wmc 55

15 Methods

Rating   Name   Duplication   Size   Complexity  
B getAdminMessageTemplateSubject() 0 30 7
B getUserMessageTemplateSubject() 0 51 11
A createCustomNotificationLogentry() 0 18 1
C sendAdminMessage() 0 71 12
A injectEventDispatcher() 0 3 1
A injectAttachmentService() 0 3 1
A sendCustomNotification() 0 33 4
A injectHashService() 0 3 1
A injectCustomNotificationLogRepository() 0 4 1
A cantSendCustomNotification() 0 5 2
A injectRegistrationRepository() 0 3 1
A injectEmailService() 0 3 1
A getNotificationBody() 0 24 4
B sendUserMessage() 0 105 7
A injectFluidStandaloneService() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like NotificationService often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use NotificationService, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Extension "sf_event_mgt" for TYPO3 CMS.
7
 *
8
 * For the full copyright and license information, please read the
9
 * LICENSE.txt file that was distributed with this source code.
10
 */
11
12
namespace DERHANSEN\SfEventMgt\Service;
13
14
use DERHANSEN\SfEventMgt\Domain\Model\Dto\CustomNotification;
15
use DERHANSEN\SfEventMgt\Domain\Model\Event;
16
use DERHANSEN\SfEventMgt\Domain\Model\Registration;
17
use DERHANSEN\SfEventMgt\Domain\Repository\CustomNotificationLogRepository;
18
use DERHANSEN\SfEventMgt\Domain\Repository\RegistrationRepository;
19
use DERHANSEN\SfEventMgt\Event\AfterAdminMessageSentEvent;
20
use DERHANSEN\SfEventMgt\Event\AfterUserMessageSentEvent;
21
use DERHANSEN\SfEventMgt\Event\ModifyCustomNotificationLogEvent;
22
use DERHANSEN\SfEventMgt\Event\ModifyUserMessageAttachmentsEvent;
23
use DERHANSEN\SfEventMgt\Event\ModifyUserMessageSenderEvent;
24
use DERHANSEN\SfEventMgt\Service\Notification\AttachmentService;
25
use DERHANSEN\SfEventMgt\Utility\MessageRecipient;
26
use DERHANSEN\SfEventMgt\Utility\MessageType;
27
use Psr\EventDispatcher\EventDispatcherInterface;
28
use Psr\Http\Message\ServerRequestInterface;
29
use TYPO3\CMS\Core\Http\ApplicationType;
30
use TYPO3\CMS\Core\Utility\GeneralUtility;
31
use TYPO3\CMS\Extbase\Security\Cryptography\HashService;
32
33
/**
34
 * NotificationService
35
 */
36
class NotificationService
37
{
38
    protected RegistrationRepository $registrationRepository;
39
    protected EmailService $emailService;
40
    protected HashService $hashService;
41
    protected FluidStandaloneService $fluidStandaloneService;
42
    protected CustomNotificationLogRepository $customNotificationLogRepository;
43
    protected AttachmentService $attachmentService;
44
    protected EventDispatcherInterface $eventDispatcher;
45
46
    public function injectAttachmentService(AttachmentService $attachmentService)
47
    {
48
        $this->attachmentService = $attachmentService;
49
    }
50
51
    public function injectCustomNotificationLogRepository(
52
        CustomNotificationLogRepository $customNotificationLogRepository
53
    ) {
54
        $this->customNotificationLogRepository = $customNotificationLogRepository;
55
    }
56
57
    public function injectEmailService(EmailService $emailService)
58
    {
59
        $this->emailService = $emailService;
60
    }
61
62
    public function injectFluidStandaloneService(FluidStandaloneService $fluidStandaloneService)
63
    {
64
        $this->fluidStandaloneService = $fluidStandaloneService;
65
    }
66
67
    public function injectHashService(HashService $hashService)
68
    {
69
        $this->hashService = $hashService;
70
    }
71
72
    public function injectRegistrationRepository(RegistrationRepository $registrationRepository)
73
    {
74
        $this->registrationRepository = $registrationRepository;
75
    }
76
77
    public function injectEventDispatcher(EventDispatcherInterface $eventDispatcher)
78
    {
79
        $this->eventDispatcher = $eventDispatcher;
80
    }
81
82
    /**
83
     * Sends a custom notification defined by the given customNotification key
84
     * to all confirmed users of the event
85
     *
86
     * @param Event $event
87
     * @param CustomNotification $customNotification
88
     * @param array $settings
89
     *
90
     * @return int Number of notifications sent
91
     */
92
    public function sendCustomNotification(
93
        Event $event,
94
        CustomNotification $customNotification,
95 8
        array $settings = []
96
    ): int {
97 8
        if ($this->cantSendCustomNotification($settings, $customNotification)) {
98 2
            return 0;
99
        }
100 6
        $count = 0;
101
102 6
        $customNotificationSettings = $settings['notification']['customNotifications'] ?? [];
103 6
        $constraints = $customNotificationSettings[$customNotification->getTemplate()]['constraints'] ?? [];
104 6
        $registrations = $this->registrationRepository->findNotificationRegistrations(
105
            $event,
106 6
            $customNotification,
107 2
            $constraints
108 2
        );
109 2
110 2
        foreach ($registrations as $registration) {
111 2
            /** @var Registration $registration */
112
            $result = $this->sendUserMessage(
113 2
                $event,
114 2
                $registration,
115 2
                $settings,
116 2
                MessageType::CUSTOM_NOTIFICATION,
117 2
                $customNotification
118 6
            );
119 6
            if ($result) {
120
                $count += 1;
121
            }
122
        }
123
124
        return $count;
125
    }
126
127
    /**
128
     * Returns true if conditions are not met to send a custom notification
129
     *
130
     * @param array $settings
131 8
     * @param CustomNotification $customNotification
132
     *
133 8
     * @return bool
134
     */
135
    protected function cantSendCustomNotification(
136
        array $settings,
137
        CustomNotification $customNotification
138
    ): bool {
139
        return $customNotification->getTemplate() === '' || empty($settings);
140
    }
141
142
    /**
143
     * Adds a logentry to the custom notification log
144
     *
145 2
     * @param Event $event
146
     * @param string $details
147 2
     * @param int $emailsSent
148 2
     */
149 2
    public function createCustomNotificationLogentry(Event $event, string $details, int $emailsSent): void
150 2
    {
151 2
        $notificationlogEntry = new \DERHANSEN\SfEventMgt\Domain\Model\CustomNotificationLog();
152 2
        $notificationlogEntry->setPid($event->getPid());
0 ignored issues
show
Bug introduced by
It seems like $event->getPid() can also be of type null; however, parameter $pid of TYPO3\CMS\Extbase\Domain...tDomainObject::setPid() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

152
        $notificationlogEntry->setPid(/** @scrutinizer ignore-type */ $event->getPid());
Loading history...
153 2
        $notificationlogEntry->setEvent($event);
154
        $notificationlogEntry->setDetails($details);
155
        $notificationlogEntry->setEmailsSent($emailsSent);
156
        $notificationlogEntry->setCruserId($GLOBALS['BE_USER']->user['uid'] ?? 0);
157
158
        $modifyCustomNotificationLogEntry = new ModifyCustomNotificationLogEvent(
159
            $notificationlogEntry,
160
            $event,
161
            $details
162
        );
163
        $this->eventDispatcher->dispatch($modifyCustomNotificationLogEntry);
164
        $notificationlogEntry = $modifyCustomNotificationLogEntry->getCustomNotificationLog();
165
166 34
        $this->customNotificationLogRepository->add($notificationlogEntry);
167
    }
168 34
169
    /**
170 34
     * Sends a message to the user based on the given type
171 4
     *
172
     * @param Event $event
173
     * @param Registration $registration
174 30
     * @param array $settings
175 20
     * @param int $type
176 20
     * @param CustomNotification|null $customNotification
177 20
     *
178 20
     * @return bool TRUE if successful, else FALSE
179 20
     */
180
    public function sendUserMessage(
181 20
        Event $event,
182 20
        Registration $registration,
183 20
        array $settings,
184 20
        int $type,
185 20
        ?CustomNotification $customNotification = null
186 20
    ): bool {
187 20
        list($template, $subject) = $this->getUserMessageTemplateSubject(
188
            $settings,
189 20
            $type,
190
            $customNotification
191 10
        );
192
193
        if (!is_array($settings) ||
0 ignored issues
show
introduced by
The condition is_array($settings) is always true.
Loading history...
194
            (substr($template, -5) != '.html') ||
195
            (bool)($settings['notification']['disabled'] ?? false)
196
        ) {
197
            return false;
198
        }
199
200
        $additionalBodyVariables = [
201
            'customNotification' => $customNotification,
202 34
        ];
203
204 34
        if (!$registration->isIgnoreNotifications()) {
205 34
            $body = $this->getNotificationBody($event, $registration, $template, $settings, $additionalBodyVariables);
206
            $subject = $this->fluidStandaloneService->parseStringFluid(
207 34
                $subject,
208 6
                [
209 6
                    'event' => $event,
210 6
                    'registration' => $registration,
211 28
                ]
212 6
            );
213 6
            $attachments = $this->attachmentService->getAttachments(
214 6
                $settings,
215 22
                $registration,
216 6
                $type,
217 6
                MessageRecipient::USER
218 6
            );
219 16
220
            // Get iCal attachment if configured
221
            $iCalAttachment = $this->attachmentService->getICalAttachment(
222
                $settings,
223 16
                $registration,
224 2
                $type,
225 2
                MessageRecipient::USER
226 2
            );
227 14
228 14
            if ($iCalAttachment !== '') {
229 14
                $attachments[] = $iCalAttachment;
230
            }
231 34
232
            $modifyUserMessageSenderEvent = new ModifyUserMessageSenderEvent(
233 34
                $settings['notification']['senderName'] ?? '',
234
                $settings['notification']['senderEmail'] ?? '',
235
                $settings['notification']['replyToEmail'] ?? '',
236
                $registration,
237
                $type,
238
                $this
239
            );
240
            $this->eventDispatcher->dispatch($modifyUserMessageSenderEvent);
241
            $senderName = $modifyUserMessageSenderEvent->getSenderName();
242
            $senderEmail = $modifyUserMessageSenderEvent->getSenderEmail();
243
            $replyToEmail = $modifyUserMessageSenderEvent->getReplyToEmail();
244
245
            $modifyUserAttachmentsEvent = new ModifyUserMessageAttachmentsEvent(
246 52
                $attachments,
247
                $registration,
248 52
                $type,
249
                $this
250
            );
251 52
            $this->eventDispatcher->dispatch($modifyUserAttachmentsEvent);
252 50
            $attachments = $modifyUserAttachmentsEvent->getAttachments();
253 52
254 12
            $result = $this->emailService->sendEmailMessage(
255
                $senderEmail,
256
                $registration->getEmail(),
257 40
                $subject,
258 40
                $body,
259 40
                $senderName,
260 40
                $attachments,
261 40
                $replyToEmail
262 40
            );
263
264 40
            $afterUserMessageSentEvent = new AfterUserMessageSentEvent(
265 40
                $registration,
266 30
                $body,
267 30
                $subject,
268 30
                $attachments,
269 30
                $senderName,
270 30
                $senderEmail,
271 30
                $replyToEmail,
272 30
                $this
273 30
            );
274
            $this->eventDispatcher->dispatch($afterUserMessageSentEvent);
275 30
276 30
            // Cleanup iCal attachment if available
277 30
            if ($iCalAttachment !== '') {
278 40
                GeneralUtility::unlink_tempfile($iCalAttachment);
279 10
            }
280 10
281 10
            return $result;
282 10
        }
283 10
284 10
        return false;
285
    }
286 10
287 10
    /**
288 40
     * Returns an array with template and subject for the user message
289
     *
290
     * @param array $settings
291
     * @param int $type Type
292
     * @param CustomNotification|null $customNotification
293
     * @return array
294
     */
295
    protected function getUserMessageTemplateSubject(
296
        array $settings,
297
        int $type,
298 52
        CustomNotification $customNotification = null
299
    ): array {
300 52
        if ($type === MessageType::CUSTOM_NOTIFICATION && $customNotification === null) {
301 52
            return ['', '',];
302
        }
303 52
304 10
        switch ($type) {
305 10
            case MessageType::REGISTRATION_NEW:
306 10
                $template = 'Notification/User/RegistrationNew.html';
307 42
                $subject = $settings['notification']['registrationNew']['userSubject'] ?? '';
308 10
                break;
309 10
            case MessageType::REGISTRATION_WAITLIST_NEW:
310 10
                $template = 'Notification/User/RegistrationWaitlistNew.html';
311 32
                $subject = $settings['notification']['registrationWaitlistNew']['userSubject'] ?? '';
312 10
                break;
313 10
            case MessageType::REGISTRATION_CONFIRMED:
314 10
                $template = 'Notification/User/RegistrationConfirmed.html';
315 22
                $subject = $settings['notification']['registrationConfirmed']['userSubject'] ?? '';
316
                break;
317
            case MessageType::REGISTRATION_WAITLIST_CONFIRMED:
318
                $template = 'Notification/User/RegistrationWaitlistConfirmed.html';
319 22
                $subject = $settings['notification']['registrationWaitlistConfirmed']['userSubject'] ?? '';
320 22
                break;
321 22
            case MessageType::REGISTRATION_CANCELLED:
322
                $template = 'Notification/User/RegistrationCancelled.html';
323 52
                $subject = $settings['notification']['registrationCancelled']['userSubject'] ?? '';
324
                break;
325 52
            case MessageType::REGISTRATION_WAITLIST_MOVE_UP:
326
                $template = 'Notification/User/RegistrationWaitlistMoveUp.html';
327
                $subject = $settings['notification']['registrationWaitlistMoveUp']['userSubject'] ?? '';
328
                break;
329
            case MessageType::CUSTOM_NOTIFICATION:
330
                $customNotificationSettings = $settings['notification']['customNotifications'] ?? '';
331
                $templateKey = $customNotification->getTemplate();
0 ignored issues
show
Bug introduced by
The method getTemplate() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

331
                /** @scrutinizer ignore-call */ 
332
                $templateKey = $customNotification->getTemplate();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
332
                $template = 'Notification/User/Custom/' . $customNotificationSettings[$templateKey]['template'] ?? '';
333
                $subject = $customNotificationSettings[$templateKey]['subject'] ?? '';
334
                if ($customNotification->getOverwriteSubject() !== '') {
335
                    $subject = $customNotification->getOverwriteSubject();
336
                }
337
                break;
338 60
            default:
339
                $template = '';
340
                $subject = '';
341 60
        }
342 60
343 60
        return [
344 60
            $template ?? '',
345
            $subject ?? '',
346 60
        ];
347
    }
348
349
    /**
350
     * Sends a message to the admin based on the given type
351
     *
352 60
     * @param Event $event Event
353 60
     * @param Registration $registration Registration
354 60
     * @param array $settings Settings
355 60
     * @param int $type Type
356 60
     *
357 60
     * @return bool TRUE if successful, else FALSE
358 60
     */
359 60
    public function sendAdminMessage(Event $event, Registration $registration, array $settings, int $type): bool
360 60
    {
361 60
        list($template, $subject) = $this->getAdminMessageTemplateSubject($settings, $type);
362 60
363 60
        if (!is_array($settings) ||
0 ignored issues
show
introduced by
The condition is_array($settings) is always true.
Loading history...
364
            ($event->getNotifyAdmin() === false && $event->getNotifyOrganisator() === false) ||
365
            (bool)($settings['notification']['disabled'] ?? false)
366
        ) {
367
            return false;
368
        }
369
370
        $allEmailsSent = true;
371
        $body = $this->getNotificationBody($event, $registration, $template, $settings);
372
        $subject = $this->fluidStandaloneService->parseStringFluid(
373
            $subject,
374
            [
375
                'event' => $event,
376
                'registration' => $registration,
377
            ]
378
        );
379
        $attachments = $this->attachmentService->getAttachments(
380
            $settings,
381
            $registration,
382
            $type,
383
            MessageRecipient::ADMIN
384
        );
385
386
        $senderName = $settings['notification']['senderName'] ?? '';
387
        $senderEmail = $settings['notification']['senderEmail'] ?? '';
388
        if ((bool)($settings['notification']['registrationDataAsSenderForAdminEmails'] ?? false)) {
389
            $senderName = $registration->getFullname();
390
            $senderEmail = $registration->getEmail();
391
        }
392
393
        if ($event->getNotifyAdmin()) {
394
            $adminEmailArr = GeneralUtility::trimExplode(',', $settings['notification']['adminEmail'] ?? '', true);
395
            foreach ($adminEmailArr as $adminEmail) {
396
                $allEmailsSent = $allEmailsSent && $this->emailService->sendEmailMessage(
397
                    $senderEmail,
398
                    $adminEmail,
399
                    $subject,
400
                    $body,
401
                    $senderName,
402
                    $attachments
403
                );
404
            }
405
        }
406
407
        if ($event->getNotifyOrganisator() && $event->getOrganisator()) {
408
            $allEmailsSent = $allEmailsSent && $this->emailService->sendEmailMessage(
409
                $senderEmail,
410
                $event->getOrganisator()->getEmail(),
411
                $subject,
412
                $body,
413
                $senderName,
414
                $attachments
415
            );
416
        }
417
418
        $afterAdminMessageSentEvent = new AfterAdminMessageSentEvent(
419
            $registration,
420
            $body,
421
            $subject,
422
            $attachments,
423
            $senderName,
424
            $senderEmail,
425
            $this
426
        );
427
        $this->eventDispatcher->dispatch($afterAdminMessageSentEvent);
428
429
        return $allEmailsSent;
430
    }
431
432
    /**
433
     * Returns an array with template and subject for the admin message
434
     *
435
     * @param array $settings
436
     * @param int $type Type
437
     * @return array
438
     */
439
    protected function getAdminMessageTemplateSubject(array $settings, int $type): array
440
    {
441
        $template = 'Notification/Admin/RegistrationNew.html';
442
        $subject = $settings['notification']['registrationNew']['adminSubject'] ?? '';
443
        switch ($type) {
444
            case MessageType::REGISTRATION_WAITLIST_NEW:
445
                $template = 'Notification/Admin/RegistrationWaitlistNew.html';
446
                $subject = $settings['notification']['registrationWaitlistNew']['adminSubject'] ?? '';
447
                break;
448
            case MessageType::REGISTRATION_CONFIRMED:
449
                $template = 'Notification/Admin/RegistrationConfirmed.html';
450
                $subject = $settings['notification']['registrationConfirmed']['adminSubject'] ?? '';
451
                break;
452
            case MessageType::REGISTRATION_WAITLIST_CONFIRMED:
453
                $template = 'Notification/Admin/RegistrationWaitlistConfirmed.html';
454
                $subject = $settings['notification']['registrationWaitlistConfirmed']['adminSubject'] ?? '';
455
                break;
456
            case MessageType::REGISTRATION_CANCELLED:
457
                $template = 'Notification/Admin/RegistrationCancelled.html';
458
                $subject = $settings['notification']['registrationCancelled']['adminSubject'] ?? '';
459
                break;
460
            case MessageType::REGISTRATION_WAITLIST_MOVE_UP:
461
                $template = 'Notification/Admin/RegistrationWaitlistMoveUp.html';
462
                $subject = $settings['notification']['registrationWaitlistMoveUp']['adminSubject'] ?? '';
463
                break;
464
            case MessageType::REGISTRATION_NEW:
465
            default:
466
        }
467
468
        return [$template, $subject];
469
    }
470
471
    /**
472
     * Returns the rendered HTML for the given template
473
     *
474
     * @param Event $event Event
475
     * @param Registration $registration Registration
476
     * @param string $template Template
477
     * @param array $settings Settings
478
     * @param array $additionalBodyVariables
479
     * @return string
480
     */
481
    protected function getNotificationBody(
482
        Event $event,
483
        Registration $registration,
484
        string $template,
485
        array $settings,
486
        array $additionalBodyVariables = []
487
    ): string {
488
        $isBackendRequest = ($GLOBALS['TYPO3_REQUEST'] ?? null) instanceof ServerRequestInterface
489
            && ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isBackend();
490
491
        if ($isBackendRequest && $registration->getLanguage() !== '') {
492
            // Temporary set Language of current BE user to given language
493
            $GLOBALS['BE_USER']->uc['lang'] = $registration->getLanguage();
494
        }
495
        $defaultVariables = [
496
            'event' => $event,
497
            'registration' => $registration,
498
            'settings' => $settings,
499
            'hmac' => $this->hashService->generateHmac('reg-' . $registration->getUid()),
500
            'reghmac' => $this->hashService->appendHmac((string)$registration->getUid()),
501
        ];
502
        $variables = array_merge($additionalBodyVariables, $defaultVariables);
503
504
        return $this->fluidStandaloneService->renderTemplate($template, $variables);
505
    }
506
}
507