Passed
Push — dependabot/npm_and_yarn/microm... ( e84ba6...f2f212 )
by
unknown
10:03
created

MessageHelper::sendMessage()   C

Complexity

Conditions 12
Paths 34

Size

Total Lines 72
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 12
eloc 35
c 1
b 0
f 0
nc 34
nop 13
dl 0
loc 72
rs 6.9666

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
/* For licensing terms, see /license.txt */
6
7
namespace Chamilo\CoreBundle\ServiceHelper;
8
9
use Chamilo\CoreBundle\Entity\Message;
10
use Chamilo\CoreBundle\Entity\MessageAttachment;
11
use Chamilo\CoreBundle\Entity\MessageRelUser;
12
use Chamilo\CoreBundle\Entity\User;
13
use Chamilo\CoreBundle\Entity\Usergroup;
14
use Chamilo\CoreBundle\Repository\MessageRepository;
15
use Chamilo\CoreBundle\Repository\Node\UserRepository;
16
use Chamilo\CoreBundle\Settings\SettingsManager;
17
use Doctrine\ORM\EntityManagerInterface;
18
use Symfony\Component\HttpFoundation\File\UploadedFile;
19
use Symfony\Component\HttpFoundation\RequestStack;
20
use Symfony\Component\Mailer\MailerInterface;
21
use Symfony\Component\Mime\Email;
22
23
class MessageHelper
24
{
25
    private $session;
26
27
    public function __construct(
28
        private readonly EntityManagerInterface $entityManager,
29
        private readonly MessageRepository      $messageRepository,
30
        private readonly UserRepository         $userRepository,
31
        private readonly RequestStack           $requestStack,
32
        private readonly AccessUrlHelper        $accessUrlHelper,
33
        private readonly SettingsManager        $settingsManager,
34
        private readonly MailerInterface        $mailer
35
    ) {
36
        if (php_sapi_name() !== 'cli') {
37
            $this->session = $this->requestStack->getSession();
38
        }
39
    }
40
41
    /**
42
     * Sends a simple message with optional attachments and notifications to HR users.
43
     */
44
    public function sendMessageSimple(
45
        int $receiverUserId,
46
        string $subject,
47
        string $message,
48
        int $senderId = 0,
49
        bool $sendCopyToDrhUsers = false,
50
        bool $uploadFiles = true,
51
        array $attachmentList = []
52
    ): ?int {
53
        $files = $_FILES ? $_FILES : [];
54
        if (false === $uploadFiles) {
55
            $files = [];
56
        }
57
58
        if (!empty($attachmentList)) {
59
            $files = $attachmentList;
60
        }
61
62
        $result = $this->sendMessage(
63
            $receiverUserId,
64
            $subject,
65
            $message,
66
            $files,
67
            [],
68
            0,
69
            0,
70
            0,
71
            $senderId
72
        );
73
74
        if ($sendCopyToDrhUsers) {
75
            $accessUrl = $this->accessUrlHelper->getCurrent();
76
            if ($accessUrl !== null) {
77
                $drhList = $this->userRepository->getDrhListFromUser($receiverUserId, $accessUrl->getId());
78
                if (!empty($drhList)) {
79
                    $receiverInfo = $this->userRepository->find($receiverUserId);
80
81
                    foreach ($drhList as $drhUser) {
82
                        $drhMessage = sprintf(
83
                                'Copy of message sent to %s',
84
                                $receiverInfo->getFirstname() . ' ' . $receiverInfo->getLastname()
85
                            ) . ' <br />' . $message;
86
87
                        $this->sendMessageSimple(
88
                            $drhUser->getId(),
89
                            $subject,
90
                            $drhMessage,
91
                            $senderId
92
                        );
93
                    }
94
                }
95
            }
96
        }
97
98
        return $result;
99
    }
100
101
    /**
102
     * Sends a message with attachments, forwards, and additional settings.
103
     */
104
    public function sendMessage(
105
        int $receiverUserId,
106
        string $subject,
107
        string $content,
108
        array $attachments = [],
109
        array $fileCommentList = [],
110
        int $groupId = 0,
111
        int $parentId = 0,
112
        int $editMessageId = 0,
113
        int $senderId = 0,
114
        int $forwardId = 0,
115
        bool $checkCurrentAudioId = false,
116
        bool $forceTitleWhenSendingEmail = false,
117
        ?int $msgType = null
118
    ): ?int {
119
120
        $sender = $this->userRepository->find($senderId);
121
        $receiver = $this->userRepository->find($receiverUserId);
122
123
        if (!$sender || !$receiver || !$receiver->isActive()) {
124
            return null;
125
        }
126
127
        $totalFileSize = 0;
128
        $attachmentList = $this->processAttachments($attachments, $fileCommentList, $totalFileSize);
129
130
        if ($totalFileSize > (int)  $this->settingsManager->getSetting('message.message_max_upload_filesize')) {
131
            throw new \Exception('Files size exceeds allowed limit.');
132
        }
133
134
        $parent = $this->messageRepository->find($parentId);
135
136
        if ($editMessageId) {
137
            $message = $this->messageRepository->find($editMessageId);
138
            if ($message) {
139
                $message->setTitle($subject);
140
                $message->setContent($content);
141
            }
142
        } else {
143
            $message = new Message();
144
            $message->setSender($sender)
145
                ->addReceiverTo($receiver)
146
                ->setTitle($subject)
147
                ->setContent($content)
148
                ->setGroup($groupId ? $this->getGroupById($groupId) : null)
149
                ->setParent($parent);
150
151
            if ($msgType !== null) {
152
                $message->setMsgType($msgType);
153
            }
154
        }
155
156
        $this->entityManager->persist($message);
157
        $this->entityManager->flush();
158
159
        if ($forwardId) {
160
            $this->forwardAttachments($forwardId, $message);
161
        }
162
163
        if ($checkCurrentAudioId) {
164
            $this->attachAudioMessage($message);
165
        }
166
167
        $this->saveAttachments($attachmentList, $message);
168
169
        $this->addSenderAsReceiver($message, $sender);
170
171
        if ($forceTitleWhenSendingEmail) {
172
            $this->sendEmailNotification($receiver, $sender, $subject, $content, $attachmentList);
173
        }
174
175
        return $message->getId();
176
    }
177
178
    /**
179
     * Processes attachments, calculates total file size, and returns the attachment list.
180
     */
181
    private function processAttachments(array $attachments, array $fileCommentList, &$totalFileSize): array
182
    {
183
        $attachmentList = [];
184
        foreach ($attachments as $index => $attachment) {
185
            $comment = $fileCommentList[$index] ?? '';
186
            $size = $attachment['size'] ?? 0;
187
188
            if (is_array($size)) {
189
                foreach ($size as $s) {
190
                    $totalFileSize += $s;
191
                }
192
            } else {
193
                $totalFileSize += $size;
194
            }
195
196
            $attachmentList[] = [
197
                'file' => $attachment,
198
                'comment' => $comment,
199
            ];
200
        }
201
        return $attachmentList;
202
    }
203
204
    /**
205
     * Forwards attachments from one message to another.
206
     */
207
    private function forwardAttachments(int $forwardId, Message $message): void
208
    {
209
        $forwardMessage = $this->messageRepository->find($forwardId);
210
        if ($forwardMessage) {
211
            foreach ($forwardMessage->getAttachments() as $attachment) {
212
                $message->addAttachment($attachment);
213
            }
214
            $this->entityManager->persist($message);
215
            $this->entityManager->flush();
216
        }
217
    }
218
219
    /**
220
     * Attaches an audio message from the current session to the message.
221
     */
222
    private function attachAudioMessage(Message $message): void
223
    {
224
        if ($this->session && $this->session->has('current_audio')) {
225
            $audio = $this->session->get('current_audio');
226
227
            if (!empty($audio['name'])) {
228
                $attachment = new MessageAttachment();
229
                $attachment->setFilename($audio['name'])
230
                    ->setComment('audio_message')
231
                    ->setMessage($message);
232
233
                $message->addAttachment($attachment);
234
235
                $this->entityManager->persist($attachment);
236
                $this->entityManager->flush();
237
            }
238
        }
239
    }
240
241
    /**
242
     * Saves the provided attachments and links them to the message.
243
     */
244
    private function saveAttachments(array $attachments, Message $message): void
245
    {
246
        foreach ($attachments as $attachment) {
247
            $file = $attachment['file'];
248
            $comment = $attachment['comment'] ?? '';
249
250
            if ($file instanceof UploadedFile && $file->getError() === UPLOAD_ERR_OK) {
251
                $attachmentEntity = new MessageAttachment();
252
                $attachmentEntity->setFilename($file->getClientOriginalName())
253
                    ->setSize($file->getSize())
254
                    ->setPath($file->getRealPath())
255
                    ->setMessage($message)
256
                    ->setComment($comment);
257
258
                $message->addAttachment($attachmentEntity);
259
                $this->entityManager->persist($attachmentEntity);
260
            }
261
        }
262
        $this->entityManager->flush();
263
    }
264
265
    /**
266
     * Adds the sender as a receiver in the message to keep track of the sent message.
267
     */
268
    private function addSenderAsReceiver(Message $message, User $sender): void
269
    {
270
        $messageRelUserRepository = $this->entityManager->getRepository(MessageRelUser::class);
271
        $existingRelation = $messageRelUserRepository->findOneBy([
272
            'message' => $message,
273
            'receiver' => $sender,
274
            'receiverType' => MessageRelUser::TYPE_SENDER
275
        ]);
276
277
        if (!$existingRelation) {
278
            $messageRelUserSender = new MessageRelUser();
279
            $messageRelUserSender->setMessage($message)
280
                ->setReceiver($sender)
281
                ->setReceiverType(MessageRelUser::TYPE_SENDER);
282
            $this->entityManager->persist($messageRelUserSender);
283
            $this->entityManager->flush();
284
        }
285
    }
286
287
    private function sendEmailNotification(User $receiver, User $sender, string $subject, string $content, array $attachmentList): void
288
    {
289
        if (empty($receiver->getEmail())) {
290
            throw new \Exception('The receiver does not have a valid email address.');
291
        }
292
293
        $email = (new Email())
294
            ->from($sender->getEmail())
295
            ->to($receiver->getEmail())
296
            ->subject($subject)
297
            ->text($content)
298
            ->html($content);
299
300
        foreach ($attachmentList as $attachment) {
301
            if ($attachment instanceof UploadedFile) {
302
                $email->attachFromPath($attachment->getRealPath(), $attachment->getClientOriginalName());
303
            }
304
        }
305
306
        try {
307
            $this->mailer->send($email);
308
        } catch (\Exception $e) {
309
            error_log('Failed to send email: ' . $e->getMessage());
310
        }
311
    }
312
    /**
313
     * Retrieves a user group by its ID.
314
     */
315
    private function getGroupById(int $groupId)
316
    {
317
        return $this->entityManager->getRepository(Usergroup::class)->find($groupId);
318
    }
319
}
320