Passed
Pull Request — master (#5831)
by
unknown
07:35
created

ReinscriptionCheckCommand::configure()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 7
nc 1
nop 0
dl 0
loc 9
rs 10
c 1
b 0
f 0
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\Entity\Session;
10
use Chamilo\CoreBundle\Entity\SessionRelUser;
11
use Chamilo\CourseBundle\Entity\CLp;
12
use Chamilo\CourseBundle\Repository\CLpRepository;
13
use Chamilo\CoreBundle\Repository\SessionRepository;
14
use Chamilo\CourseBundle\Entity\CLpView;
15
use Doctrine\ORM\EntityManagerInterface;
16
use Symfony\Component\Console\Command\Command;
17
use Symfony\Component\Console\Input\InputInterface;
18
use Symfony\Component\Console\Output\OutputInterface;
19
use Symfony\Component\Console\Input\InputOption;
20
21
class ReinscriptionCheckCommand extends Command
22
{
23
    protected static $defaultName = 'app:reinscription-check';
24
25
    private CLpRepository $lpRepository;
26
    private SessionRepository $sessionRepository;
27
    private EntityManagerInterface $entityManager;
28
29
    public function __construct(
30
        CLpRepository $lpRepository,
31
        SessionRepository $sessionRepository,
32
        EntityManagerInterface $entityManager
33
    ) {
34
        parent::__construct();
35
        $this->lpRepository = $lpRepository;
36
        $this->sessionRepository = $sessionRepository;
37
        $this->entityManager = $entityManager;
38
    }
39
40
    protected function configure(): void
41
    {
42
        $this
43
            ->setDescription('Checks for users whose course completions have expired and reinscribe them into new sessions if needed.')
44
            ->addOption(
45
                'debug',
46
                null,
47
                InputOption::VALUE_NONE,
48
                'If set, debug messages will be shown.'
49
            );
50
    }
51
52
    protected function execute(InputInterface $input, OutputInterface $output): int
53
    {
54
        $debug = $input->getOption('debug');
55
56
        $expiredViews = $this->lpRepository->findExpiredViews(0);
57
58
        if ($debug) {
59
            $output->writeln(sprintf('Found %d expired views.', count($expiredViews)));
60
        }
61
62
        foreach ($expiredViews as $view) {
63
            $user = $view->getUser();
64
            $session = $view->getSession();
65
            $lp = $view->getLp();
66
67
            if ($debug) {
68
                $output->writeln(sprintf(
69
                    'User %d completed course %d associated with session %d, and its validity has expired.',
70
                    $user->getId(),
71
                    $lp->getIid(),
72
                    $session->getId()
73
                ));
74
            }
75
76
            $validSession = $this->findValidSessionInHierarchy($session);
77
78
            if ($validSession) {
79
                $this->enrollUserInSession($user, $validSession);
80
                if ($debug) {
81
                    $output->writeln(sprintf(
82
                        'User %d re-enrolled into session %d.',
83
                        $user->getId(),
84
                        $validSession->getId()
85
                    ));
86
                }
87
            } else {
88
                if ($debug) {
89
                    $output->writeln(sprintf(
90
                        'No valid session found for user %d.',
91
                        $user->getId()
92
                    ));
93
                }
94
            }
95
        }
96
97
        return Command::SUCCESS;
98
    }
99
100
    /**
101
     * Find users with expired completion based on "validity_in_days".
102
     */
103
    private function findExpiredCompletions($lp, $validityDays)
0 ignored issues
show
Unused Code introduced by
The method findExpiredCompletions() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
104
    {
105
        $now = new \DateTime();
106
        $expirationDate = (clone $now)->modify('-' . $validityDays . ' days');
107
108
        // Find users with 100% completion and whose last access date (start_time) is older than 'validity_in_days'
109
        return $this->entityManager->getRepository(CLpView::class)
110
            ->createQueryBuilder('v')
111
            ->innerJoin('Chamilo\CourseBundle\Entity\CLpItemView', 'iv', 'WITH', 'iv.view = v')
112
            ->where('v.lp = :lp')
113
            ->andWhere('v.progress = 100')
114
            ->andWhere('iv.startTime < :expirationDate')
115
            ->setParameter('lp', $lp)
116
            ->setParameter('expirationDate', $expirationDate->getTimestamp())
117
            ->getQuery()
118
            ->getResult();
119
    }
120
121
    /**
122
     * Enrolls a user into a session.
123
     */
124
    private function enrollUserInSession($user, $session): void
125
    {
126
        $existingSubscription = $this->findUserSubscriptionInSession($user, $session);
127
128
        if (!$existingSubscription) {
129
            $session->addUserInSession(Session::STUDENT, $user);
130
            $this->entityManager->persist($session);
131
            $this->entityManager->flush();
132
        }
133
    }
134
135
    private function findUserSubscriptionInSession($user, $session)
136
    {
137
        return $this->entityManager->getRepository(SessionRelUser::class)
138
            ->findOneBy([
139
                'user' => $user,
140
                'session' => $session,
141
            ]);
142
    }
143
144
    private function findValidSessionInHierarchy(Session $session): ?Session
145
    {
146
        $childSessions = $this->sessionRepository->findChildSessions($session);
147
148
        /* @var Session $child */
149
        foreach ($childSessions as $child) {
150
            $validUntil = (clone $child->getAccessEndDate())->modify("-{$child->getDaysToReinscription()} days");
151
            if (new \DateTime() <= $validUntil) {
152
                return $child;
153
            }
154
155
            $validChild = $this->findValidSessionInHierarchy($child);
156
            if ($validChild) {
157
                return $validChild;
158
            }
159
        }
160
161
        /* @var Session $parentSession */
162
        $parentSession = $this->sessionRepository->findParentSession($session);
163
164
        if ($parentSession) {
0 ignored issues
show
introduced by
$parentSession is of type Chamilo\CoreBundle\Entity\Session, thus it always evaluated to true.
Loading history...
165
            $validUntil = (clone $parentSession->getAccessEndDate())->modify("-{$parentSession->getDaysToReinscription()} days");
166
            if (new \DateTime() <= $validUntil) {
167
                return $parentSession;
168
            }
169
        }
170
171
        return null;
172
    }
173
174
}
175