Passed
Push — develop ( 6a4af3...23485b )
by Torben
07:44
created

NotificationService   C

Complexity

Total Complexity 53

Size/Duplication

Total Lines 426
Duplicated Lines 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
eloc 243
dl 0
loc 426
rs 6.96
c 5
b 0
f 0
wmc 53

15 Methods

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

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): void
47
    {
48
        $this->attachmentService = $attachmentService;
49
    }
50
51
    public function injectCustomNotificationLogRepository(
52
        CustomNotificationLogRepository $customNotificationLogRepository
53
    ): void {
54
        $this->customNotificationLogRepository = $customNotificationLogRepository;
55
    }
56
57
    public function injectEmailService(EmailService $emailService): void
58
    {
59
        $this->emailService = $emailService;
60
    }
61
62
    public function injectFluidStandaloneService(FluidStandaloneService $fluidStandaloneService): void
63
    {
64
        $this->fluidStandaloneService = $fluidStandaloneService;
65
    }
66
67
    public function injectHashService(HashService $hashService): void
68
    {
69
        $this->hashService = $hashService;
70
    }
71
72
    public function injectRegistrationRepository(RegistrationRepository $registrationRepository): void
73
    {
74
        $this->registrationRepository = $registrationRepository;
75
    }
76
77
    public function injectEventDispatcher(EventDispatcherInterface $eventDispatcher): void
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. Returns the number of notifications sent.
85
     */
86
    public function sendCustomNotification(
87
        Event $event,
88
        CustomNotification $customNotification,
89
        array $settings = []
90
    ): int {
91
        if ($this->cantSendCustomNotification($settings, $customNotification)) {
92
            return 0;
93
        }
94
        $count = 0;
95
96
        $customNotificationSettings = $settings['notification']['customNotifications'] ?? [];
97
        $constraints = $customNotificationSettings[$customNotification->getTemplate()]['constraints'] ?? [];
98
        $registrations = $this->registrationRepository->findNotificationRegistrations(
99
            $event,
100
            $customNotification,
101
            $constraints
102
        );
103
104
        foreach ($registrations as $registration) {
105
            /** @var Registration $registration */
106
            $result = $this->sendUserMessage(
107
                $event,
108
                $registration,
109
                $settings,
110
                MessageType::CUSTOM_NOTIFICATION,
111
                $customNotification
112
            );
113
            if ($result) {
114
                $count += 1;
115
            }
116
        }
117
118
        return $count;
119
    }
120
121
    /**
122
     * Returns true if conditions are not met to send a custom notification
123
     */
124
    protected function cantSendCustomNotification(
125
        array $settings,
126
        CustomNotification $customNotification
127
    ): bool {
128
        return $customNotification->getTemplate() === '' || empty($settings);
129
    }
130
131
    /**
132
     * Adds a logentry to the custom notification log
133
     */
134
    public function createCustomNotificationLogentry(
135
        Event $event,
136
        string $details,
137
        int $emailsSent,
138
        CustomNotification $customNotification
139
    ): void {
140
        $notificationlogEntry = new \DERHANSEN\SfEventMgt\Domain\Model\CustomNotificationLog();
141
        $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

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

308
                /** @scrutinizer ignore-call */ 
309
                $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...
309
                $template = 'Notification/User/Custom/' . $customNotificationSettings[$templateKey]['template'] ?? '';
310
                $subject = $customNotificationSettings[$templateKey]['subject'] ?? '';
311
                if ($customNotification->getOverwriteSubject() !== '') {
312
                    $subject = $customNotification->getOverwriteSubject();
313
                }
314
                break;
315
            default:
316
                $template = '';
317
                $subject = '';
318
        }
319
320
        return [
321
            $template,
322
            $subject,
323
        ];
324
    }
325
326
    /**
327
     * Sends a message to the admin based on the given type. Returns true, if the message was sent, otherwise false
328
     */
329
    public function sendAdminMessage(Event $event, Registration $registration, array $settings, int $type): bool
