Passed
Push — master ( 4c7952...221fe6 )
by Angel Fernando Quiroz
08:53
created

MessageHelper::sendMessage()   C

Complexity

Conditions 12
Paths 34

Size

Total Lines 72
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

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

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