Passed
Push — dependabot/npm_and_yarn/cross-... ( ad80c0...c9e4a1 )
by
unknown
15:20 queued 04:46
created

SendEventRemindersCommand::execute()   F

Complexity

Conditions 31
Paths 240

Size

Total Lines 141
Code Lines 83

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 31
eloc 83
c 4
b 0
f 0
nc 240
nop 2
dl 0
loc 141
rs 2.8333

How to fix   Long Method    Complexity   

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:

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
declare(strict_types=1);
6
7
namespace Chamilo\CoreBundle\Command;
8
9
use Chamilo\CoreBundle\Entity\AgendaReminder;
10
use Chamilo\CoreBundle\Entity\Session;
11
use Chamilo\CoreBundle\Entity\User;
12
use Chamilo\CoreBundle\Repository\Node\CourseRepository;
13
use Chamilo\CoreBundle\ServiceHelper\MessageHelper;
14
use Chamilo\CoreBundle\Settings\SettingsManager;
15
use Chamilo\CourseBundle\Entity\CCalendarEvent;
16
use DateTime;
17
use DateTimeZone;
18
use Doctrine\ORM\EntityManagerInterface;
19
use Symfony\Component\Console\Command\Command;
20
use Symfony\Component\Console\Input\InputInterface;
21
use Symfony\Component\Console\Input\InputOption;
22
use Symfony\Component\Console\Output\OutputInterface;
23
use Symfony\Component\Console\Style\SymfonyStyle;
24
use Symfony\Contracts\Translation\TranslatorInterface;
25
26
use const PHP_EOL;
27
28
class SendEventRemindersCommand extends Command
29
{
30
    /**
31
     * @var string
32
     */
33
    protected static $defaultName = 'app:send-event-reminders';
34
35
    public function __construct(
36
        private readonly EntityManagerInterface $entityManager,
37
        private readonly SettingsManager $settingsManager,
38
        private readonly CourseRepository $courseRepository,
39
        private readonly TranslatorInterface $translator,
40
        private readonly MessageHelper $messageHelper
41
    ) {
42
        parent::__construct();
43
    }
44
45
    protected function configure(): void
46
    {
47
        $this
48
            ->setDescription('Send notification messages to users that have reminders from events in their agenda.')
49
            ->addOption('debug', null, InputOption::VALUE_NONE, 'Enable debug mode')
50
            ->setHelp('This command sends notifications to users who have pending reminders for calendar events.')
51
        ;
52
    }
53
54
    protected function execute(InputInterface $input, OutputInterface $output): int
55
    {
56
        $io = new SymfonyStyle($input, $output);
57
        $debug = $input->getOption('debug');
58
        $now = new DateTime('now', new DateTimeZone('UTC'));
59
        $initialSentRemindersCount = 0;
60
        $sentRemindersCount = 0;
61
62
        if ($debug) {
63
            error_log('Debug mode activated');
64
            $io->note('Debug mode activated');
65
        }
66
67
        $remindersRepo = $this->entityManager->getRepository(AgendaReminder::class);
68
        $reminders = $remindersRepo->findBy(['sent' => false]);
69
70
        if ($debug) {
71
            error_log('Total reminders fetched: '.\count($reminders));
72
        }
73
74
        $senderId = $this->settingsManager->getSetting('agenda.agenda_reminders_sender_id');
75
        $senderId = (int) $senderId ?: $this->getFirstAdminId();
76
77
        foreach ($reminders as $reminder) {
78
            /** @var CCalendarEvent $event */
79
            $event = $reminder->getEvent();
80
81
            if (null === $event) {
82
                if ($debug) {
83
                    error_log('No event found for reminder ID: '.$reminder->getId());
84
                }
85
86
                continue;
87
            }
88
89
            $eventType = $event->determineType();
90
            $notificationDate = clone $event->getStartDate();
91
            $notificationDate->sub($reminder->getDateInterval());
92
            if ($notificationDate > $now) {
93
                continue;
94
            }
95
96
            $eventDetails = $this->generateEventDetails($event);
97
98
            $initialSentRemindersCount = $sentRemindersCount;
99
100
            if ('personal' === $eventType) {
101
                $creator = $event->getResourceNode()->getCreator();
102
                if ($creator) {
103
                    $this->sendReminderMessage($creator, $event, $senderId, $debug, $io, $sentRemindersCount);
104
                }
105
106
                $resourceLinks = $event->getResourceNode()->getResourceLinks();
107
                if (!$resourceLinks->isEmpty()) {
108
                    foreach ($resourceLinks as $link) {
109
                        if ($user = $link->getUser()) {
110
                            $this->sendReminderMessage($user, $event, $senderId, $debug, $io, $sentRemindersCount);
111
                        }
112
                    }
113
                }
114
            } else {
115
                $resourceLink = $event->getResourceNode()->getResourceLinks()->first();
116
                if (!$resourceLink) {
117
                    if ($debug) {
118
                        error_log("No ResourceLink found for event ID: {$event->getIid()}");
119
                    }
120
121
                    continue;
122
                }
123
124
                switch ($eventType) {
125
                    case 'global':
126
                        foreach ($event->getResourceNode()->getResourceLinks() as $link) {
127
                            if ($user = $link->getUser()) {
128
                                $this->sendReminderMessage($user, $event, $senderId, $debug, $io, $sentRemindersCount);
129
                            }
130
                        }
131
132
                        break;
133
134
                    case 'course':
135
                        if ($course = $resourceLink->getCourse()) {
136
                            $users = $this->courseRepository->getSubscribedUsers($course)->getQuery()->getResult();
137
                            foreach ($users as $user) {
138
                                $this->sendReminderMessage($user, $event, $senderId, $debug, $io, $sentRemindersCount);
139
                            }
140
                        }
141
142
                        break;
143
144
                    case 'session':
145
                        if ($session = $resourceLink->getSession()) {
146
                            $course = $resourceLink->getCourse();
147
                            if (!$course) {
148
                                if ($debug) {
149
                                    error_log("No course found for resource link in session ID: {$session->getId()}");
150
                                }
151
152
                                break;
153
                            }
154
155
                            $usersToNotify = [];
156
                            $studentSubscriptions = $session->getSessionRelCourseRelUsersByStatus($course, Session::STUDENT);
157
                            foreach ($studentSubscriptions as $studentSubscription) {
158
                                $usersToNotify[$studentSubscription->getUser()->getId()] = $studentSubscription->getUser();
159
                            }
160
161
                            $coachSubscriptions = $session->getSessionRelCourseRelUsersByStatus($course, Session::COURSE_COACH);
162
                            foreach ($coachSubscriptions as $coachSubscription) {
163
                                $usersToNotify[$coachSubscription->getUser()->getId()] = $coachSubscription->getUser();
164
                            }
165
166
                            $generalCoaches = $session->getGeneralCoaches();
167
                            foreach ($generalCoaches as $generalCoach) {
168
                                $usersToNotify[$generalCoach->getId()] = $generalCoach;
169
                            }
170
171
                            foreach ($usersToNotify as $user) {
172
                                $this->sendReminderMessage($user, $event, $senderId, $debug, $io, $sentRemindersCount);
173
                            }
174
                        }
175
176
                        break;
177
                }
178
            }
179
180
            if ($sentRemindersCount > $initialSentRemindersCount) {
181
                $reminder->setSent(true);
182
                $this->entityManager->persist($reminder);
183
            }
184
        }
185
186
        $this->entityManager->flush();
187
188
        if ($sentRemindersCount > 0) {
189
            $io->success(\sprintf('%d event reminders have been sent successfully.', $sentRemindersCount));
190
        } else {
191
            $io->warning('No event reminders were sent.');
192
        }
193
194
        return Command::SUCCESS;
195
    }
196
197
    private function sendReminderMessage(User $user, CCalendarEvent $event, int $senderId, bool $debug, SymfonyStyle $io, int &$sentRemindersCount): void
198
    {
199
        $locale = $user->getLocale() ?: 'en';
200
        $this->translator->setLocale($locale);
201
202
        $messageSubject = $this->translator->trans('Reminder for event : %s', ['%s' => $event->getTitle()]);
203
        $messageContent = implode(PHP_EOL, $this->generateEventDetails($event));
204
205
        $this->messageHelper->sendMessageSimple($user->getId(), $messageSubject, $messageContent, $senderId);
206
207
        if ($debug) {
208
            error_log("Message sent to user ID: {$user->getId()} for event: {$event->getTitle()}");
209
            error_log("Message Subject: {$messageSubject}");
210
            error_log("Message Content: {$messageContent}");
211
        }
212
213
        $sentRemindersCount++;
214
    }
215
216
    private function getFirstAdminId(): int
217
    {
218
        $admin = $this->entityManager->getRepository(User::class)->findOneBy([]);
219
220
        return $admin && ($admin->hasRole('ROLE_ADMIN') || $admin->hasRole('ROLE_SUPER_ADMIN'))
221
            ? $admin->getId()
222
            : 1;
223
    }
224
225
    private function generateEventDetails(CCalendarEvent $event): array
226
    {
227
        $details = [];
228
        $details[] = \sprintf('<p><strong>%s</strong></p>', $event->getTitle());
229
230
        if ($event->isAllDay()) {
231
            $details[] = \sprintf('<p class="small">%s</p>', $this->translator->trans('All Day'));
232
        } else {
233
            $details[] = \sprintf(
234
                '<p class="small">%s</p>',
235
                $this->translator->trans('From %s', ['%s' => $event->getStartDate()->format('Y-m-d H:i:s')])
236
            );
237
238
            if ($event->getEndDate()) {
239
                $details[] = \sprintf(
240
                    '<p class="small">%s</p>',
241
                    $this->translator->trans('Until %s', ['%s' => $event->getEndDate()->format('Y-m-d H:i:s')])
242
                );
243
            }
244
        }
245
246
        if ($event->getContent()) {
247
            $cleanContent = strip_tags($event->getContent());
248
            $details[] = \sprintf('<p>%s</p>', $cleanContent);
249
        }
250
251
        return $details;
252
    }
253
}
254