330
    {
331
        list($template, $subject) = $this->getAdminMessageTemplateSubject($settings, $type);
332
333
        if (($event->getNotifyAdmin() === false && $event->getNotifyOrganisator() === false) ||
334
            (bool)($settings['notification']['disabled'] ?? false)
335
        ) {
336
            return false;
337
        }
338
339
        $allEmailsSent = true;
340
        $body = $this->getNotificationBody($event, $registration, $template, $settings);
341
        $subject = $this->fluidStandaloneService->parseStringFluid(
342
            $subject,
343
            [
344
                'event' => $event,
345
                'registration' => $registration,
346
            ]
347
        );
348
        $attachments = $this->attachmentService->getAttachments(
349
            $settings,
350
            $registration,
351
            $type,
352
            MessageRecipient::ADMIN
353
        );
354
355
        $senderName = $settings['notification']['senderName'] ?? '';
356
        $senderEmail = $settings['notification']['senderEmail'] ?? '';
357
        if ((bool)($settings['notification']['registrationDataAsSenderForAdminEmails'] ?? false)) {
358
            $senderName = $registration->getFullname();
359
            $senderEmail = $registration->getEmail();
360
        }
361
362
        if ($event->getNotifyAdmin()) {
363
            $adminEmailArr = GeneralUtility::trimExplode(',', $settings['notification']['adminEmail'] ?? '', true);
364
            foreach ($adminEmailArr as $adminEmail) {
365
                $allEmailsSent = $allEmailsSent && $this->emailService->sendEmailMessage(
366
                    $senderEmail,
367
                    $adminEmail,
368
                    $subject,
369
                    $body,
370
                    $senderName,
371
                    $attachments
372
                );
373
            }
374
        }
375
376
        if ($event->getNotifyOrganisator() && $event->getOrganisator()) {
377
            $allEmailsSent = $allEmailsSent && $this->emailService->sendEmailMessage(
378
                $senderEmail,
379
                $event->getOrganisator()->getEmail(),
380
                $subject,
381
                $body,
382
                $senderName,
383
                $attachments
384
            );
385
        }
386
387
        $afterAdminMessageSentEvent = new AfterAdminMessageSentEvent(
388
            $registration,
389
            $body,
390
            $subject,
391
            $attachments,
392
            $senderName,
393
            $senderEmail,
394
            $type,
395
            $this
396
        );
397
        $this->eventDispatcher->dispatch($afterAdminMessageSentEvent);
398
399
        return $allEmailsSent;
400
    }
401
402
    /**
403
     * Returns an array with template and subject for the admin message
404
     */
405
    protected function getAdminMessageTemplateSubject(array $settings, int $type): array
406
    {
407
        $template = 'Notification/Admin/RegistrationNew.html';
408
        $subject = $settings['notification']['registrationNew']['adminSubject'] ?? '';
409
        switch ($type) {
410
            case MessageType::REGISTRATION_WAITLIST_NEW:
411
                $template = 'Notification/Admin/RegistrationWaitlistNew.html';
412
                $subject = $settings['notification']['registrationWaitlistNew']['adminSubject'] ?? '';
413
                break;
414
            case MessageType::REGISTRATION_CONFIRMED:
415
                $template = 'Notification/Admin/RegistrationConfirmed.html';
416
                $subject = $settings['notification']['registrationConfirmed']['adminSubject'] ?? '';
417
                break;
418
            case MessageType::REGISTRATION_WAITLIST_CONFIRMED:
419
                $template = 'Notification/Admin/RegistrationWaitlistConfirmed.html';
420
                $subject = $settings['notification']['registrationWaitlistConfirmed']['adminSubject'] ?? '';
421
                break;
422
            case MessageType::REGISTRATION_CANCELLED:
423
                $template = 'Notification/Admin/RegistrationCancelled.html';
424
                $subject = $settings['notification']['registrationCancelled']['adminSubject'] ?? '';
425
                break;
426
            case MessageType::REGISTRATION_WAITLIST_MOVE_UP:
427
                $template = 'Notification/Admin/RegistrationWaitlistMoveUp.html';
428
                $subject = $settings['notification']['registrationWaitlistMoveUp']['adminSubject'] ?? '';
429
                break;
430
        }
431
432
        return [$template, $subject];
433
    }
434
435
    /**
436
     * Returns the rendered HTML for the given template
437
     */
438
    protected function getNotificationBody(
439
        Event $event,
440
        Registration $registration,
441
        string $template,
442
        array $settings,
443
        array $additionalBodyVariables = []
444
    ): string {
445
        $isBackendRequest = ($GLOBALS['TYPO3_REQUEST'] ?? null) instanceof ServerRequestInterface
446
            && ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isBackend();
447
448
        if ($isBackendRequest && $registration->getLanguage() !== '') {
449
            // Temporary set Language of current BE user to given language
450
            $GLOBALS['BE_USER']->uc['lang'] = $registration->getLanguage();
451
        }
452
        $defaultVariables = [
453
            'event' => $event,
454
            'registration' => $registration,
455
            'settings' => $settings,
456
            'hmac' => $this->hashService->generateHmac('reg-' . $registration->getUid()),
457
            'reghmac' => $this->hashService->appendHmac((string)$registration->getUid()),
458
        ];
459
        $variables = array_merge($additionalBodyVariables, $defaultVariables);
460
461
        return $this->fluidStandaloneService->renderTemplate($template, $variables);
462
    }
463
}
464