Passed
Pull Request — master (#5832)
by
unknown
06:59
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
    public function __construct(
30
        private CourseRepository $courseRepository,
31
        private CourseRelUserRepository $courseRelUserRepository,
32
        private ExtraFieldValuesRepository $extraFieldValuesRepository,
33
        private TrackEDefaultRepository $trackEDefaultRepository,
34
        private UserRepository $userRepository,
35
        private MailerInterface $mailer,
36
        private Environment $twig,
37
        private TranslatorInterface $translator
38
    ) {
39
        parent::__construct();
40
    }
41
42
43
    protected function configure()
44
    {
45
        $this
46
            ->setDescription('Send LP progress reminders to users based on "number_of_days_for_completion".')
47
            ->addOption(
48
                'debug',
49
                null,
50
                InputOption::VALUE_NONE,
51
                'If set, will output detailed debug information'
52
            );
53
    }
54
55
    protected function execute(InputInterface $input, OutputInterface $output): int
56
    {
57
        $debugMode = $input->getOption('debug');
58
        $output->writeln('Starting the LP progress reminder process...');
59
60
        // Retrieve LPs with completion days
61
        $lpItems = $this->extraFieldValuesRepository->getLpIdWithDaysForCompletion();
62
        if ($debugMode) {
63
            $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

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