NotificationService::getNotificationBody()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 26
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 13
c 1
b 0
f 0
nc 2
nop 6
dl 0
loc 26
rs 9.8333
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\CustomNotificationLog;
15
use DERHANSEN\SfEventMgt\Domain\Model\Dto\CustomNotification;
16
use DERHANSEN\SfEventMgt\Domain\Model\Event;
17
use DERHANSEN\SfEventMgt\Domain\Model\Registration;
18
use DERHANSEN\SfEventMgt\Domain\Repository\CustomNotificationLogRepository;
19
use DERHANSEN\SfEventMgt\Domain\Repository\RegistrationRepository;
20
use DERHANSEN\SfEventMgt\Event\AfterAdminMessageSentEvent;
0 ignored issues
show
Bug introduced by
The type DERHANSEN\SfEventMgt\Eve...erAdminMessageSentEvent was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
21
use DERHANSEN\SfEventMgt\Event\AfterUserMessageSentEvent;
0 ignored issues
show
Bug introduced by
The type DERHANSEN\SfEventMgt\Eve...terUserMessageSentEvent was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
22
use DERHANSEN\SfEventMgt\Event\ModifyAdminMessageSenderEvent;
23
use DERHANSEN\SfEventMgt\Event\ModifyCustomNotificationLogEvent;
24
use DERHANSEN\SfEventMgt\Event\ModifyUserMessageAttachmentsEvent;
25
use DERHANSEN\SfEventMgt\Event\ModifyUserMessageSenderEvent;
26
use DERHANSEN\SfEventMgt\Security\HashScope;
27
use DERHANSEN\SfEventMgt\Service\Notification\AttachmentService;
28
use DERHANSEN\SfEventMgt\Utility\MessageRecipient;
29
use DERHANSEN\SfEventMgt\Utility\MessageType;
30
use Psr\EventDispatcher\EventDispatcherInterface;
31
use RuntimeException;
32
use TYPO3\CMS\Core\Context\Context;
33
use TYPO3\CMS\Core\Crypto\HashService;
34
use TYPO3\CMS\Core\Http\ApplicationType;
35
use TYPO3\CMS\Core\Utility\GeneralUtility;
36
use TYPO3\CMS\Extbase\Mvc\RequestInterface;
0 ignored issues
show
Bug introduced by
The type TYPO3\CMS\Extbase\Mvc\RequestInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
37
38
class NotificationService
39
{
40
    public function __construct(
41
        protected readonly RegistrationRepository $registrationRepository,
42
        protected readonly EmailService $emailService,
43
        protected readonly HashService $hashService,
44
        protected readonly FluidRenderingService $fluidRenderingService,
45
        protected readonly CustomNotificationLogRepository $customNotificationLogRepository,
46
        protected readonly AttachmentService $attachmentService,
47
        protected readonly EventDispatcherInterface $eventDispatcher,
48
        protected readonly Context $context
49
    ) {
50
    }
51
52
    /**
53
     * Sends a custom notification defined by the given customNotification key
54
     * to users of the event. Returns the number of notifications sent.
55
     */
56
    public function sendCustomNotification(
57
        RequestInterface $request,
58
        Event $event,
59
        CustomNotification $customNotification,
60
        array $settings = []
61
    ): int {
62
        if ($this->cantSendCustomNotification($settings, $customNotification)) {
63
            return 0;
64
        }
65
        $count = 0;
66
67
        $customNotificationSettings = $settings['notification']['customNotifications'] ?? [];
68
        $constraints = $customNotificationSettings[$customNotification->getTemplate()]['constraints'] ?? [];
69
        $registrations = $this->registrationRepository->findNotificationRegistrations(
70
            $event,
71
            $customNotification,
72
            $constraints
73
        );
74
75
        foreach ($registrations as $registration) {
76
            /** @var Registration $registration */
77
            $result = $this->sendUserMessage(
78
                $request,
79
                $event,
80
                $registration,
81
                $settings,
82
                MessageType::CUSTOM_NOTIFICATION,
83
                $customNotification
84
            );
85
            if ($result) {
86
                ++$count;
87
            }
88
        }
89
90
        return $count;
91
    }
92
93
    /**
94
     * Returns true if conditions are not met to send a custom notification
95
     */
96
    protected function cantSendCustomNotification(
97
        array $settings,
98
        CustomNotification $customNotification
99
    ): bool {
100
        return $customNotification->getTemplate() === '' || empty($settings);
101
    }
102
103
    /**
104
     * Adds a logentry to the custom notification log
105
     */
106
    public function createCustomNotificationLogentry(
107
        Event $event,
108
        string $details,
109
        int $emailsSent,
110
        CustomNotification $customNotification
111
    ): void {
112
        $notificationlogEntry = new CustomNotificationLog();
113
        $notificationlogEntry->setPid($event->getPid());
114
        $notificationlogEntry->setEvent($event);
115
        $notificationlogEntry->setDetails($details);
116
        $notificationlogEntry->setEmailsSent($emailsSent);
117
        $notificationlogEntry->setCruserId($this->context->getPropertyFromAspect('backend.user', 'id'));
118
119
        $modifyCustomNotificationLogEntry = new ModifyCustomNotificationLogEvent(
120
            $notificationlogEntry,
121
            $event,
122
            $details,
123
            $customNotification
124
        );
125
        $this->eventDispatcher->dispatch($modifyCustomNotificationLogEntry);
126
        $notificationlogEntry = $modifyCustomNotificationLogEntry->getCustomNotificationLog();
127
128
        $this->customNotificationLogRepository->add($notificationlogEntry);
129
    }
130
131
    /**
132
     * Sends a message to the user based on the given type
133
     */
134
    public function sendUserMessage(
135
        RequestInterface $request,
136
        Event $event,
137
        Registration $registration,
138
        array $settings,
139
        int $type,
140
        ?CustomNotification $customNotification = null
141
    ): bool {
142
        [$template, $subject] = $this->getUserMessageTemplateSubject(
143
            $settings,
144
            $type,
145
            $customNotification
146
        );
147
148
        if ((bool)($settings['notification']['disabled'] ?? false) || !str_ends_with($template, '.html')) {
149
            return false;
150
        }
151
152
        $additionalBodyVariables = [
153
            'customNotification' => $customNotification,
154
        ];
155
156
        if (!$registration->isIgnoreNotifications()) {
157
            $body = $this->getNotificationBody($request, $event, $registration, $template, $settings, $additionalBodyVariables);
158
            $subject = $this->fluidRenderingService->parseString(
159
                $request,
160
                $subject,
161
                [
162
                    'event' => $event,
163
                    'registration' => $registration,
164
                ],
165
                $registration->getLanguage()
166
            );
167
            $attachments = $this->attachmentService->getAttachments(
168
                $settings,
169
                $registration,
170
                $type,
171
                MessageRecipient::USER,
172
                $customNotification
173
            );
174
175
            // Get iCal attachment if configured
176
            $iCalAttachment = $this->attachmentService->getICalAttachment(
177
                $request,
178
                $settings,
179
                $registration,
180
                $type,
181
                MessageRecipient::USER,
182
                $customNotification
183
            );
184
185
            if ($iCalAttachment !== '') {
186
                $attachments[] = $iCalAttachment;
187
            }
188
189
            $modifyUserMessageSenderEvent = new ModifyUserMessageSenderEvent(
190
                $settings['notification']['senderName'] ?? '',
191
                $settings['notification']['senderEmail'] ?? '',
192
                $settings['notification']['replyToEmail'] ?? '',
193
                $subject,
194
                $body,
195
                $registration,
196
                $type,
197
                $this,
198
                $request
199
            );
200
            $this->eventDispatcher->dispatch($modifyUserMessageSenderEvent);
201
            $subject = $modifyUserMessageSenderEvent->getSubject();
202
            $body = $modifyUserMessageSenderEvent->getBody();
203
204
            $senderName = $modifyUserMessageSenderEvent->getSenderName();
205
            $senderEmail = $modifyUserMessageSenderEvent->getSenderEmail();
206
            $replyToEmail = $modifyUserMessageSenderEvent->getReplyToEmail();
207
208
            $modifyUserAttachmentsEvent = new ModifyUserMessageAttachmentsEvent(
209
                $attachments,
210
                $registration,
211
                $type,
212
                $settings,
213
                $customNotification,
214
                $this,
215
                $request
216
            );
217
            $this->eventDispatcher->dispatch($modifyUserAttachmentsEvent);
218
            $attachments = $modifyUserAttachmentsEvent->getAttachments();
219
220
            $result = $this->emailService->sendEmailMessage(
221
                $senderEmail,
222
                $registration->getEmail(),
223
                $subject,
224
                $body,
225
                $senderName,
226
                $attachments,
227
                $replyToEmail
228
            );
229
230
            $afterUserMessageSentEvent = new AfterUserMessageSentEvent(
231
                $registration,
232
                $body,
233
                $subject,
234
                $attachments,
235
                $senderName,
236
                $senderEmail,
237
                $replyToEmail,
238
                $this,
239
                $request
240
            );
241
            $this->eventDispatcher->dispatch($afterUserMessageSentEvent);
242
243
            // Cleanup iCal attachment if available
244
            if ($iCalAttachment !== '') {
245
                GeneralUtility::unlink_tempfile($iCalAttachment);
246
            }
247
248
            return $result;
249
        }
250
251
        return false;
252
    }
253
254
    /**
255
     * Returns an array with template and subject for the user message
256
     */
257
    protected function getUserMessageTemplateSubject(
258
        array $settings,
259
        int $type,
260
        ?CustomNotification $customNotification = null
261
    ): array {
262
        if ($type === MessageType::CUSTOM_NOTIFICATION && $customNotification === null) {
263
            return ['', ''];
264
        }
265
266
        switch ($type) {
267
            case MessageType::REGISTRATION_NEW:
268
                $template = 'Notification/User/RegistrationNew.html';
269
                $subject = $settings['notification']['registrationNew']['userSubject'] ?? '';
270
                break;
271
            case MessageType::REGISTRATION_WAITLIST_NEW:
272
                $template = 'Notification/User/RegistrationWaitlistNew.html';
273
                $subject = $settings['notification']['registrationWaitlistNew']['userSubject'] ?? '';
274
                break;
275
            case MessageType::REGISTRATION_CONFIRMED:
276
                $template = 'Notification/User/RegistrationConfirmed.html';
277
                $subject = $settings['notification']['registrationConfirmed']['userSubject'] ?? '';
278
                break;
279
            case MessageType::REGISTRATION_WAITLIST_CONFIRMED:
280
                $template = 'Notification/User/RegistrationWaitlistConfirmed.html';
281
                $subject = $settings['notification']['registrationWaitlistConfirmed']['userSubject'] ?? '';
282
                break;
283
            case MessageType::REGISTRATION_CANCELLED:
284
                $template = 'Notification/User/RegistrationCancelled.html';
285
                $subject = $settings['notification']['registrationCancelled']['userSubject'] ?? '';
286
                break;
287
            case MessageType::REGISTRATION_WAITLIST_MOVE_UP:
288
                $template = 'Notification/User/RegistrationWaitlistMoveUp.html';
289
                $subject = $settings['notification']['registrationWaitlistMoveUp']['userSubject'] ?? '';
290
                break;
291
            case MessageType::CUSTOM_NOTIFICATION:
292
                $customNotificationSettings = $settings['notification']['customNotifications'] ?? [];
293
                $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

293
                /** @scrutinizer ignore-call */ 
294
                $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...
294
                $template = 'Notification/User/Custom/' . ($customNotificationSettings[$templateKey]['template'] ?? '');
295
                $subject = $customNotificationSettings[$templateKey]['subject'] ?? '';
296
                if ($customNotification->getOverwriteSubject() !== '') {
297
                    $subject = $customNotification->getOverwriteSubject();
298
                }
299
                break;
300
            default:
301
                $template = '';
302
                $subject = '';
303
        }
304
305
        return [
306
            $template,
307
            $subject,
308
        ];
309
    }
310
311
    /**
312
     * Sends a message to the admin based on the given type. Returns true, if the message was sent, otherwise false
313
     */
314
    public function sendAdminMessage(
315
        RequestInterface $request,
316
        Event $event,
317
        Registration $registration,
318
        array $settings,
319
        int $type
320
    ): bool {
321
        [$template, $subject] = $this->getAdminMessageTemplateSubject($settings, $type);
322
323
        if ((bool)($settings['notification']['disabled'] ?? false) ||
324
            ($event->getNotifyAdmin() === false && $event->getNotifyOrganisator() === false)
325
        ) {
326
            return false;
327
        }
328
329
        $allEmailsSent = true;
330
        $body = $this->getNotificationBody($request, $event, $registration, $template, $settings);
331
        $subject = $this->fluidRenderingService->parseString(
332
            $request,
333
            $subject,
334
            [
335
                'event' => $event,
336
                'registration' => $registration,
337
            ],
338
            $registration->getLanguage()
339
        );
340
        $attachments = $this->attachmentService->getAttachments(
341
            $settings,
342
            $registration,
343
            $type,
344
            MessageRecipient::ADMIN
345
        );
346
347
        $senderName = $settings['notification']['senderName'] ?? '';
348
        $senderEmail = $settings['notification']['senderEmail'] ?? '';
349
        if ((bool)($settings['notification']['registrationDataAsSenderForAdminEmails'] ?? false)) {
350
            $senderName = $registration->getFullname();
351
            $senderEmail = $registration->getEmail();
352
        }
353
354
        $modifyAdminMessageSenderEvent = new ModifyAdminMessageSenderEvent(
355
            $senderName,
356
            $senderEmail,
357
            $senderEmail,
358
            $subject,
359
            $body,
360
            $registration,
361
            $type,
362
            $this,
363
            $request
364
        );
365
        $this->eventDispatcher->dispatch($modifyAdminMessageSenderEvent);
366
        $subject = $modifyAdminMessageSenderEvent->getSubject();
367
        $body = $modifyAdminMessageSenderEvent->getBody();
368
369
        $senderName = $modifyAdminMessageSenderEvent->getSenderName();
370
        $senderEmail = $modifyAdminMessageSenderEvent->getSenderEmail();
371
        $replyToEmail = $modifyAdminMessageSenderEvent->getReplyToEmail();
372
373
        if ($event->getNotifyAdmin()) {
374
            $adminEmailArr = GeneralUtility::trimExplode(',', $settings['notification']['adminEmail'] ?? '', true);
375
            foreach ($adminEmailArr as $adminEmail) {
376
                $allEmailsSent = $allEmailsSent && $this->emailService->sendEmailMessage(
377
                    $senderEmail,
378
                    $adminEmail,
379
                    $subject,
380
                    $body,
381
                    $senderName,
382
                    $attachments,
383
                    $replyToEmail
384
                );
385
            }
386
        }
387
388
        if ($event->getNotifyOrganisator() && $event->getOrganisator()) {
389
            $allEmailsSent = $allEmailsSent && $this->emailService->sendEmailMessage(
390
                $senderEmail,
391
                $event->getOrganisator()->getEmail(),
392
                $subject,
393
                $body,
394
                $senderName,
395
                $attachments,
396
                $replyToEmail
397
            );
398
        }
399
400
        $afterAdminMessageSentEvent = new AfterAdminMessageSentEvent(
401
            $registration,
402
            $body,
403
            $subject,
404
            $attachments,
405
            $senderName,
406
            $senderEmail,
407
            $type,
408
            $replyToEmail,
409
            $this,
410
            $request
411
        );
412
        $this->eventDispatcher->dispatch($afterAdminMessageSentEvent);
413
414
        return $allEmailsSent;
415
    }
416
417
    /**
418
     * Returns an array with template and subject for the admin message
419
     */
420
    protected function getAdminMessageTemplateSubject(array $settings, int $type): array
421
    {
422
        $template = 'Notification/Admin/RegistrationNew.html';
423
        $subject = $settings['notification']['registrationNew']['adminSubject'] ?? '';
424
        switch ($type) {
425
            case MessageType::REGISTRATION_WAITLIST_NEW:
426
                $template = 'Notification/Admin/RegistrationWaitlistNew.html';
427
                $subject = $settings['notification']['registrationWaitlistNew']['adminSubject'] ?? '';
428
                break;
429
            case MessageType::REGISTRATION_CONFIRMED:
430
                $template = 'Notification/Admin/RegistrationConfirmed.html';
431
                $subject = $settings['notification']['registrationConfirmed']['adminSubject'] ?? '';
432
                break;
433
            case MessageType::REGISTRATION_WAITLIST_CONFIRMED:
434
                $template = 'Notification/Admin/RegistrationWaitlistConfirmed.html';
435
                $subject = $settings['notification']['registrationWaitlistConfirmed']['adminSubject'] ?? '';
436
                break;
437
            case MessageType::REGISTRATION_CANCELLED:
438
                $template = 'Notification/Admin/RegistrationCancelled.html';
439
                $subject = $settings['notification']['registrationCancelled']['adminSubject'] ?? '';
440
                break;
441
            case MessageType::REGISTRATION_WAITLIST_MOVE_UP:
442
                $template = 'Notification/Admin/RegistrationWaitlistMoveUp.html';
443
                $subject = $settings['notification']['registrationWaitlistMoveUp']['adminSubject'] ?? '';
444
                break;
445
        }
446
447
        return [$template, $subject];
448
    }
449
450
    /**
451
     * Returns the rendered HTML for the given template
452
     */
453
    protected function getNotificationBody(
454
        RequestInterface $request,
455
        Event $event,
456
        Registration $registration,
457
        string $template,
458
        array $settings,
459
        array $additionalBodyVariables = []
460
    ): string {
461
        $isBackendRequest = ApplicationType::fromRequest($request)->isBackend();
462
463
        if ($isBackendRequest && $registration->getLanguage() !== '') {
464
            // Temporary set language of current BE user to given language
465
            $GLOBALS['BE_USER']->user['lang'] = $registration->getLanguage();
466
        }
467
        $defaultVariables = [
468
            'event' => $event,
469
            'registration' => $registration,
470
            'settings' => $settings,
471
            'hmac' => $this->hashService->hmac('reg-' . $registration->getUid(), HashScope::RegistrationUid->value),
472
            'reghmac' => $this->hashService->appendHmac((string)$registration->getUid(), HashScope::RegistrationHmac->value),
473
            'confirmAction' => $this->getTargetLinkAction('confirmAction', $settings),
474
            'cancelAction' => $this->getTargetLinkAction('cancelAction', $settings),
475
        ];
476
        $variables = array_merge($additionalBodyVariables, $defaultVariables);
477
478
        return $this->fluidRenderingService->renderTemplate($request, $template, $variables);
479
    }
480
481
    private function getTargetLinkAction(string $action, array $settings): string
482
    {
483
        switch ($action) {
484
            case 'confirmAction':
485
                $additionalStep = (bool)($settings['confirmation']['additionalVerificationStep'] ?? false);
486
                $action = $additionalStep ? 'verifyConfirmRegistration' : 'confirmRegistration';
487
                break;
488
            case 'cancelAction':
489
                $additionalStep = (bool)($settings['cancellation']['additionalVerificationStep'] ?? false);
490
                $action = $additionalStep ? 'verifyCancelRegistration' : 'cancelRegistration';
491
                break;
492
            default:
493
                throw new RuntimeException('Unknown action for getTargetLinkAction()', 1718170550);
494
        }
495
496
        return $action;
497
    }
498
}
499