1<?php 2require_once 'Services/Cron/classes/class.ilCronJob.php'; 3require_once 'Services/Cron/classes/class.ilCronJobResult.php'; 4require_once 'Modules/Test/classes/class.ilObjTest.php'; 5require_once 'Modules/Test/classes/class.ilTestPassFinishTasks.php'; 6require_once 'Services/Logging/classes/public/class.ilLoggerFactory.php'; 7 8/* Copyright (c) 1998-2016 ILIAS open source, Extended GPL, see docs/LICENSE */ 9 10/** 11 * Class ilCronFinishUnfinishedTestPasses 12 * @author Guido Vollbach <gvollbach@databay.de> 13 */ 14class ilCronFinishUnfinishedTestPasses extends ilCronJob 15{ 16 17 /** 18 * @var ilLogger 19 */ 20 protected $log; 21 22 /** 23 * @var $lng ilLanguage 24 */ 25 protected $lng; 26 27 /** 28 * @var $ilDB ilDB 29 */ 30 protected $db; 31 32 /** 33 * @var $ilObjDataCache ilObjectDataCache 34 */ 35 protected $obj_data_cache; 36 37 /** 38 * @var int 39 */ 40 protected $now; 41 42 protected $unfinished_passes; 43 44 protected $test_ids; 45 46 protected $test_ending_times; 47 48 /** 49 * @var ilTestProcessLockerFactory 50 */ 51 protected $processLockerFactory; 52 53 /** 54 * Constructor 55 */ 56 public function __construct() 57 { 58 /** 59 * @var $ilDB ilDB 60 * @var $ilObjDataCache ilObjectDataCache 61 */ 62 63 global $DIC; 64 $ilObjDataCache = $DIC['ilObjDataCache']; 65 $lng = $DIC['lng']; 66 $ilDB = $DIC['ilDB']; 67 68 global $DIC; /* @var ILIAS\DI\Container $DIC */ 69 70 $this->log = ilLoggerFactory::getLogger('tst'); 71 $this->lng = $lng; 72 $this->lng->loadLanguageModule('assessment'); 73 $this->db = $ilDB; 74 $this->obj_data_cache = $ilObjDataCache; 75 $this->now = time(); 76 $this->unfinished_passes = array(); 77 $this->test_ids = array(); 78 $this->test_ending_times = array(); 79 80 require_once 'Modules/Test/classes/class.ilTestProcessLockerFactory.php'; 81 $this->processLockerFactory = new ilTestProcessLockerFactory( 82 new ilSetting('assessment'), 83 $DIC->database() 84 ); 85 } 86 87 public function getId() 88 { 89 return 'finish_unfinished_passes'; 90 } 91 92 public function getTitle() 93 { 94 global $DIC; 95 $lng = $DIC['lng']; 96 97 return $lng->txt("finish_unfinished_passes"); 98 } 99 100 public function getDescription() 101 { 102 global $DIC; 103 $lng = $DIC['lng']; 104 105 return $lng->txt("finish_unfinished_passes_desc"); 106 } 107 108 public function getDefaultScheduleType() 109 { 110 return self::SCHEDULE_TYPE_DAILY; 111 } 112 113 public function getDefaultScheduleValue() 114 { 115 return; 116 } 117 118 public function hasAutoActivation() 119 { 120 return false; 121 } 122 123 public function hasFlexibleSchedule() 124 { 125 return true; 126 } 127 128 public function hasCustomSettings() 129 { 130 return true; 131 } 132 133 public function run() 134 { 135 $this->log->info('start inf cronjob...'); 136 137 $result = new ilCronJobResult(); 138 139 $this->gatherUsersWithUnfinishedPasses(); 140 if (count($this->unfinished_passes) > 0) { 141 $this->log->info('found ' . count($this->unfinished_passes) . ' unfinished passes starting analyses.'); 142 $this->getTestsFinishAndProcessingTime(); 143 $this->processPasses(); 144 } else { 145 $this->log->info('No unfinished passes found.'); 146 } 147 148 $result->setStatus(ilCronJobResult::STATUS_OK); 149 150 $this->log->info(' ...finishing cronjob.'); 151 152 return $result; 153 } 154 155 protected function gatherUsersWithUnfinishedPasses() 156 { 157 $query = "SELECT tst_active.active_id, 158 tst_active.tries, 159 tst_active.user_fi usr_id, 160 tst_active.test_fi test_fi, 161 usr_data.login, 162 usr_data.lastname, 163 usr_data.firstname, 164 tst_active.submitted test_finished, 165 usr_data.matriculation, 166 usr_data.active, 167 tst_active.lastindex, 168 tst_active.last_started_pass last_started 169 FROM tst_active 170 LEFT JOIN usr_data 171 ON tst_active.user_fi = usr_data.usr_id 172 WHERE IFNULL(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass 173 "; 174 $result = $this->db->query($query); 175 while ($row = $this->db->fetchAssoc($result)) { 176 $this->unfinished_passes[] = $row; 177 $this->test_ids[] = $row['test_fi']; 178 } 179 } 180 181 protected function getTestsFinishAndProcessingTime() 182 { 183 $query = 'SELECT test_id, obj_fi, ending_time, ending_time_enabled, processing_time, enable_processing_time FROM tst_tests WHERE ' . 184 $this->db->in('test_id', $this->test_ids, false, 'integer'); 185 $result = $this->db->query($query); 186 while ($row = $this->db->fetchAssoc($result)) { 187 $this->test_ending_times[$row['test_id']] = $row; 188 } 189 $this->log->info('Gathered data for ' . count($this->test_ids) . ' test id(s) => (' . implode(',', $this->test_ids) . ')'); 190 } 191 192 protected function processPasses() 193 { 194 $now = time(); 195 foreach ($this->unfinished_passes as $key => $data) { 196 $test_id = $data['test_fi']; 197 $can_not_be_finished = true; 198 if (array_key_exists($test_id, $this->test_ending_times)) { 199 if ($this->test_ending_times[$test_id]['ending_time_enabled'] == 1) { 200 $this->log->info('Test (' . $test_id . ') has ending time (' . $this->test_ending_times[$test_id]['ending_time'] . ')'); 201 $ending_time = $this->test_ending_times[$test_id]['ending_time']; 202 if ($ending_time < $now) { 203 $this->finishPassForUser($data['active_id'], $this->test_ending_times[$test_id]['obj_fi']); 204 $can_not_be_finished = false; 205 } else { 206 $this->log->info('Test (' . $test_id . ') ending time (' . $this->test_ending_times[$test_id]['ending_time'] . ') > now (' . $now . ') is not reached.'); 207 } 208 } else { 209 $this->log->info('Test (' . $test_id . ') has no ending time.'); 210 } 211 if ($this->test_ending_times[$test_id]['enable_processing_time'] == 1) { 212 $this->log->info('Test (' . $test_id . ') has processing time (' . $this->test_ending_times[$test_id]['processing_time'] . ')'); 213 $obj_id = $this->test_ending_times[$test_id]['obj_fi']; 214 $test_obj = new ilObjTest($obj_id, false); 215 $startingTime = $test_obj->getStartingTimeOfUser($data['active_id'], $data['last_started_pass']); 216 $max_processing_time = $test_obj->isMaxProcessingTimeReached($startingTime, $data['active_id']); 217 if ($max_processing_time) { 218 $this->log->info('Max Processing time reached for user id (' . $data['usr_id'] . ') so test with active id (' . $data['active_id'] . ') will be finished.'); 219 $this->finishPassForUser($data['active_id'], $this->test_ending_times[$test_id]['obj_fi']); 220 $can_not_be_finished = false; 221 } 222 } else { 223 $this->log->info('Test (' . $test_id . ') has no processing time.'); 224 } 225 226 if ($can_not_be_finished) { 227 $this->log->info('Test session with active id (' . $data['active_id'] . ') can not be finished by this cron job.'); 228 } 229 } 230 } 231 } 232 233 protected function finishPassForUser($active_id, $obj_id) 234 { 235 $this->processLockerFactory->setActiveId($active_id); 236 $processLocker = $this->processLockerFactory->getLocker(); 237 238 $pass_finisher = new ilTestPassFinishTasks($active_id, $obj_id); 239 $pass_finisher->performFinishTasks($processLocker); 240 241 $this->log->info('Test session with active id (' . $active_id . ') and obj_id (' . $obj_id . ') is now finished.'); 242 } 243} 244