Internal: Reinscription logic updated to use sessions' validity and gradebook certificates - refs BT#22057

pull/5831/head
Christian Beeznest 9 months ago
parent ad82e0be9b
commit 3b34dc1fbe
  1. 30
      public/main/inc/lib/sessionmanager.lib.php
  2. 17
      public/main/lp/lp_add.php
  3. 17
      public/main/lp/lp_edit.php
  4. 13
      public/main/session/session_add.php
  5. 9
      public/main/session/session_edit.php
  6. 1
      public/phpinfo.php
  7. 261
      src/CoreBundle/Command/ReinscriptionCheckCommand.php
  8. 15
      src/CoreBundle/Entity/Session.php
  9. 15
      src/CoreBundle/Entity/SessionRelUser.php
  10. 48
      src/CoreBundle/Migrations/Schema/V200/Version20240928003000.php
  11. 14
      src/CourseBundle/Entity/CLp.php
  12. 19
      src/CourseBundle/Repository/CLpRepository.php

@ -163,7 +163,8 @@ class SessionManager
$parentId = null,
$daysBeforeFinishingForReinscription = null,
$lastRepetition = false,
$daysBeforeFinishingToCreateNewRepetition = null
$daysBeforeFinishingToCreateNewRepetition = null,
$validityInDays = null
) {
global $_configuration;
@ -234,7 +235,8 @@ class SessionManager
->setParentId($parentId)
->setDaysToReinscription((int) $daysBeforeFinishingForReinscription)
->setLastRepetition($lastRepetition)
->setDaysToNewRepetition((int) $daysBeforeFinishingToCreateNewRepetition);
->setDaysToNewRepetition((int) $daysBeforeFinishingToCreateNewRepetition)
->setValidityInDays((int) $validityInDays);
foreach ($coachesId as $coachId) {
$session->addGeneralCoach(api_get_user_entity($coachId));
@ -1806,7 +1808,8 @@ class SessionManager
$parentId = 0,
$daysBeforeFinishingForReinscription = null,
$daysBeforeFinishingToCreateNewRepetition = null,
$lastRepetition = false
$lastRepetition = false,
$validityInDays = null
) {
$id = (int) $id;
$status = (int) $status;
@ -1880,6 +1883,7 @@ class SessionManager
->setDaysToReinscription((int) $daysBeforeFinishingForReinscription)
->setLastRepetition($lastRepetition)
->setDaysToNewRepetition((int) $daysBeforeFinishingToCreateNewRepetition)
->setValidityInDays((int) $validityInDays)
->setAccessStartDate(null)
->setAccessStartDate(null)
->setDisplayStartDate(null)
@ -8334,6 +8338,26 @@ class SessionManager
'last_repetition',
get_lang('Last repetition')
);
$form->addElement(
'number',
'validity_in_days',
get_lang('Validity in days'),
[
'min' => 0,
'max' => 365,
'step' => 1,
'placeholder' => get_lang('Enter the number of days'),
]
);
$form->addRule(
'validity_in_days',
get_lang('The field must be a positive number'),
'numeric',
null,
'client'
);
}
/** @var HTML_QuickForm_select $element */

