1<?php 2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */ 3 4require_once "./Services/Object/classes/class.ilObject.php"; 5require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLocker.php'; 6 7/** 8 * Class ilObjAssessmentFolder 9 * 10 * @author Helmut Schottmüller <hschottm@gmx.de> 11 * @author Björn Heyser <bheyser@databay.de> 12 * 13 * @version $Id$ 14 * 15 * @ingroup ModulesTest 16 */ 17class ilObjAssessmentFolder extends ilObject 18{ 19 const ADDITIONAL_QUESTION_CONTENT_EDITING_MODE_PAGE_OBJECT_DISABLED = 0; 20 const ADDITIONAL_QUESTION_CONTENT_EDITING_MODE_PAGE_OBJECT_ENABLED = 1; 21 22 const ASS_PROC_LOCK_MODE_NONE = 'none'; 23 const ASS_PROC_LOCK_MODE_FILE = 'file'; 24 const ASS_PROC_LOCK_MODE_DB = 'db'; 25 26 const SETTINGS_KEY_SKL_TRIG_NUM_ANSWERS_BARRIER = 'ass_skl_trig_num_answ_barrier'; 27 const DEFAULT_SKL_TRIG_NUM_ANSWERS_BARRIER = 1; 28 29 public $setting; 30 31 /** 32 * Constructor 33 * @access public 34 * @param integer reference_id or object_id 35 * @param boolean treat the id as reference_id (true) or object_id (false) 36 */ 37 public function __construct($a_id = 0, $a_call_by_reference = true) 38 { 39 include_once "./Services/Administration/classes/class.ilSetting.php"; 40 $this->setting = new ilSetting("assessment"); 41 $this->type = "assf"; 42 parent::__construct($a_id, $a_call_by_reference); 43 } 44 45 /** 46 * update object data 47 * 48 * @access public 49 * @return boolean 50 */ 51 public function update() 52 { 53 if (!parent::update()) { 54 return false; 55 } 56 57 // put here object specific stuff 58 59 return true; 60 } 61 62 public static function getSkillTriggerAnswerNumberBarrier() 63 { 64 require_once 'Services/Administration/classes/class.ilSetting.php'; 65 $assSettings = new ilSetting('assessment'); 66 67 return $assSettings->get( 68 self::SETTINGS_KEY_SKL_TRIG_NUM_ANSWERS_BARRIER, 69 self::DEFAULT_SKL_TRIG_NUM_ANSWERS_BARRIER 70 ); 71 } 72 73 /** 74 * delete object and all related data 75 * 76 * @access public 77 * @return boolean true if all object data were removed; false if only a references were removed 78 */ 79 public function delete() 80 { 81 // always call parent delete function first!! 82 if (!parent::delete()) { 83 return false; 84 } 85 86 //put here your module specific stuff 87 88 return true; 89 } 90 91 /** 92 * enable assessment logging 93 */ 94 public function _enableAssessmentLogging($a_enable) 95 { 96 $setting = new ilSetting("assessment"); 97 98 if ($a_enable) { 99 $setting->set("assessment_logging", 1); 100 } else { 101 $setting->set("assessment_logging", 0); 102 } 103 } 104 105 /** 106 * set the log language 107 */ 108 public function _setLogLanguage($a_language) 109 { 110 $setting = new ilSetting("assessment"); 111 112 $setting->set("assessment_log_language", $a_language); 113 } 114 115 /** 116 * check wether assessment logging is enabled or not 117 */ 118 public static function _enabledAssessmentLogging() 119 { 120 $setting = new ilSetting("assessment"); 121 122 return (boolean) $setting->get("assessment_logging"); 123 } 124 125 /** 126 * Returns the forbidden questiontypes for ILIAS 127 */ 128 public static function _getForbiddenQuestionTypes() 129 { 130 $setting = new ilSetting("assessment"); 131 $types = $setting->get("forbidden_questiontypes"); 132 $result = array(); 133 if (strlen(trim($types)) == 0) { 134 $result = array(); 135 } else { 136 $result = unserialize($types); 137 } 138 return $result; 139 } 140 141 /** 142 * Sets the forbidden questiontypes for ILIAS 143 * 144 * @param array $a_types An array containing the database ID's of the forbidden question types 145 */ 146 public function _setForbiddenQuestionTypes($a_types) 147 { 148 $setting = new ilSetting("assessment"); 149 $types = ""; 150 if (is_array($a_types) && (count($a_types) > 0)) { 151 $types = serialize($a_types); 152 } 153 $setting->set("forbidden_questiontypes", $types); 154 } 155 156 /** 157 * retrieve the log language for assessment logging 158 */ 159 public static function _getLogLanguage() 160 { 161 $setting = new ilSetting("assessment"); 162 163 $lang = $setting->get("assessment_log_language"); 164 if (strlen($lang) == 0) { 165 $lang = "en"; 166 } 167 return $lang; 168 } 169 170 /** 171 * Returns the fact wether manually scoreable 172 * question types exist or not 173 * 174 * @static 175 * @access public 176 * 177 * @return boolean $mananuallyScoreableQuestionTypesExists 178 */ 179 public static function _mananuallyScoreableQuestionTypesExists() 180 { 181 if (count(self::_getManualScoring()) > 0) { 182 return true; 183 } 184 185 return false; 186 } 187 188 /** 189 * Retrieve the manual scoring settings 190 */ 191 public static function _getManualScoring() 192 { 193 $setting = new ilSetting("assessment"); 194 195 $types = $setting->get("assessment_manual_scoring"); 196 return explode(",", $types); 197 } 198 199 /** 200 * Retrieve the manual scoring settings as type strings 201 */ 202 public static function _getManualScoringTypes() 203 { 204 global $DIC; 205 $ilDB = $DIC['ilDB']; 206 207 $result = $ilDB->query("SELECT * FROM qpl_qst_type"); 208 $dbtypes = array(); 209 while ($row = $ilDB->fetchAssoc($result)) { 210 $dbtypes[$row["question_type_id"]] = $row["type_tag"]; 211 } 212 $setting = new ilSetting("assessment"); 213 $types = $setting->get("assessment_manual_scoring"); 214 $ids = explode(",", $types); 215 foreach ($ids as $key => $value) { 216 $ids[$key] = $dbtypes[$value]; 217 } 218 return $ids; 219 } 220 221 /** 222 * Set the manual scoring settings 223 * 224 * @param array $type_ids An array containing the database ids of the question types which could be scored manually 225 */ 226 public function _setManualScoring($type_ids) 227 { 228 $setting = new ilSetting("assessment"); 229 if ((!is_array($type_ids)) || (count($type_ids) == 0)) { 230 $setting->delete("assessment_manual_scoring"); 231 } else { 232 $setting->set("assessment_manual_scoring", implode(",", $type_ids)); 233 } 234 } 235 236 public static function getScoringAdjustableQuestions() 237 { 238 $setting = new ilSetting("assessment"); 239 240 $types = $setting->get("assessment_scoring_adjustment"); 241 return explode(",", $types); 242 } 243 244 public static function setScoringAdjustableQuestions($type_ids) 245 { 246 $setting = new ilSetting("assessment"); 247 if ((!is_array($type_ids)) || (count($type_ids) == 0)) { 248 $setting->delete("assessment_scoring_adjustment"); 249 } else { 250 $setting->set("assessment_scoring_adjustment", implode(",", $type_ids)); 251 } 252 } 253 254 public static function getScoringAdjustmentEnabled() 255 { 256 $setting = new ilSetting("assessment"); 257 return $setting->get('assessment_adjustments_enabled'); 258 } 259 260 public static function setScoringAdjustmentEnabled($active) 261 { 262 $setting = new ilSetting('assessment'); 263 $setting->set('assessment_adjustments_enabled', (bool) $active); 264 } 265 266 /** 267 * Add an assessment log entry 268 * 269 * @param integer $user_id The user id of the acting user 270 * @param integer $object_id The database id of the modified test object 271 * @param string $logtext The textual description for the log entry 272 * @param integer $question_id The database id of a modified question (optional) 273 * @param integer $original_id The database id of the original of a modified question (optional) 274 * @return array Array containing the datasets between $ts_from and $ts_to for the test with the id $test_id 275 */ 276 public static function _addLog($user_id, $object_id, $logtext, $question_id = "", $original_id = "", $test_only = false, $test_ref_id = null) 277 { 278 global $DIC; 279 $ilUser = $DIC['ilUser']; 280 $ilDB = $DIC['ilDB']; 281 if (strlen($question_id) == 0) { 282 $question_id = null; 283 } 284 if (strlen($original_id) == 0) { 285 $original_id = null; 286 } 287 if (strlen($test_ref_id) == 0) { 288 $test_ref_id = null; 289 } 290 $only = ($test_only == true) ? 1 : 0; 291 $next_id = $ilDB->nextId('ass_log'); 292 $affectedRows = $ilDB->manipulateF( 293 "INSERT INTO ass_log (ass_log_id, user_fi, obj_fi, logtext, question_fi, original_fi, test_only, ref_id, tstamp) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)", 294 array('integer', 'integer', 'integer', 'text', 'integer', 'integer', 'text', 'integer', 'integer'), 295 array( 296 $next_id, 297 $user_id, 298 $object_id, 299 $logtext, 300 $question_id, 301 $original_id, 302 $only, 303 $test_ref_id, 304 time() 305 ) 306 ); 307 } 308 309 /** 310 * Retrieve assessment log datasets from the database 311 * 312 * @param string $ts_from Timestamp of the starting date/time period 313 * @param string $ts_to Timestamp of the ending date/time period 314 * @param integer $test_id Database id of the ILIAS test object 315 * @return array Array containing the datasets between $ts_from and $ts_to for the test with the id $test_id 316 */ 317 public static function getLog($ts_from, $ts_to, $test_id, $test_only = false) 318 { 319 global $DIC; 320 $ilDB = $DIC['ilDB']; 321 322 $log = array(); 323 if ($test_only == true) { 324 $result = $ilDB->queryF( 325 "SELECT * FROM ass_log WHERE obj_fi = %s AND tstamp > %s AND tstamp < %s AND test_only = %s ORDER BY tstamp", 326 array('integer','integer','integer','text'), 327 array( 328 $test_id, 329 $ts_from, 330 $ts_to, 331 1 332 ) 333 ); 334 } else { 335 $result = $ilDB->queryF( 336 "SELECT * FROM ass_log WHERE obj_fi = %s AND tstamp > %s AND tstamp < %s ORDER BY tstamp", 337 array('integer','integer','integer'), 338 array( 339 $test_id, 340 $ts_from, 341 $ts_to 342 ) 343 ); 344 } 345 while ($row = $ilDB->fetchAssoc($result)) { 346 if (!array_key_exists($row["tstamp"], $log)) { 347 $log[$row["tstamp"]] = array(); 348 } 349 array_push($log[$row["tstamp"]], $row); 350 } 351 krsort($log); 352 // flatten array 353 $log_array = array(); 354 foreach ($log as $key => $value) { 355 foreach ($value as $index => $row) { 356 array_push($log_array, $row); 357 } 358 } 359 return $log_array; 360 } 361 362 /** 363 * Retrieve assessment log datasets from the database 364 * 365 * @param string $ts_from Timestamp of the starting date/time period 366 * @param string $ts_to Timestamp of the ending date/time period 367 * @param integer $test_id Database id of the ILIAS test object 368 * @return array Array containing the datasets between $ts_from and $ts_to for the test with the id $test_id 369 */ 370 public static function _getLog($ts_from, $ts_to, $test_id, $test_only = false) 371 { 372 global $DIC; 373 $ilDB = $DIC['ilDB']; 374 375 $log = array(); 376 if ($test_only == true) { 377 $result = $ilDB->queryF( 378 "SELECT * FROM ass_log WHERE obj_fi = %s AND tstamp > %s AND tstamp < %s AND test_only = %s ORDER BY tstamp", 379 array('integer', 'integer', 'integer', 'text'), 380 array($test_id, $ts_from, $ts_to, 1) 381 ); 382 } else { 383 $result = $ilDB->queryF( 384 "SELECT * FROM ass_log WHERE obj_fi = %s AND tstamp > %s AND tstamp < %s ORDER BY tstamp", 385 array('integer', 'integer', 'integer'), 386 array($test_id, $ts_from, $ts_to) 387 ); 388 } 389 while ($row = $ilDB->fetchAssoc($result)) { 390 if (!array_key_exists($row["tstamp"], $log)) { 391 $log[$row["tstamp"]] = array(); 392 } 393 $type_href = ""; 394 if (array_key_exists("ref_id", $row)) { 395 if ($row["ref_id"] > 0) { 396 $type = ilObject::_lookupType($row['ref_id'], true); 397 switch ($type) { 398 case "tst": 399 $type_href = sprintf("goto.php?target=tst_%s&client_id=" . CLIENT_ID, $row["ref_id"]); 400 break; 401 case "cat": 402 $type_href = sprintf("goto.php?target=cat_%s&client_id=" . CLIENT_ID, $row["ref_id"]); 403 break; 404 } 405 } 406 } 407 $row["href"] = $type_href; 408 array_push($log[$row["tstamp"]], $row); 409 } 410 krsort($log); 411 // flatten array 412 $log_array = array(); 413 foreach ($log as $key => $value) { 414 foreach ($value as $index => $row) { 415 array_push($log_array, $row); 416 } 417 } 418 return $log_array; 419 } 420 421 /** 422 * Returns the number of log entries for a given test id 423 * 424 * @param integer $test_obj_id Database id of the ILIAS test object 425 * @return integer The number of log entries for the test object 426 */ 427 public function getNrOfLogEntries($test_obj_id) 428 { 429 global $DIC; 430 $ilDB = $DIC['ilDB']; 431 $result = $ilDB->queryF( 432 "SELECT COUNT(obj_fi) logcount FROM ass_log WHERE obj_fi = %s", 433 array('integer'), 434 array($test_obj_id) 435 ); 436 if ($result->numRows()) { 437 $row = $ilDB->fetchAssoc($result); 438 return $row["logcount"]; 439 } else { 440 return 0; 441 } 442 } 443 444 /** 445 * Returns the full path output of an object 446 * 447 * @param integer $ref_id The reference id of the object 448 * @return string The full path with hyperlinks to the path elements 449 */ 450 public function getFullPath($ref_id) 451 { 452 global $DIC; 453 $tree = $DIC['tree']; 454 $path = $tree->getPathFull($ref_id); 455 $pathelements = array(); 456 foreach ($path as $id => $data) { 457 if ($id == 0) { 458 array_push($pathelements, ilUtil::prepareFormOutput($this->lng->txt("repository"))); 459 } else { 460 array_push($pathelements, "<a href=\"./goto.php?target=" . $data["type"] . "_" . $data["ref_id"] . "&client=" . CLIENT_ID . "\">" . 461 ilUtil::prepareFormOutput($data["title"]) . "</a>"); 462 } 463 } 464 return implode(" > ", $pathelements); 465 } 466 467 /** 468 * Deletes the log entries for a given array of test object IDs 469 * 470 * @param array $a_array An array containing the object IDs of the tests 471 */ 472 public function deleteLogEntries($a_array) 473 { 474 global $DIC; 475 $ilDB = $DIC['ilDB']; 476 $ilUser = $DIC['ilUser']; 477 478 foreach ($a_array as $object_id) { 479 $affectedRows = $ilDB->manipulateF( 480 "DELETE FROM ass_log WHERE obj_fi = %s", 481 array('integer'), 482 array($object_id) 483 ); 484 self::_addLog($ilUser->getId(), $object_id, $this->lng->txt("assessment_log_deleted")); 485 } 486 } 487 488 /** 489 * returns the fact wether content editing with ilias page editor is enabled for questions or not 490 * 491 * @global ilSetting $ilSetting 492 * @return bool $isPageEditorEnabled 493 */ 494 public static function isAdditionalQuestionContentEditingModePageObjectEnabled() 495 { 496 require_once 'Modules/TestQuestionPool/classes/class.assQuestion.php'; 497 498 global $DIC; 499 $ilSetting = $DIC['ilSetting']; 500 501 $isPageEditorEnabled = $ilSetting->get( 502 'enable_tst_page_edit', 503 self::ADDITIONAL_QUESTION_CONTENT_EDITING_MODE_PAGE_OBJECT_DISABLED 504 ); 505 506 return $isPageEditorEnabled; 507 } 508 509 public function getAssessmentProcessLockMode() 510 { 511 return $this->setting->get('ass_process_lock_mode', self::ASS_PROC_LOCK_MODE_NONE); 512 } 513 514 public function setAssessmentProcessLockMode($lockMode) 515 { 516 $this->setting->set('ass_process_lock_mode', $lockMode); 517 } 518 519 public static function getValidAssessmentProcessLockModes() 520 { 521 return array(self::ASS_PROC_LOCK_MODE_NONE, self::ASS_PROC_LOCK_MODE_FILE, self::ASS_PROC_LOCK_MODE_DB); 522 } 523 524 public function getSkillTriggeringNumAnswersBarrier() 525 { 526 return $this->setting->get( 527 'ass_skl_trig_num_answ_barrier', 528 self::DEFAULT_SKL_TRIG_NUM_ANSWERS_BARRIER 529 ); 530 } 531 532 public function setSkillTriggeringNumAnswersBarrier($skillTriggeringNumAnswersBarrier) 533 { 534 $this->setting->set('ass_skl_trig_num_answ_barrier', $skillTriggeringNumAnswersBarrier); 535 } 536 537 public function setExportEssayQuestionsWithHtml($value) 538 { 539 $this->setting->set('export_essay_qst_with_html', $value); 540 } 541 542 public function getExportEssayQuestionsWithHtml() 543 { 544 return $this->setting->get('export_essay_qst_with_html'); 545 } 546 547 public function fetchScoringAdjustableTypes($allQuestionTypes) 548 { 549 require_once 'Modules/TestQuestionPool/classes/class.assQuestionGUI.php'; 550 $scoringAdjustableQuestionTypes = array(); 551 552 foreach ($allQuestionTypes as $type => $typeData) { 553 $questionGui = assQuestionGUI::_getQuestionGUI($typeData['type_tag']); 554 555 if ($this->questionSupportsScoringAdjustment($questionGui)) { 556 $scoringAdjustableQuestionTypes[$type] = $typeData; 557 } 558 } 559 560 return $scoringAdjustableQuestionTypes; 561 } 562 563 private function questionSupportsScoringAdjustment(\assQuestionGUI $question_object) 564 { 565 return ($question_object instanceof ilGuiQuestionScoringAdjustable 566 || $question_object instanceof ilGuiAnswerScoringAdjustable) 567 && ($question_object->object instanceof ilObjQuestionScoringAdjustable 568 || $question_object->object instanceof ilObjAnswerScoringAdjustable); 569 } 570} 571