Passed
Push — typo3_11 ( 20e161...9114f7 )
by Torben
03:26
created

NotificationService::injectAttachmentService()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
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
        array $settings = []
96
    ): int {
97
        if ($this->cantSendCustomNotification($settings, $customNotification)) {
98
            return 0;
99
        }
100
        $count = 0;
101
102
        $customNotificationSettings = $settings['notification']['customNotifications'] ?? [];
103
        $constraints = $customNotificationSettings[$customNotification->getTemplate()]['constraints'] ?? [];
104
        $registrations = $this->registrationRepository->findNotificationRegistrations(
105
            $event,
106
            $customNotification,
107
            $constraints
108
        );
109
110
        foreach ($registrations as $registration) {
111
            /** @var Registration $registration */
112
            $result = $this->sendUserMessage(
113
                $event,
114
                $registration,
115
                $settings,
116
                MessageType::CUSTOM_NOTIFICATION,
117
                $customNotification
118
            );
119
            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
     * @param CustomNotification|null $customNotification
132
     *
133
     * @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
     * @param Event $event
146
     * @param string $details
147
     * @param int $emailsSent
148
     */
149
    public function createCustomNotificationLogentry(Event $event, string $details, int $emailsSent): void
150
    {
151
        $notificationlogEntry = new \DERHANSEN\SfEventMgt\Domain\Model\CustomNotificationLog();
152
        $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
        $notificationlogEntry->setEvent($event);
154
        $notificationlogEntry->setDetails($details);
155
        $notificationlogEntry->setEmailsSent($emailsSent);
156
        $notificationlogEntry->setCruserId($GLOBALS['BE_USER']->user['uid']);
157
158
        $modifyCustomNotificationLogEntry = new ModifyCustomNotificationLogEvent(
159
            $notificationlogEntry,
160
            $event,
161
            $details
162
        );
163
        $this->eventDispatcher->dispatch($modifyCustomNotificationLogEntry);
164
        $notificationlogEntry = $modifyCustomNotificationLogEntry->getCustomNotificationLog();
165
166
        $this->customNotificationLogRepository->add($notificationlogEntry);
167
    }
168
169
    /**
170
     * Sends a message to the user based on the given type
171
     *
172
     * @param Event $event
173
     * @param Registration $registration
174
     * @param array $settings
175
     * @param int $type
176
     * @param CustomNotification|null $customNotification
177
     *
178
     * @return bool TRUE if successful, else FALSE
179
     */
180
    public function sendUserMessage(
181
        Event $event,
182
        Registration $registration,
183
        array $settings,
184
        int $type,
185
        ?CustomNotification $customNotification = null
186
    ): bool {
187
        list($template, $subject) = $this->getUserMessageTemplateSubject(
188
            $settings,
189
            $type,
190
            $customNotification
191
        );
192
193
        if (!is_array($settings) || (substr($template, -5) != '.html') || (bool)$settings['notification']['disabled']) {
0 ignored issues
show
introduced by
The condition is_array($settings) is always true.
Loading history...
194
            return false;
195
        }
196
197
        $additionalBodyVariables = [
198
            'customNotification' => $customNotification
199
        ];
200
201
        if (!$registration->isIgnoreNotifications()) {
202
            $body = $this->getNotificationBody($event, $registration, $template, $settings, $additionalBodyVariables);
203
            $subject = $this->fluidStandaloneService->parseStringFluid(
204
                $subject,
205
                [
206
                    'event' => $event,
207
                    'registration' => $registration
208
                ]
209
            );
210
            $attachments = $this->attachmentService->getAttachments(
211
                $settings,
212
                $registration,
213
                $type,
214
                MessageRecipient::USER
215
            );
216
217
            // Get iCal attachment if configured
218
            $iCalAttachment = $this->attachmentService->getICalAttachment(
219
                $settings,
220
                $registration,
221
                $type,
222
                MessageRecipient::USER
223
            );
224
225
            if ($iCalAttachment !== '') {
226
                $attachments[] = $iCalAttachment;
227
            }
228
229
            $modifyUserMessageSenderEvent = new ModifyUserMessageSenderEvent(
230
                $settings['notification']['senderName'] ?? '',
231
                $settings['notification']['senderEmail'] ?? '',
232
                $settings['notification']['replyToEmail'] ?? '',
233
                $registration,
234
                $type,
235
                $this
236
            );
237
            $this->eventDispatcher->dispatch($modifyUserMessageSenderEvent);
238
            $senderName = $modifyUserMessageSenderEvent->getSenderName();
239
            $senderEmail = $modifyUserMessageSenderEvent->getSenderEmail();
240
            $replyToEmail = $modifyUserMessageSenderEvent->getReplyToEmail();
241
242
            $modifyUserAttachmentsEvent = new ModifyUserMessageAttachmentsEvent(
243
                $attachments,
244
                $registration,
245
                $type,
246
                $this
247
            );
248
            $this->eventDispatcher->dispatch($modifyUserAttachmentsEvent);
249
            $attachments = $modifyUserAttachmentsEvent->getAttachments();
250
251
            $result = $this->emailService->sendEmailMessage(
252
                $senderEmail,
253
                $registration->getEmail(),
254
                $subject,
255
                $body,
256
                $senderName,
257
                $attachments,
258
                $replyToEmail
259
            );
260
261
            $afterUserMessageSentEvent = new AfterUserMessageSentEvent(
262
                $registration,
263
                $body,
264
                $subject,
265
                $attachments,
266
                $senderName,
267
                $senderEmail,
268
                $replyToEmail,
269
                $this
270
            );
271
            $this->eventDispatcher->dispatch($afterUserMessageSentEvent);
272
273
            // Cleanup iCal attachment if available
274
            if ($iCalAttachment !== '') {
275
                GeneralUtility::unlink_tempfile($iCalAttachment);
276
            }
277
278
            return $result;
279
        }
280
281
        return false;
282
    }
283
284
    /**
285
     * Returns an array with template and subject for the user message
286
     *
287
     * @param array $settings
288
     * @param int $type Type
289
     * @param CustomNotification|null $customNotification
290
     * @return array
291
     */
292
    protected function getUserMessageTemplateSubject(
293
        array $settings,
294
        int $type,
295
        CustomNotification $customNotification = null
296
    ): array {
297
        switch ($type) {
298
            case MessageType::REGISTRATION_NEW:
299
                $template = 'Notification/User/RegistrationNew.html';
300
                $subject = $settings['notification']['registrationNew']['userSubject'] ?? '';
301
                break;
302
            case MessageType::REGISTRATION_WAITLIST_NEW:
303
                $template = 'Notification/User/RegistrationWaitlistNew.html';
304
                $subject = $settings['notification']['registrationWaitlistNew']['userSubject'] ?? '';
305
                break;
306
            case MessageType::REGISTRATION_CONFIRMED:
307
                $template = 'Notification/User/RegistrationConfirmed.html';
308
                $subject = $settings['notification']['registrationConfirmed']['userSubject'] ?? '';
309
                break;
310
            case MessageType::REGISTRATION_WAITLIST_CONFIRMED:
311
                $template = 'Notification/User/RegistrationWaitlistConfirmed.html';
312
                $subject = $settings['notification']['registrationWaitlistConfirmed']['userSubject'] ?? '';
313
                break;
314
            case MessageType::REGISTRATION_CANCELLED:
315
                $template = 'Notification/User/RegistrationCancelled.html';
316
                $subject = $settings['notification']['registrationCancelled']['userSubject'] ?? '';
317
                break;
318
            case MessageType::REGISTRATION_WAITLIST_MOVE_UP:
319
                $template = 'Notification/User/RegistrationWaitlistMoveUp.html';
320
                $subject = $settings['notification']['registrationWaitlistMoveUp']['userSubject'] ?? '';
321
                break;
322
            case MessageType::CUSTOM_NOTIFICATION && $customNotification:
323
                $customNotificationSettings = $settings['notification']['customNotifications'] ?? '';
324
                $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

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