@ -148,21 +148,6 @@ $extra = $extraField->addElements($form, 0, ['lp_icon']);
SkillModel::addSkillsToForm($form, ITEM_TYPE_LEARNPATH, 0);
$showValidityField = 'true' === api_get_setting('session.enable_auto_reinscription') || 'true' === api_get_setting('session.enable_session_replication');
if ($showValidityField) {
$form->addElement(
'number',
'validity_in_days',
get_lang('Validity in days'),
[
'min' => 0,
'max' => 365,
'step' => 1,
'placeholder' => get_lang('Enter the number of days'),
]
);
}
$form->addElement('html', '</div>');
$defaults['activate_start_date_check'] = 1;
@ -223,8 +208,6 @@ if ($form->validate()) {
$lp->setSubscribeUsers(isset($_REQUEST['subscribe_users']) ? 1 : 0);
$lp->setAccumulateScormTime(1 === (int) $_REQUEST['accumulate_scorm_time'] ? 1 : 0);
$validityInDays = $_REQUEST['validity_in_days'] ?? null;
$lp->setValidityInDays($validityInDays);
$lpRepo->update($lp);
$url = api_get_self().'?action=add_item&type=step&lp_id='.$lpId.'&'.api_get_cidreq();

@ -137,21 +137,6 @@ $form->addRule(
['jpg', 'jpeg', 'png', 'gif']
);
$showValidityField = 'true' === api_get_setting('session.enable_auto_reinscription') || 'true' === api_get_setting('session.enable_session_replication');
if ($showValidityField) {
$form->addElement(
'number',
'validity_in_days',
get_lang('Validity in days'),
[
'min' => 0,
'max' => 365,
'step' => 1,
'placeholder' => get_lang('Enter the number of days'),
]
);
}
// Search terms (only if search is activated).
if ('true' === api_get_setting('search_enabled')) {
$specific_fields = get_specific_field_list();
@ -181,7 +166,6 @@ $defaults['lp_author'] = Security::remove_XSS($lp->getAuthor());
$defaults['hide_toc_frame'] = $hideTableOfContents;
$defaults['category_id'] = $learnPath->getCategoryId();
$defaults['accumulate_scorm_time'] = $learnPath->getAccumulateScormTime();
$defaults['validity_in_days'] = $lp->getValidityInDays() ?? null;
$expired_on = $learnPath->expired_on;
$published_on = $learnPath->published_on;
@ -379,7 +363,6 @@ if ($form->validate()) {
->setExpiredOn(api_get_utc_datetime($expired_on, true, true))
->setCategory($category)
->setSubscribeUsers(isset($_REQUEST['subscribe_users']) ? 1 : 0)
->setValidityInDays(isset($_REQUEST['validity_in_days']) ? (int) $_REQUEST['validity_in_days'] : null)
;
$extraFieldValue = new ExtraFieldValue('lp');

@ -219,6 +219,7 @@ $(function() {
</script>";
$form->addButtonNext(get_lang('Next step'));
$showValidityField = 'true' === api_get_setting('session.enable_auto_reinscription') || 'true' === api_get_setting('session.enable_session_replication');
$formDefaults = [];
if (!$formSent) {
@ -250,9 +251,17 @@ if (!$formSent) {
'last_repetition' => $session->getLastRepetition(),
'parent_id' => $session->getParentId() ?? 0,
];
if ($showValidityField) {
$formDefaults['validity_in_days'] = $session->getValidityInDays();
}
} else {
$formDefaults['access_start_date'] = $formDefaults['display_start_date'] = api_get_local_time();
$formDefaults['coach_username'] = [api_get_user_id()];
if ($showValidityField) {
$formDefaults['validity_in_days'] = null;
}
}
}
@ -318,6 +327,7 @@ if ($form->validate()) {
$daysBeforeFinishingForReinscription = $params['days_before_finishing_for_reinscription'] ?? null;
$lastRepetition = isset($params['last_repetition']) ? true : false;
$daysBeforeFinishingToCreateNewRepetition = $params['days_before_finishing_to_create_new_repetition'] ?? null;
$validityInDays = $params['validity_in_days'] ?? null;
$return = SessionManager::create_session(
$title,
@ -343,7 +353,8 @@ if ($form->validate()) {
$parentId,
$daysBeforeFinishingForReinscription,
$lastRepetition,
$daysBeforeFinishingToCreateNewRepetition
$daysBeforeFinishingToCreateNewRepetition,
$validityInDays
);
if ($return == strval(intval($return))) {

@ -49,6 +49,7 @@ $(function() {
</script>';
$form->addButtonUpdate(get_lang('Edit this session'));
$showValidityField = 'true' === api_get_setting('session.enable_auto_reinscription') || 'true' === api_get_setting('session.enable_session_replication');
$formDefaults = [
'id' => $session->getId(),
@ -78,6 +79,10 @@ $formDefaults = [
'parent_id' => $session->getParentId() ?? 0,
];
if ($showValidityField) {
$formDefaults['validity_in_days'] = $session->getValidityInDays();
}
$form->setDefaults($formDefaults);
if ($form->validate()) {
@ -121,6 +126,7 @@ if ($form->validate()) {
$daysBeforeFinishingForReinscription = $params['days_before_finishing_for_reinscription'] ?? null;
$daysBeforeFinishingToCreateNewRepetition = $params['days_before_finishing_to_create_new_repetition'] ?? null;
$lastRepetition = isset($params['last_repetition']);
$validityInDays = $params['validity_in_days'] ?? null;
$return = SessionManager::edit_session(
$id,
@ -145,7 +151,8 @@ if ($form->validate()) {
$parentId,
$daysBeforeFinishingForReinscription,
$daysBeforeFinishingToCreateNewRepetition,
$lastRepetition
$lastRepetition,
$validityInDays
);
if ($return) {

@ -1 +0,0 @@
<?php phpinfo(); ?>

@ -8,10 +8,10 @@ namespace Chamilo\CoreBundle\Command;
use Chamilo\CoreBundle\Entity\Session;
use Chamilo\CoreBundle\Entity\SessionRelUser;
use Chamilo\CourseBundle\Entity\CLp;
use Chamilo\CourseBundle\Repository\CLpRepository;
use Chamilo\CoreBundle\Entity\SessionRelCourse;
use Chamilo\CoreBundle\Entity\GradebookCertificate;
use Chamilo\CoreBundle\Repository\SessionRepository;
use Chamilo\CourseBundle\Entity\CLpView;
use Chamilo\CoreBundle\Repository\GradebookCertificateRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
@ -22,25 +22,25 @@ class ReinscriptionCheckCommand extends Command
{
protected static $defaultName = 'app:reinscription-check';
private CLpRepository $lpRepository;
private SessionRepository $sessionRepository;
private GradebookCertificateRepository $certificateRepository;
private EntityManagerInterface $entityManager;
public function __construct(
CLpRepository $lpRepository,
SessionRepository $sessionRepository,
GradebookCertificateRepository $certificateRepository,
EntityManagerInterface $entityManager
) {
parent::__construct();
$this->lpRepository = $lpRepository;
$this->sessionRepository = $sessionRepository;
$this->certificateRepository = $certificateRepository;
$this->entityManager = $entityManager;
}
protected function configure(): void
{
$this
->setDescription('Checks for users whose course completions have expired and reinscribe them into new sessions if needed.')
->setDescription('Checks for users who have validated all gradebooks and reinscribe them into new sessions if needed.')
->addOption(
'debug',
null,
@ -53,93 +53,201 @@ class ReinscriptionCheckCommand extends Command
{
$debug = $input->getOption('debug');
$expiredViews = $this->lpRepository->findExpiredViews(0);
$sessions = $this->sessionRepository->findAll();
if ($debug) {
$output->writeln(sprintf('Found %d expired views.', count($expiredViews)));
}
foreach ($sessions as $session) {
if ($session->getValidityInDays() === null) {
continue;
}
foreach ($expiredViews as $view) {
$user = $view->getUser();
$session = $view->getSession();
$users = $this->getUsersForSession($session);
if ($this->isUserAlreadyEnrolledInChildSession($user, $session)) {
foreach ($users as $user) {
if ($debug) {
$output->writeln(sprintf('User %d is already enrolled in a valid child session.', $user->getId()));
$output->writeln(sprintf('Processing user %d in session %d.', $user->getId(), $session->getId()));
}
if ($this->isUserReinscribed($user, $session)) {
continue;
}
if ($this->isUserAlreadyEnrolledInChildSession($user, $session)) {
if ($debug) {
$output->writeln(sprintf('User %d is already enrolled in a valid child session.', $user->getId()));
}
continue;
}
$certificates = $this->getUserCertificatesForSession($user, $session);
if ($this->hasUserValidatedAllGradebooks($session, $certificates)) {
$latestValidationDate = $this->getLatestCertificateDate($certificates);
if ($latestValidationDate !== null) {
$reinscriptionDate = (clone $latestValidationDate)->modify("+{$session->getValidityInDays()} days");
if ($debug) {
$output->writeln(sprintf(
'User %d - Latest certificate date: %s, Reinscription date: %s',
$user->getId(),
$latestValidationDate->format('Y-m-d'),
$reinscriptionDate->format('Y-m-d')
));
}
if (new \DateTime() >= $reinscriptionDate) {
$validSession = $this->findValidSessionInHierarchy($session);
if ($validSession) {
$this->enrollUserInSession($user, $validSession, $session);
if ($debug) {
$output->writeln(sprintf(
'User %d re-enrolled into session %d.',
$user->getId(),
$validSession->getId()
));
}
}
}
} else {
if ($debug) {
$output->writeln(sprintf(
'User %d has no valid certificates for session %d.',
$user->getId(),
$session->getId()
));
}
}
}
continue;
}
}
$lp = $view->getLp();
return Command::SUCCESS;
}
/**
* Retrieves all users associated with the session.
*/
private function getUsersForSession(Session $session): array
{
$usersToNotify = [];
$sessionCourses = $this->entityManager->getRepository(SessionRelCourse::class)->findBy(['session' => $session]);
foreach ($sessionCourses as $courseRel) {
$course = $courseRel->getCourse();
if ($debug) {
$output->writeln(sprintf(
'User %d completed course %d associated with session %d, and its validity has expired.',
$user->getId(),
$lp->getIid(),
$session->getId()
));
$studentSubscriptions = $session->getSessionRelCourseRelUsersByStatus($course, Session::STUDENT);
foreach ($studentSubscriptions as $studentSubscription) {
$usersToNotify[$studentSubscription->getUser()->getId()] = $studentSubscription->getUser();
}
$validSession = $this->findValidSessionInHierarchy($session);
$coachSubscriptions = $session->getSessionRelCourseRelUsersByStatus($course, Session::COURSE_COACH);
foreach ($coachSubscriptions as $coachSubscription) {
$usersToNotify[$coachSubscription->getUser()->getId()] = $coachSubscription->getUser();
}
}
if ($validSession) {
$this->enrollUserInSession($user, $validSession);
if ($debug) {
$output->writeln(sprintf(
'User %d re-enrolled into session %d.',
$user->getId(),
$validSession->getId()
));
}
} else {
if ($debug) {
$output->writeln(sprintf(
'No valid session found for user %d.',
$user->getId()
));
}
$generalCoaches = $session->getGeneralCoaches();
foreach ($generalCoaches as $generalCoach) {
$usersToNotify[$generalCoach->getId()] = $generalCoach;
}
return array_values($usersToNotify);
}
/**
* Checks if the user is already enrolled in a valid child session.
*/
private function isUserAlreadyEnrolledInChildSession($user, $parentSession): bool
{
$childSessions = $this->sessionRepository->findChildSessions($parentSession);
foreach ($childSessions as $childSession) {
if ($this->findUserSubscriptionInSession($user, $childSession)) {
return true;
}
}
return Command::SUCCESS;
return false;
}
/**
* Find users with expired completion based on "validity_in_days".
* Gets the user's certificates for the courses in the session.
*/
private function findExpiredCompletions($lp, $validityDays)
private function getUserCertificatesForSession($user, Session $session): array
{
$now = new \DateTime();
$expirationDate = (clone $now)->modify('-' . $validityDays . ' days');
// Find users with 100% completion and whose last access date (start_time) is older than 'validity_in_days'
return $this->entityManager->getRepository(CLpView::class)
->createQueryBuilder('v')
->innerJoin('Chamilo\CourseBundle\Entity\CLpItemView', 'iv', 'WITH', 'iv.view = v')
->where('v.lp = :lp')
->andWhere('v.progress = 100')
->andWhere('iv.startTime < :expirationDate')
->setParameter('lp', $lp)
->setParameter('expirationDate', $expirationDate->getTimestamp())
$courses = $this->entityManager->getRepository(SessionRelCourse::class)
->findBy(['session' => $session]);
$courseIds = array_map(fn($rel) => $rel->getCourse()->getId(), $courses);
return $this->certificateRepository->createQueryBuilder('gc')
->join('gc.category', 'cat')
->where('gc.user = :user')
->andWhere('cat.course IN (:courses)')
->setParameter('user', $user)
->setParameter('courses', $courseIds)
->getQuery()
->getResult();
}
/**
* Enrolls a user into a session.
* Checks if the user has validated all gradebooks in the session.
*/
private function hasUserValidatedAllGradebooks(Session $session, array $certificates): bool
{
$courses = $this->entityManager->getRepository(SessionRelCourse::class)
->findBy(['session' => $session]);
return count($certificates) === count($courses);
}
/**
* Returns the latest certificate creation date.
*/
private function enrollUserInSession($user, $session): void
private function getLatestCertificateDate(array $certificates): ?\DateTime
{
$existingSubscription = $this->findUserSubscriptionInSession($user, $session);
$dates = array_map(fn($cert) => $cert->getCreatedAt(), $certificates);
if (empty($dates)) {
return null;
}
return max($dates);
}
/**
* Enrolls the user in a new session and updates the previous session subscription.
*/
private function enrollUserInSession($user, $newSession, $oldSession): void
{
$existingSubscription = $this->findUserSubscriptionInSession($user, $newSession);
if (!$existingSubscription) {
$session->addUserInSession(Session::STUDENT, $user);
$this->entityManager->persist($session);
$newSession->addUserInSession(Session::STUDENT, $user);
$subscription = $this->findUserSubscriptionInSession($user, $oldSession);
if ($subscription) {
$subscription->setNewSubscriptionSessionId($newSession->getId());
}
$this->entityManager->persist($newSession);
$this->entityManager->flush();
}
}
/**
* Determines if the user has already been reinscribed.
*/
private function isUserReinscribed($user, Session $session): bool
{
$subscription = $this->findUserSubscriptionInSession($user, $session);
return $subscription && $subscription->getNewSubscriptionSessionId() !== null;
}
/**
* Finds the user's subscription in the specified session.
*/
private function findUserSubscriptionInSession($user, $session)
{
return $this->entityManager->getRepository(SessionRelUser::class)
@ -149,6 +257,9 @@ class ReinscriptionCheckCommand extends Command
]);
}
/**
* Finds a valid session within the session hierarchy.
*/
private function findValidSessionInHierarchy(Session $session): ?Session
{
$childSessions = $this->sessionRepository->findChildSessions($session);
@ -159,36 +270,14 @@ class ReinscriptionCheckCommand extends Command
if (new \DateTime() <= $validUntil) {
return $child;
}
$validChild = $this->findValidSessionInHierarchy($child);
if ($validChild) {
return $validChild;
}
}
/* @var Session $parentSession */
$parentSession = $this->sessionRepository->findParentSession($session);
if ($parentSession) {
$validUntil = (clone $parentSession->getAccessEndDate())->modify("-{$parentSession->getDaysToReinscription()} days");
if (new \DateTime() <= $validUntil) {
return $parentSession;
}
if ($parentSession && new \DateTime() <= $parentSession->getAccessEndDate()) {
return $parentSession;
}
return null;
}
private function isUserAlreadyEnrolledInChildSession($user, $parentSession): bool
{
$childSessions = $this->sessionRepository->findChildSessions($parentSession);
foreach ($childSessions as $childSession) {
if ($this->findUserSubscriptionInSession($user, $childSession)) {
return true;
}
}
return false;
}
}

@ -395,6 +395,10 @@ class Session implements ResourceWithAccessUrlInterface, Stringable
#[ORM\Column(name: 'notify_boss', type: 'boolean', options: ['default' => false])]
protected bool $notifyBoss = false;
#[Groups(['session:basic', 'session:read', 'session:write'])]
#[ORM\Column(name: 'validity_in_days', type: 'integer', nullable: true)]
protected ?int $validityInDays = null;
public function __construct()
{
$this->skills = new ArrayCollection();
@ -1545,4 +1549,15 @@ class Session implements ResourceWithAccessUrlInterface, Stringable
return $this;
}
public function getValidityInDays(): ?int
{
return $this->validityInDays;
}
public function setValidityInDays(?int $validityInDays): self
{
$this->validityInDays = $validityInDays;
return $this;
}
}

@ -108,6 +108,9 @@ class SessionRelUser
#[ORM\Column(name: 'collapsed', type: 'boolean', nullable: true, options: ['default' => null])]
protected ?bool $collapsed = null;
#[ORM\Column(name: 'new_subscription_session_id', type: 'integer', nullable: true)]
protected ?int $newSubscriptionSessionId = null;
/**
* @throws Exception
*/
@ -226,4 +229,16 @@ class SessionRelUser
return $this;
}
public function getNewSubscriptionSessionId(): ?int
{
return $this->newSubscriptionSessionId;
}
public function setNewSubscriptionSessionId(?int $newSubscriptionSessionId): self
{
$this->newSubscriptionSessionId = $newSubscriptionSessionId;
return $this;
}
}

@ -20,6 +20,15 @@ final class Version20240928003000 extends AbstractMigrationChamilo
{
$schemaManager = $this->connection->createSchemaManager();
// Add 'new_subscription_session_id' to the 'session_rel_user' table
if ($schemaManager->tablesExist('session_rel_user')) {
$sessionRelUserTable = $schemaManager->listTableColumns('session_rel_user');
if (!isset($sessionRelUserTable['new_subscription_session_id'])) {
$this->addSql("ALTER TABLE session_rel_user ADD new_subscription_session_id INT DEFAULT NULL");
}
}
// Add fields to the 'session' table
if ($schemaManager->tablesExist('session')) {
$sessionTable = $schemaManager->listTableColumns('session');
@ -38,12 +47,21 @@ final class Version20240928003000 extends AbstractMigrationChamilo
}
}
// Add fields to the 'c_lp' (Learnpath) table
// Add 'validity_in_days' to the 'session' table
if ($schemaManager->tablesExist('session')) {
$sessionTable = $schemaManager->listTableColumns('session');
if (!isset($sessionTable['validity_in_days'])) {
$this->addSql("ALTER TABLE session ADD validity_in_days INT DEFAULT NULL");
}
}
// Remove 'validity_in_days' from the 'c_lp' table
if ($schemaManager->tablesExist('c_lp')) {
$clpTable = $schemaManager->listTableColumns('c_lp');
if (!isset($clpTable['validity_in_days'])) {
$this->addSql("ALTER TABLE c_lp ADD validity_in_days INT DEFAULT NULL");
if (isset($clpTable['validity_in_days'])) {
$this->addSql("ALTER TABLE c_lp DROP COLUMN validity_in_days");
}
}
@ -69,6 +87,15 @@ final class Version20240928003000 extends AbstractMigrationChamilo
{
$schemaManager = $this->connection->createSchemaManager();
// Revert 'new_subscription_session_id' in the 'session_rel_user' table
if ($schemaManager->tablesExist('session_rel_user')) {
$sessionRelUserTable = $schemaManager->listTableColumns('session_rel_user');
if (isset($sessionRelUserTable['new_subscription_session_id'])) {
$this->addSql("ALTER TABLE session_rel_user DROP COLUMN new_subscription_session_id");
}
}
// Revert changes in the 'session' table
if ($schemaManager->tablesExist('session')) {
$sessionTable = $schemaManager->listTableColumns('session');
@ -87,12 +114,21 @@ final class Version20240928003000 extends AbstractMigrationChamilo
}
}
// Revert changes in the 'c_lp' table
// Revert 'validity_in_days' in the 'session' table
if ($schemaManager->tablesExist('session')) {
$sessionTable = $schemaManager->listTableColumns('session');
if (isset($sessionTable['validity_in_days'])) {
$this->addSql("ALTER TABLE session DROP COLUMN validity_in_days");
}
}
// Re-add 'validity_in_days' to the 'c_lp' table
if ($schemaManager->tablesExist('c_lp')) {
$clpTable = $schemaManager->listTableColumns('c_lp');
if (isset($clpTable['validity_in_days'])) {
$this->addSql("ALTER TABLE c_lp DROP COLUMN validity_in_days");
if (!isset($clpTable['validity_in_days'])) {
$this->addSql("ALTER TABLE c_lp ADD validity_in_days INT DEFAULT NULL");
}
}

@ -158,9 +158,6 @@ class CLp extends AbstractResource implements ResourceInterface, ResourceShowCou
#[ORM\Column(name: 'duration', type: 'integer', nullable: true)]
protected ?int $duration = null;
#[ORM\Column(name: 'validity_in_days', type: 'integer', nullable: true)]
protected ?int $validityInDays = null;
public function __construct()
{
$now = new DateTime();
@ -650,17 +647,6 @@ class CLp extends AbstractResource implements ResourceInterface, ResourceShowCou
return $this;
}
public function getValidityInDays(): ?int
{
return $this->validityInDays;
}
public function setValidityInDays(?int $validityInDays): self
{
$this->validityInDays = $validityInDays;
return $this;
}
public function getResourceIdentifier(): int|Uuid
{
return $this->getIid();

@ -138,23 +138,4 @@ final class CLpRepository extends ResourceRepository implements ResourceWithLink
return null;
}
public function findExpiredViews(int $validityDays): array
{
$now = new \DateTime();
$expirationDate = (clone $now)->modify('-' . $validityDays . ' days');
return $this->getEntityManager()
->createQueryBuilder()
->select('v')
->from('Chamilo\CourseBundle\Entity\CLpView', 'v')
->join('v.lp', 'lp')
->where('lp.validityInDays > 0')
->andWhere('v.progress = 100')
->andWhere('v.session IS NOT NULL')
->andWhere('v.lastItem < :expirationDate')
->setParameter('expirationDate', $expirationDate->getTimestamp())
->getQuery()
->getResult();
}
}

Loading…
Cancel
Save