NotificationService::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 0
c 1
b 0
f 0
nc 1
nop 8
dl 0
loc 10
rs 10

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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

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