1<?php 2/* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */ 3 4/** @defgroup ModulesExercise Modules/Exercise 5 */ 6 7/** 8* Class ilObjExercise 9* 10* @author Stefan Meyer <meyer@leifos.com> 11* @author Michael Jansen <mjansen@databay.de> 12* 13* @ingroup ModulesExercise 14*/ 15class ilObjExercise extends ilObject 16{ 17 /** 18 * @var ilObjUser 19 */ 20 protected $user; 21 22 public $file_obj; 23 public $members_obj; 24 public $files; 25 26 public $timestamp; 27 public $hour; 28 public $minutes; 29 public $day; 30 public $month; 31 public $year; 32 public $instruction; 33 public $certificate_visibility; 34 35 public $tutor_feedback = 7; // [int] 36 37 /** 38 * @var int number of mandatory assignments in random pass mode 39 */ 40 protected $nr_random_mand; 41 42 const TUTOR_FEEDBACK_MAIL = 1; 43 const TUTOR_FEEDBACK_TEXT = 2; 44 const TUTOR_FEEDBACK_FILE = 4; 45 46 const PASS_MODE_NR = "nr"; 47 const PASS_MODE_ALL = "all"; 48 const PASS_MODE_RANDOM = "random"; 49 50 /** 51 * 52 * Indicates whether completion by submission is enabled or not 53 * 54 * @var boolean 55 * @access protected 56 * 57 */ 58 protected $completion_by_submission = false; 59 60 /** 61 * @var \ILIAS\Filesystem\Filesystem 62 */ 63 private $webFilesystem; 64 65 /** 66 * @var ilExcMandatoryAssignmentManager 67 */ 68 protected $mandatory_manager; 69 70 /** 71 * Constructor 72 * @access public 73 * @param integer reference_id or object_id 74 * @param boolean treat the id as reference_id (true) or object_id (false) 75 */ 76 public function __construct($a_id = 0, $a_call_by_reference = true) 77 { 78 global $DIC; 79 80 $this->db = $DIC->database(); 81 $this->app_event_handler = $DIC["ilAppEventHandler"]; 82 $this->lng = $DIC->language(); 83 $this->user = $DIC->user(); 84 $this->setPassMode("all"); 85 $this->type = "exc"; 86 $this->webFilesystem = $DIC->filesystem()->web(); 87 88 parent::__construct($a_id, $a_call_by_reference); 89 $this->mandatory_manager = $DIC->exercise()->internal()->service()->getMandatoryAssignmentManager($this); 90 } 91 92 /** 93 * Set id 94 * @param int $id 95 */ 96 public function setId($id) 97 { 98 global $DIC; 99 parent::setId($id); 100 // this is needed, since e.g. ilObjectFactory initialises the object with id 0 and later sets the id 101 $this->mandatory_manager = $DIC->exercise()->internal()->service()->getMandatoryAssignmentManager($this); 102 } 103 104 // SET, GET METHODS 105 public function setDate($a_hour, $a_minutes, $a_day, $a_month, $a_year) 106 { 107 $this->hour = (int) $a_hour; 108 $this->minutes = (int) $a_minutes; 109 $this->day = (int) $a_day; 110 $this->month = (int) $a_month; 111 $this->year = (int) $a_year; 112 $this->timestamp = mktime($this->hour, $this->minutes, 0, $this->month, $this->day, $this->year); 113 return true; 114 } 115 public function getTimestamp() 116 { 117 return $this->timestamp; 118 } 119 public function setTimestamp($a_timestamp) 120 { 121 $this->timestamp = $a_timestamp; 122 } 123 public function setInstruction($a_instruction) 124 { 125 $this->instruction = $a_instruction; 126 } 127 public function getInstruction() 128 { 129 return $this->instruction; 130 } 131 132 /** 133 * Set pass mode (all | nr) 134 * 135 * @param string pass mode 136 */ 137 public function setPassMode($a_val) 138 { 139 $this->pass_mode = $a_val; 140 } 141 142 /** 143 * Get pass mode (all | nr) 144 * 145 * @return string pass mode 146 */ 147 public function getPassMode() 148 { 149 return $this->pass_mode; 150 } 151 152 /** 153 * Set number of assignments that must be passed to pass the exercise 154 * 155 * @param integer pass nr 156 */ 157 public function setPassNr($a_val) 158 { 159 $this->pass_nr = $a_val; 160 } 161 162 /** 163 * Get number of assignments that must be passed to pass the exercise 164 * 165 * @return integer pass nr 166 */ 167 public function getPassNr() 168 { 169 return $this->pass_nr; 170 } 171 172 /** 173 * Set whether submissions of learners should be shown to other learners after deadline 174 * 175 * @param boolean show submissions 176 */ 177 public function setShowSubmissions($a_val) 178 { 179 $this->show_submissions = $a_val; 180 } 181 182 /** 183 * Get whether submissions of learners should be shown to other learners after deadline 184 * 185 * @return integer show submissions 186 */ 187 public function getShowSubmissions() 188 { 189 return $this->show_submissions; 190 } 191 192 /** 193 * Set number of mandatory assignments in random pass mode 194 * 195 * @param int $a_val 196 */ 197 public function setNrMandatoryRandom($a_val) 198 { 199 $this->nr_random_mand = $a_val; 200 } 201 202 /** 203 * Get number of mandatory assignments in random pass mode 204 * 205 * @return int 206 */ 207 public function getNrMandatoryRandom() 208 { 209 return $this->nr_random_mand; 210 } 211 212 213 /* function getFiles() 214 { 215 return $this->files; 216 }*/ 217 218 public function checkDate() 219 { 220 return $this->hour == (int) date("H", $this->timestamp) and 221 $this->minutes == (int) date("i", $this->timestamp) and 222 $this->day == (int) date("d", $this->timestamp) and 223 $this->month == (int) date("m", $this->timestamp) and 224 $this->year == (int) date("Y", $this->timestamp); 225 } 226 227 public function hasTutorFeedbackText() 228 { 229 return $this->tutor_feedback & self::TUTOR_FEEDBACK_TEXT; 230 } 231 232 public function hasTutorFeedbackMail() 233 { 234 return $this->tutor_feedback & self::TUTOR_FEEDBACK_MAIL; 235 } 236 237 public function hasTutorFeedbackFile() 238 { 239 return $this->tutor_feedback & self::TUTOR_FEEDBACK_FILE; 240 } 241 242 protected function getTutorFeedback() 243 { 244 return $this->tutor_feedback; 245 } 246 247 public function setTutorFeedback($a_value) 248 { 249 $this->tutor_feedback = $a_value; 250 } 251 252 public function saveData() 253 { 254 $ilDB = $this->db; 255 256 $ilDB->insert("exc_data", array( 257 "obj_id" => array("integer", $this->getId()), 258 "instruction" => array("clob", $this->getInstruction()), 259 "time_stamp" => array("integer", $this->getTimestamp()), 260 "pass_mode" => array("text", $this->getPassMode()), 261 "nr_mandatory_random" => array("integer", (int) $this->getNrMandatoryRandom()), 262 "pass_nr" => array("text", $this->getPassNr()), 263 "show_submissions" => array("integer", (int) $this->getShowSubmissions()), 264 'compl_by_submission' => array('integer', (int) $this->isCompletionBySubmissionEnabled()), 265 "certificate_visibility" => array("integer", (int) $this->getCertificateVisibility()), 266 "tfeedback" => array("integer", (int) $this->getTutorFeedback()) 267 )); 268 return true; 269 } 270 271 /** 272 * Clone exercise (no member data) 273 * 274 * @access public 275 * @param int target ref_id 276 * @param int copy id 277 */ 278 public function cloneObject($a_target_id, $a_copy_id = 0, $a_omit_tree = false) 279 { 280 $ilDB = $this->db; 281 282 // Copy settings 283 $new_obj = parent::cloneObject($a_target_id, $a_copy_id, $a_omit_tree); 284 $new_obj->setInstruction($this->getInstruction()); 285 $new_obj->setTimestamp($this->getTimestamp()); 286 $new_obj->setPassMode($this->getPassMode()); 287 $new_obj->setNrMandatoryRandom($this->getNrMandatoryRandom()); 288 $new_obj->saveData(); 289 $new_obj->setPassNr($this->getPassNr()); 290 $new_obj->setShowSubmissions($this->getShowSubmissions()); 291 $new_obj->setCompletionBySubmission($this->isCompletionBySubmissionEnabled()); 292 $new_obj->setTutorFeedback($this->getTutorFeedback()); 293 $new_obj->setCertificateVisibility($this->getCertificateVisibility()); 294 $new_obj->update(); 295 296 $new_obj->saveCertificateVisibility($this->getCertificateVisibility()); 297 298 // Copy criteria catalogues 299 $crit_cat_map = array(); 300 foreach (ilExcCriteriaCatalogue::getInstancesByParentId($this->getId()) as $crit_cat) { 301 $new_id = $crit_cat->cloneObject($new_obj->getId()); 302 $crit_cat_map[$crit_cat->getId()] = $new_id; 303 } 304 305 // Copy assignments 306 ilExAssignment::cloneAssignmentsOfExercise($this->getId(), $new_obj->getId(), $crit_cat_map); 307 308 // Copy learning progress settings 309 $obj_settings = new ilLPObjSettings($this->getId()); 310 $obj_settings->cloneSettings($new_obj->getId()); 311 unset($obj_settings); 312 313 $pathFactory = new ilCertificatePathFactory(); 314 $templateRepository = new ilCertificateTemplateRepository($ilDB); 315 316 $cloneAction = new ilCertificateCloneAction( 317 $ilDB, 318 $pathFactory, 319 $templateRepository, 320 $this->webFilesystem, 321 $this->log, 322 new ilCertificateObjectHelper() 323 ); 324 325 $cloneAction->cloneCertificate($this, $new_obj); 326 327 // additional features 328 foreach (ilContainer::_getContainerSettings($this->getId()) as $keyword => $value) { 329 ilContainer::_writeContainerSetting($new_obj->getId(), $keyword, $value); 330 } 331 332 // org unit setting 333 $orgu_object_settings = new ilOrgUnitObjectPositionSetting($new_obj->getId()); 334 $orgu_object_settings->setActive( 335 (int) ilOrgUnitGlobalSettings::getInstance()->isPositionAccessActiveForObject($this->getId()) 336 ); 337 $orgu_object_settings->update(); 338 339 return $new_obj; 340 } 341 342 /** 343 * delete course and all related data 344 * 345 * @access public 346 * @return boolean true if all object data were removed; false if only a references were removed 347 */ 348 public function delete() 349 { 350 $ilDB = $this->db; 351 $ilAppEventHandler = $this->app_event_handler; 352 353 // always call parent delete function first!! 354 if (!parent::delete()) { 355 return false; 356 } 357 // put here course specific stuff 358 $ilDB->manipulate("DELETE FROM exc_data " . 359 "WHERE obj_id = " . $ilDB->quote($this->getId(), "integer")); 360 361 ilExcCriteriaCatalogue::deleteByParent($this->getId()); 362 363 // remove all notifications 364 ilNotification::removeForObject(ilNotification::TYPE_EXERCISE_SUBMISSION, $this->getId()); 365 366 $ilAppEventHandler->raise( 367 'Modules/Exercise', 368 'delete', 369 array('obj_id' => $this->getId()) 370 ); 371 372 return true; 373 } 374 375 public function read() 376 { 377 $ilDB = $this->db; 378 379 parent::read(); 380 381 $query = "SELECT * FROM exc_data " . 382 "WHERE obj_id = " . $ilDB->quote($this->getId(), "integer"); 383 384 $res = $ilDB->query($query); 385 while ($row = $ilDB->fetchObject($res)) { 386 $this->setInstruction($row->instruction); 387 $this->setTimestamp($row->time_stamp); 388 $pm = ($row->pass_mode == "") 389 ? "all" 390 : $row->pass_mode; 391 $this->setPassMode($pm); 392 $this->setShowSubmissions($row->show_submissions); 393 if ($row->pass_mode == "nr") { 394 $this->setPassNr($row->pass_nr); 395 } 396 $this->setNrMandatoryRandom($row->nr_mandatory_random); 397 $this->setCompletionBySubmission($row->compl_by_submission == 1 ? true : false); 398 $this->setCertificateVisibility($row->certificate_visibility); 399 $this->setTutorFeedback($row->tfeedback); 400 } 401 402 $this->members_obj = new ilExerciseMembers($this); 403 404 return true; 405 } 406 407 public function update() 408 { 409 $ilDB = $this->db; 410 411 parent::update(); 412 413 if ($this->getPassMode() == "all") { 414 $pass_nr = null; 415 } else { 416 $pass_nr = $this->getPassNr(); 417 } 418 419 $ilDB->update("exc_data", array( 420 "instruction" => array("clob", $this->getInstruction()), 421 "time_stamp" => array("integer", $this->getTimestamp()), 422 "pass_mode" => array("text", $this->getPassMode()), 423 "pass_nr" => array("integer", $this->getPassNr()), 424 "nr_mandatory_random" => array("integer", (int) $this->getNrMandatoryRandom()), 425 "show_submissions" => array("integer", (int) $this->getShowSubmissions()), 426 'compl_by_submission' => array('integer', (int) $this->isCompletionBySubmissionEnabled()), 427 'tfeedback' => array('integer', (int) $this->getTutorFeedback()), 428 ), array( 429 "obj_id" => array("integer", $this->getId()) 430 )); 431 432 $this->updateAllUsersStatus(); 433 434 return true; 435 } 436 437 /** 438 * send exercise per mail to members 439 */ 440 public function sendAssignment(ilExAssignment $a_ass, $a_members) 441 { 442 $lng = $this->lng; 443 $ilUser = $this->user; 444 445 $lng->loadLanguageModule("exc"); 446 447 // subject 448 $subject = $a_ass->getTitle() 449 ? $this->getTitle() . ": " . $a_ass->getTitle() 450 : $this->getTitle(); 451 452 453 // body 454 455 $body = $a_ass->getInstruction(); 456 $body .= "\n\n"; 457 458 $body .= $lng->txt("exc_edit_until") . ": "; 459 $body .= (!$a_ass->getDeadline()) 460 ? $lng->txt("exc_no_deadline_specified") 461 : ilDatePresentation::formatDate(new ilDateTime($a_ass->getDeadline(), IL_CAL_UNIX)); 462 $body .= "\n\n"; 463 464 $body .= ilLink::_getLink($this->getRefId(), "exc"); 465 466 467 // files 468 $file_names = array(); 469 $storage = new ilFSStorageExercise($a_ass->getExerciseId(), $a_ass->getId()); 470 $files = $storage->getFiles(); 471 if (count($files)) { 472 $mfile_obj = new ilFileDataMail($GLOBALS['DIC']['ilUser']->getId()); 473 foreach ($files as $file) { 474 $mfile_obj->copyAttachmentFile($file["fullpath"], $file["name"]); 475 $file_names[] = $file["name"]; 476 } 477 } 478 479 // recipients 480 $recipients = array(); 481 foreach ($a_members as $member_id) { 482 $tmp_obj = ilObjectFactory::getInstanceByObjId($member_id); 483 $recipients[] = $tmp_obj->getLogin(); 484 unset($tmp_obj); 485 } 486 $recipients = implode(",", $recipients); 487 488 // send mail 489 $tmp_mail_obj = new ilMail($ilUser->getId()); 490 $errors = $tmp_mail_obj->enqueue( 491 $recipients, 492 "", 493 "", 494 $subject, 495 $body, 496 $file_names 497 ); 498 unset($tmp_mail_obj); 499 500 // remove tmp files 501 if (sizeof($file_names)) { 502 $mfile_obj->unlinkFiles($file_names); 503 unset($mfile_obj); 504 } 505 506 // set recipients mail status 507 foreach ($a_members as $member_id) { 508 $member_status = $a_ass->getMemberStatus($member_id); 509 $member_status->setSent(true); 510 $member_status->update(); 511 } 512 513 return true; 514 } 515 516 /** 517 * Determine status of user 518 */ 519 public function determinStatusOfUser($a_user_id = 0) 520 { 521 $ilUser = $this->user; 522 523 $mandatory_manager = $this->mandatory_manager; 524 525 if ($a_user_id == 0) { 526 $a_user_id = $ilUser->getId(); 527 } 528 529 $ass = ilExAssignment::getInstancesByExercise($this->getId()); 530 531 $passed_all_mandatory = true; 532 $failed_a_mandatory = false; 533 $cnt_passed = 0; 534 $cnt_notgraded = 0; 535 536 /** @var ilExAssignment $a */ 537 foreach ($ass as $a) { 538 $stat = $a->getMemberStatus($a_user_id)->getStatus(); 539 $mandatory = $mandatory_manager->isMandatoryForUser($a->getId(), $a_user_id); 540 if ($mandatory && ($stat == "failed" || $stat == "notgraded")) { 541 $passed_all_mandatory = false; 542 } 543 if ($mandatory && ($stat == "failed")) { 544 $failed_a_mandatory = true; 545 } 546 if ($stat == "passed") { 547 $cnt_passed++; 548 } 549 if ($stat == "notgraded") { 550 $cnt_notgraded++; 551 } 552 } 553 554 if (count($ass) == 0) { 555 $passed_all_mandatory = false; 556 } 557 558 if ($this->getPassMode() == self::PASS_MODE_ALL) { 559 $overall_stat = "notgraded"; 560 if ($failed_a_mandatory) { 561 $overall_stat = "failed"; 562 } elseif ($passed_all_mandatory && $cnt_passed > 0) { 563 $overall_stat = "passed"; 564 } 565 } elseif ($this->getPassMode() == self::PASS_MODE_NR) { 566 $min_nr = $this->getPassNr(); 567 $overall_stat = "notgraded"; 568 if ($failed_a_mandatory || ($cnt_passed + $cnt_notgraded < $min_nr)) { 569 $overall_stat = "failed"; 570 } elseif ($passed_all_mandatory && $cnt_passed >= $min_nr) { 571 $overall_stat = "passed"; 572 } 573 } elseif ($this->getPassMode() == self::PASS_MODE_RANDOM) { 574 $overall_stat = "notgraded"; 575 if ($failed_a_mandatory) { 576 $overall_stat = "failed"; 577 } elseif ($passed_all_mandatory && $cnt_passed > 0) { 578 $overall_stat = "passed"; 579 } 580 } 581 582 $ret = array( 583 "overall_status" => $overall_stat, 584 "failed_a_mandatory" => $failed_a_mandatory); 585 //echo "<br>p:".$cnt_passed.":ng:".$cnt_notgraded; 586 //var_dump($ret); exit; 587 return $ret; 588 } 589 590 /** 591 * Update exercise status of user 592 */ 593 public function updateUserStatus($a_user_id = 0) 594 { 595 $ilUser = $this->user; 596 597 if ($a_user_id == 0) { 598 $a_user_id = $ilUser->getId(); 599 } 600 601 $st = $this->determinStatusOfUser($a_user_id); 602 603 ilExerciseMembers::_writeStatus( 604 $this->getId(), 605 $a_user_id, 606 $st["overall_status"] 607 ); 608 } 609 610 /** 611 * Update status of all users 612 */ 613 public function updateAllUsersStatus() 614 { 615 if (!is_object($this->members_obj)) { 616 $this->members_obj = new ilExerciseMembers($this); 617 } 618 619 $mems = $this->members_obj->getMembers(); 620 foreach ($mems as $mem) { 621 $this->updateUserStatus($mem); 622 } 623 } 624 625 /** 626 * Exports grades as excel 627 */ 628 public function exportGradesExcel() 629 { 630 $ass_data = ilExAssignment::getInstancesByExercise($this->getId()); 631 632 $excel = new ilExcel(); 633 $excel->addSheet($this->lng->txt("exc_status")); 634 635 636 // 637 // status 638 // 639 640 // header row 641 $row = $cnt = 1; 642 $excel->setCell($row, 0, $this->lng->txt("name")); 643 foreach ($ass_data as $ass) { 644 $excel->setCell($row, $cnt++, ($cnt / 2) . " - ". $this->lng->txt("exc_tbl_status")); 645 $excel->setCell($row, $cnt++, (($cnt - 1) / 2) . " - ". $this->lng->txt("exc_tbl_mark")); 646 } 647 $excel->setCell($row, $cnt++, $this->lng->txt("exc_total_exc")); 648 $excel->setCell($row, $cnt++, $this->lng->txt("exc_mark")); 649 $excel->setCell($row++, $cnt, $this->lng->txt("exc_comment_for_learner")); 650 $excel->setBold("A1:" . $excel->getColumnCoord($cnt) . "1"); 651 652 // data rows 653 $mem_obj = new ilExerciseMembers($this); 654 655 $filtered_members = $GLOBALS['DIC']->access()->filterUserIdsByRbacOrPositionOfCurrentUser( 656 'edit_submissions_grades', 657 'edit_submissions_grades', 658 $this->getRefId(), 659 (array) $mem_obj->getMembers() 660 ); 661 662 foreach ((array) $filtered_members as $user_id) { 663 $mems[$user_id] = ilObjUser::_lookupName($user_id); 664 } 665 $mems = ilUtil::sortArray($mems, "lastname", "asc", false, true); 666 667 foreach ($mems as $user_id => $d) { 668 $col = 0; 669 670 // name 671 $excel->setCell($row, $col++, $d["lastname"] . ", " . $d["firstname"] . " [" . $d["login"] . "]"); 672 673 reset($ass_data); 674 foreach ($ass_data as $ass) { 675 $status = $ass->getMemberStatus($user_id)->getStatus(); 676 $mark = $ass->getMemberStatus($user_id)->getMark(); 677 $excel->setCell($row, $col++, $this->lng->txt("exc_" . $status)); 678 $excel->setCell($row, $col++, $mark); 679 } 680 681 // total status 682 $status = ilExerciseMembers::_lookupStatus($this->getId(), $user_id); 683 $excel->setCell($row, $col++, $this->lng->txt("exc_" . $status)); 684 685 // #18096 686 $marks_obj = new ilLPMarks($this->getId(), $user_id); 687 $excel->setCell($row, $col++, $marks_obj->getMark()); 688 $excel->setCell($row++, $col, $marks_obj->getComment()); 689 } 690 691 692 // 693 // mark 694 // 695 696 $excel->addSheet($this->lng->txt("exc_mark")); 697 698 // header row 699 $row = $cnt = 1; 700 $excel->setCell($row, 0, $this->lng->txt("name")); 701 foreach ($ass_data as $ass) { 702 $excel->setCell($row, $cnt++, $cnt - 1); 703 } 704 $excel->setCell($row++, $cnt++, $this->lng->txt("exc_total_exc")); 705 $excel->setBold("A1:" . $excel->getColumnCoord($cnt) . "1"); 706 707 // data rows 708 reset($mems); 709 foreach ($mems as $user_id => $d) { 710 $col = 0; 711 712 // name 713 $d = ilObjUser::_lookupName($user_id); 714 $excel->setCell($row, $col++, $d["lastname"] . ", " . $d["firstname"] . " [" . $d["login"] . "]"); 715 716 reset($ass_data); 717 foreach ($ass_data as $ass) { 718 $excel->setCell($row, $col++, $ass->getMemberStatus($user_id)->getMark()); 719 } 720 721 // total mark 722 $excel->setCell($row++, $col, ilLPMarks::_lookupMark($user_id, $this->getId())); 723 } 724 725 $exc_name = ilUtil::getASCIIFilename(preg_replace("/\s/", "_", $this->getTitle())); 726 $excel->sendToClient($exc_name); 727 } 728 729 /** 730 * Send feedback file notification to user 731 */ 732 public function sendFeedbackFileNotification($a_feedback_file, $a_user_id, $a_ass_id, $a_is_text_feedback = false) 733 { 734 $user_ids = $a_user_id; 735 if (!is_array($user_ids)) { 736 $user_ids = array($user_ids); 737 } 738 739 $type = (bool) $a_is_text_feedback 740 ? ilExerciseMailNotification::TYPE_FEEDBACK_TEXT_ADDED 741 : ilExerciseMailNotification::TYPE_FEEDBACK_FILE_ADDED; 742 743 $not = new ilExerciseMailNotification(); 744 $not->setType($type); 745 $not->setAssignmentId($a_ass_id); 746 $not->setObjId($this->getId()); 747 if ($this->getRefId() > 0) { 748 $not->setRefId($this->getRefId()); 749 } 750 $not->setRecipients($user_ids); 751 $not->send(); 752 } 753 754 /** 755 * 756 * Checks whether completion by submission is enabled or not 757 * 758 * @return boolean 759 * @access public 760 * 761 */ 762 public function isCompletionBySubmissionEnabled() 763 { 764 return $this->completion_by_submission; 765 } 766 767 /** 768 * 769 * Enabled/Disable completion by submission 770 * 771 * @param boolean 772 * @return ilObjExercise 773 * @access public 774 * 775 */ 776 public function setCompletionBySubmission($bool) 777 { 778 $this->completion_by_submission = (bool) $bool; 779 780 return $this; 781 } 782 783 public function processExerciseStatus(ilExAssignment $a_ass, array $a_user_ids, $a_has_submitted, array $a_valid_submissions = null) 784 { 785 $a_has_submitted = (bool) $a_has_submitted; 786 787 foreach ($a_user_ids as $user_id) { 788 $member_status = $a_ass->getMemberStatus($user_id); 789 $member_status->setReturned($a_has_submitted); 790 $member_status->update(); 791 792 ilExerciseMembers::_writeReturned($this->getId(), $user_id, $a_has_submitted); 793 } 794 795 // re-evaluate exercise status 796 if ($this->isCompletionBySubmissionEnabled()) { 797 foreach ($a_user_ids as $user_id) { 798 $status = 'notgraded'; 799 if ($a_has_submitted) { 800 if (!is_array($a_valid_submissions) || 801 $a_valid_submissions[$user_id]) { 802 $status = 'passed'; 803 } 804 } 805 806 $member_status = $a_ass->getMemberStatus($user_id); 807 $member_status->setStatus($status); 808 $member_status->update(); 809 } 810 } 811 } 812 813 /** 814 * Get all exercises for user 815 * 816 * @param <type> $a_user_id 817 * @return array (exercise id => passed) 818 */ 819 public static function _lookupFinishedUserExercises($a_user_id) 820 { 821 global $DIC; 822 823 $ilDB = $DIC->database(); 824 825 $set = $ilDB->query("SELECT obj_id, status FROM exc_members" . 826 " WHERE usr_id = " . $ilDB->quote($a_user_id, "integer") . 827 " AND (status = " . $ilDB->quote("passed", "text") . 828 " OR status = " . $ilDB->quote("failed", "text") . ")"); 829 830 $all = array(); 831 while ($row = $ilDB->fetchAssoc($set)) { 832 $all[$row["obj_id"]] = ($row["status"] == "passed"); 833 } 834 return $all; 835 } 836 837 838 /** 839 * Returns the visibility settings of the certificate 840 * 841 * @return integer The value for the visibility settings (0 = always, 1 = only passed, 2 = never) 842 * @access public 843 */ 844 public function getCertificateVisibility() 845 { 846 return (strlen($this->certificate_visibility)) ? $this->certificate_visibility : 0; 847 } 848 849 /** 850 * Sets the visibility settings of the certificate 851 * 852 * @param integer $a_value The value for the visibility settings (0 = always, 1 = only passed, 2 = never) 853 * @access public 854 */ 855 public function setCertificateVisibility($a_value) 856 { 857 $this->certificate_visibility = $a_value; 858 } 859 860 /** 861 * Saves the visibility settings of the certificate 862 * 863 * @param integer $a_value The value for the visibility settings (0 = always, 1 = only passed, 2 = never) 864 * @access private 865 */ 866 public function saveCertificateVisibility($a_value) 867 { 868 $ilDB = $this->db; 869 870 $affectedRows = $ilDB->manipulateF( 871 "UPDATE exc_data SET certificate_visibility = %s WHERE obj_id = %s", 872 array('integer', 'integer'), 873 array($a_value, $this->getId()) 874 ); 875 } 876 877 /** 878 * Add to desktop after hand-in 879 * 880 * @return bool 881 */ 882 public function hasAddToDesktop() 883 { 884 $exc_set = new ilSetting("excs"); 885 return (bool) $exc_set->get("add_to_pd", true); 886 } 887} 888