Passed
Pull Request — master (#5832)
by
unknown
08:28
created

LpProgressReminderCommand::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 8
dl 0
loc 11
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
/* For licensing terms, see /license.txt */
6
7
namespace Chamilo\CoreBundle\Command;
8
9
use Chamilo\CoreBundle\Repository\CourseRelUserRepository;
10
use Chamilo\CoreBundle\Repository\ExtraFieldValuesRepository;
11
use Chamilo\CoreBundle\Repository\Node\CourseRepository;
12
use Chamilo\CoreBundle\Repository\Node\UserRepository;
13
use Chamilo\CoreBundle\Repository\TrackEDefaultRepository;
14
use DateTime;
15
use DateTimeZone;
16
use Symfony\Component\Mailer\MailerInterface;
17
use Symfony\Component\Mime\Email;
18
use Symfony\Contracts\Translation\TranslatorInterface;
19
use Twig\Environment;
20
use Symfony\Component\Console\Command\Command;
21
use Symfony\Component\Console\Input\InputInterface;
22
use Symfony\Component\Console\Input\InputOption;
23
use Symfony\Component\Console\Output\OutputInterface;
24
25
class LpProgressReminderCommand extends Command
26
{
27
    protected static $defaultName = 'app:lp-progress-reminder';
28
29
    private const NUMBER_OF_DAYS_TO_RESEND_NOTIFICATION = 3;
30
31
    public function __construct(
32
        private CourseRepository $courseRepository,
33
        private CourseRelUserRepository $courseRelUserRepository,
34
        private ExtraFieldValuesRepository $extraFieldValuesRepository,
35
        private TrackEDefaultRepository $trackEDefaultRepository,
36
        private UserRepository $userRepository,
37
        private MailerInterface $mailer,
38
        private Environment $twig,
39
        private TranslatorInterface $translator
40
    ) {
41
        parent::__construct();
42
    }
43
44
45
    protected function configure()
46
    {
47
        $this
48
            ->setDescription('Send LP progress reminders to users based on "number_of_days_for_completion".')
49
            ->addOption(
50
                'debug',
51
                null,
52
                InputOption::VALUE_NONE,
53
                'If set, will output detailed debug information'
54
            );
55
    }
56
57
    protected function execute(InputInterface $input, OutputInterface $output): int
58
    {
59
        $debugMode = $input->getOption('debug');
60
        $output->writeln('Starting the LP progress reminder process...');
61
62
        // Retrieve LPs with completion days
63
        $lpItems = $this->extraFieldValuesRepository->getLpIdWithDaysForCompletion();
64
        if ($debugMode) {
65
            $output->writeln('LP Items retrieved: ' . print_r($lpItems, true));
0 ignored issues
show
Bug introduced by
Are you sure print_r($lpItems, true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

65
            $output->writeln('LP Items retrieved: ' . /** @scrutinizer ignore-type */ print_r($lpItems, true));
Loading history...
66
        }
67
68
        if (empty($lpItems)) {
69
            $output->writeln('No learning paths with days for completion found.');
70
            return Command::SUCCESS;
71
        }
72
73
        // Retrieve all courses from the CourseRepository
74
        $courses = $this->courseRepository->findAll();
75
        if ($debugMode) {
76
            $output->writeln('Courses retrieved: ' . count($courses));
77
        }
78
79
        foreach ($courses as $course) {
80
            $courseId = $course->getId();
81
82
            if ($debugMode) {
83
                $output->writeln('Processing course ID: ' . $courseId);
84
            }
85
86
            // Retrieve users for the course (without session)
87
            $courseUsers = $this->courseRelUserRepository->getCourseUsers($courseId, array_keys($lpItems));
88
            // Retrieve users for the course session
89
            $sessionCourseUsers = $this->courseRelUserRepository->getCourseUsers($courseId, array_keys($lpItems), true);
90
91
            if ($debugMode) {
92
                $output->writeln('Course users retrieved: ' . count($courseUsers));
93
                $output->writeln('Session users retrieved: ' . count($sessionCourseUsers));
94
            }
95
96
            // Process users from the main course (sessionId = 0 or null)
97
            $this->processCourseUsers($courseUsers, $lpItems, $courseId);
98
99
            // Process users from the course session (sessionId > 0)
100
            $this->processCourseUsers($sessionCourseUsers, $lpItems, $courseId, true);
101
        }
102
103
        $output->writeln('LP progress reminder process finished.');
104
        return Command::SUCCESS;
105
    }
106
107
    /**
108
     * Processes users from a course or session to check if a reminder needs to be sent.
109
     */
110
    private function processCourseUsers(array $users, array $lpItems, int $courseId, bool $checkSession = false): void
111
    {
112
        foreach ($users as $user) {
113
            $userId = $user['userId'];
114
            $courseTitle = $user['courseTitle'];
115
            $lpId = $user['lpId'];
116
            $progress = (int) $user['progress'];
117
            $nbDaysForLpCompletion = (int) $lpItems[$lpId]['ndays'];
118
119
            if ($checkSession && isset($user['session_id']) && $user['session_id'] > 0) {
120
                $sessionId = $user['session_id'];
121
            } else {
122
                $sessionId = 0;
123
            }
124
125
            $registrationDate = $this->trackEDefaultRepository->getUserCourseRegistrationAt($courseId, $userId, $sessionId);
126
127
            if ($registrationDate && $this->isTimeToRemindUser($registrationDate, $nbDaysForLpCompletion)) {
128
                $nbRemind = $this->getNbReminder($registrationDate, $nbDaysForLpCompletion);
129
                $this->sendLpReminder($userId, $courseTitle, $progress, $registrationDate, $nbRemind);
130
            }
131
        }
132
    }
133
134
    /**
135
     * Calculates the number of reminders to be sent based on registration date and days for completion.
136
     */
137
    private function getNbReminder(DateTime $registrationDate, int $nbDaysForLpCompletion): int
138
    {
139
        $date1 = clone $registrationDate;
140
        $date1->modify("+$nbDaysForLpCompletion day");
141
142
        $date2 = new DateTime('now', new DateTimeZone('UTC'));
143
144
        $interval = $date1->diff($date2);
145
        $diffDays = (int) $interval->format('%a');
146
147
        return (int) ceil($diffDays / self::NUMBER_OF_DAYS_TO_RESEND_NOTIFICATION) + 1;
148
    }
149
150
    /**
151
     * Checks if it is time to remind the user based on their registration date and LP completion days.
152
     */
153
    private function isTimeToRemindUser(DateTime $registrationDate, int $nbDaysForLpCompletion): bool
154
    {
155
        $date1 = clone $registrationDate;
156
        $date1->modify("+$nbDaysForLpCompletion day");
157
        $startDate = $date1->format('Y-m-d');
158
159
        $date2 = new DateTime('now', new DateTimeZone('UTC'));
160
        $now = $date2->format('Y-m-d');
161
162
        if ($startDate < $now) {
163
            $interval = $date1->diff($date2);
164
            $diffDays = (int) $interval->format('%a');
165
            return (0 === $diffDays % self::NUMBER_OF_DAYS_TO_RESEND_NOTIFICATION);
166
        }
167
168
        return $startDate === $now;
169
    }
170
171
    /**
172
     * Sends a reminder email to the user regarding their LP progress.
173
     */
174
    private function sendLpReminder(int $toUserId, string $courseName, int $lpProgress, DateTime $registrationDate, int $nbRemind): bool
175
    {
176
        $user = $this->userRepository->find($toUserId);
177
        if (!$user) {
178
            throw new \Exception("User not found");
179
        }
180
181
        $hello = $this->translator->trans('HelloX');
182
        $youAreRegCourse = $this->translator->trans('YouAreRegCourseXFromDateX');
183
        $thisMessageIsAbout = $this->translator->trans('ThisMessageIsAboutX');
184
        $stepsToRemind = $this->translator->trans('StepsToRemindX');
185
        $lpRemindFooter = $this->translator->trans('LpRemindFooterX');
186
187
        $hello = sprintf($hello, $user->getFullName());
188
        $youAreRegCourse = sprintf($youAreRegCourse, $courseName, $registrationDate->format('Y-m-d'));
189
        $thisMessageIsAbout = sprintf($thisMessageIsAbout, $lpProgress);
190
        $stepsToRemind = sprintf($stepsToRemind, '', $user->getUsername(), '');
191
        $lpRemindFooter = sprintf($lpRemindFooter, '', 'm');
192
193
        $body = $this->twig->render('@ChamiloCore/Mailer/Legacy/lp_progress_reminder_body.html.twig', [
194
            'HelloX' => $hello,
195
            'YouAreRegCourseXFromDateX' => $youAreRegCourse,
196
            'ThisMessageIsAboutX' => $thisMessageIsAbout,
197
            'StepsToRemindX' => $stepsToRemind,
198
            'LpRemindFooterX' => $lpRemindFooter,
199
        ]);
200
201
        $email = (new Email())
202
            ->from('[email protected]')
203
            ->to($user->getEmail())
204
            ->subject(sprintf("Reminder number %d for the course %s", $nbRemind, $courseName))
205
            ->html($body);
206
207
        try {
208
            $this->mailer->send($email);
209
            return true;
210
        } catch (\Exception $e) {
211
            throw new \Exception('Error to send email: ' . $e->getMessage());
212
        }
213
    }
214
}
215