1<?php 2 3/* Copyright (c) 1998-2010 ILIAS open source, Extended GPL, see docs/LICENSE */ 4 5use \ILIAS\Survey\Participants; 6 7/** 8 * Class ilObjSurvey 9 * 10 * @author Helmut Schottmüller <helmut.schottmueller@mac.com> 11 */ 12class ilObjSurvey extends ilObject 13{ 14 /** 15 * @var ilObjUser 16 */ 17 protected $user; 18 19 /** 20 * @var ilAccessHandler 21 */ 22 protected $access; 23 24 /** 25 * @var ilPluginAdmin 26 */ 27 protected $plugin_admin; 28 29 const EVALUATION_ACCESS_OFF = 0; 30 const EVALUATION_ACCESS_ALL = 1; 31 const EVALUATION_ACCESS_PARTICIPANTS = 2; 32 33 34 const ANONYMIZE_OFF = 0; // personalized, no codes 35 const ANONYMIZE_ON = 1; // anonymized, codes 36 const ANONYMIZE_FREEACCESS = 2; // anonymized, no codes 37 const ANONYMIZE_CODE_ALL = 3; // personalized, codes 38 39 const QUESTIONTITLES_HIDDEN = 0; 40 const QUESTIONTITLES_VISIBLE = 1; 41 42 // constants to define the print view values. 43 const PRINT_HIDE_LABELS = 1; // Show only the titles in "print" and "PDF Export" 44 const PRINT_SHOW_LABELS = 3; // Show titles and labels in "print" and "PDF Export" 45 46 /** 47 * A unique positive numerical ID which identifies the survey. 48 * This is the primary key from a database table. 49 * 50 * @var integer 51 */ 52 public $survey_id; 53 54 /** 55 * A text representation of the authors name. The name of the author must 56 * not necessary be the name of the owner. 57 * 58 * @var string 59 */ 60 public $author; 61 62 /** 63 * A text representation of the surveys introduction. 64 * 65 * @var string 66 */ 67 public $introduction; 68 69 /** 70 * A text representation of the surveys outro. 71 * 72 * @var string 73 */ 74 public $outro; 75 76 77 /** 78 * Indicates the evaluation access for learners 79 * 80 * @var string 81 */ 82 public $evaluation_access; 83 84 /** 85 * The start date of the survey 86 * 87 * @var string 88 */ 89 public $start_date; 90 91 /** 92 * The end date of the survey 93 * 94 * @var string 95 */ 96 public $end_date; 97 98 /** 99 * The questions contained in this survey 100 * 101 * @var array 102 */ 103 public $questions; 104 105 106 /** 107 * Indicates the anonymization of the survey 108 * @var integer 109 */ 110 public $anonymize; 111 112 /** 113 * Indicates if the question titles are shown during a query 114 * @var integer 115 */ 116 public $display_question_titles; 117 118 /** 119 * Indicates if a survey code may be exported with the survey statistics 120 * 121 * @var boolean 122 **/ 123 public $surveyCodeSecurity; 124 125 public $mailnotification; 126 public $mailaddresses; 127 public $mailparticipantdata; 128 public $template_id; 129 public $pool_usage; 130 131 /** 132 * @var ilLogger 133 */ 134 protected $log; 135 136 protected $activation_visibility; 137 protected $activation_starting_time; 138 protected $activation_ending_time; 139 140 // 360° 141 protected $mode_360_self_eval; // [bool] 142 protected $mode_360_self_appr; // [bool] 143 protected $mode_360_self_rate; // [bool] 144 protected $mode_360_results; // [int] 145 protected $mode_skill_service; // [bool] 146 147 const RESULTS_360_NONE = 0; 148 const RESULTS_360_OWN = 1; 149 const RESULTS_360_ALL = 2; 150 151 // reminder/notification 152 protected $reminder_status; // [bool] 153 protected $reminder_start; // [ilDate] 154 protected $reminder_end; // [ilDate] 155 protected $reminder_frequency; // [int] 156 protected $reminder_target; // [int] 157 protected $reminder_last_sent; // [bool] 158 protected $reminder_tmpl; // [int] 159 protected $tutor_ntf_status; // [bool] 160 protected $tutor_ntf_recipients; // [array] 161 protected $tutor_ntf_target; // [int] 162 protected $tutor_res_status; // [bool] 163 protected $tutor_res_recipients; // [array] 164 165 protected $view_own_results; // [bool] 166 protected $mail_own_results; // [bool] 167 protected $mail_confirmation; // [bool] 168 169 protected $anon_user_list; // [bool] 170 171 const NOTIFICATION_PARENT_COURSE = 1; 172 const NOTIFICATION_INVITED_USERS = 2; 173 const NOTIFICATION_APPRAISEES = 3; 174 const NOTIFICATION_RATERS = 4; 175 const NOTIFICATION_APPRAISEES_AND_RATERS = 5; 176 177 protected $mode; //[int] 178 protected $mode_self_eval_results; //[int] 179 180 //MODE TYPES 181 const MODE_STANDARD = 0; 182 const MODE_360 = 1; 183 const MODE_SELF_EVAL = 2; 184 185 //self evaluation only access to results 186 const RESULTS_SELF_EVAL_NONE = 0; 187 const RESULTS_SELF_EVAL_OWN = 1; 188 const RESULTS_SELF_EVAL_ALL = 2; 189 190 191 /** 192 * @var Participants\InvitationsManager 193 */ 194 protected $invitation_manager; 195 196 /** 197 * Constructor 198 * @access public 199 * @param integer reference_id or object_id 200 * @param boolean treat the id as reference_id (true) or object_id (false) 201 */ 202 public function __construct($a_id = 0, $a_call_by_reference = true) 203 { 204 global $DIC; 205 206 $this->user = $DIC->user(); 207 $this->lng = $DIC->language(); 208 $this->db = $DIC->database(); 209 $this->access = $DIC->access(); 210 $this->log = $DIC["ilLog"]; 211 $this->plugin_admin = $DIC["ilPluginAdmin"]; 212 $this->tree = $DIC->repositoryTree(); 213 $ilUser = $DIC->user(); 214 $lng = $DIC->language(); 215 216 $this->type = "svy"; 217 $this->survey_id = -1; 218 $this->introduction = ""; 219 $this->outro = $lng->txt("survey_finished"); 220 $this->author = $ilUser->getFullname(); 221 $this->evaluation_access = self::EVALUATION_ACCESS_OFF; 222 $this->questions = array(); 223 $this->anonymize = self::ANONYMIZE_OFF; 224 $this->display_question_titles = self::QUESTIONTITLES_VISIBLE; 225 $this->surveyCodeSecurity = true; 226 $this->template_id = null; 227 $this->pool_usage = true; 228 $this->log = ilLoggerFactory::getLogger("svy"); 229 $this->mode = self::MODE_STANDARD; 230 $this->mode_self_eval_results = self::RESULTS_SELF_EVAL_OWN; 231 232 $this->invitation_manager = new Participants\InvitationsManager(); 233 234 parent::__construct($a_id, $a_call_by_reference); 235 } 236 237 /** 238 * create survey object 239 */ 240 public function create($a_upload = false) 241 { 242 parent::create(); 243 if (!$a_upload) { 244 $this->createMetaData(); 245 } 246 $this->setOfflineStatus(true); 247 $this->update($a_upload); 248 } 249 250 /** 251 * Create meta data entry 252 * 253 * @access public 254 */ 255 public function createMetaData() 256 { 257 parent::createMetaData(); 258 $this->saveAuthorToMetadata(); 259 } 260 261 /** 262 * update object data 263 * 264 * @access public 265 * @return boolean 266 */ 267 public function update($a_upload = false) 268 { 269 if (!$a_upload) { 270 $this->updateMetaData(); 271 } 272 273 if (!parent::update()) { 274 return false; 275 } 276 277 // put here object specific stuff 278 279 return true; 280 } 281 282 public function createReference() 283 { 284 $result = parent::createReference(); 285 $this->saveToDb(); 286 return $result; 287 } 288 289 /** 290 * read object data from db into object 291 * @access public 292 */ 293 public function read() 294 { 295 parent::read(); 296 $this->loadFromDb(); 297 } 298 299 /** 300 * Adds a question to the survey (used in importer!) 301 * 302 * @param integer $question_id The question id of the question 303 * @access public 304 */ 305 public function addQuestion($question_id) 306 { 307 array_push($this->questions, $question_id); 308 } 309 310 /** 311 * delete object and all related data 312 * 313 * @access public 314 * @return boolean true if all object data were removed; false if only a references were removed 315 */ 316 public function delete() 317 { 318 if ($this->countReferences() == 1) { 319 $this->deleteMetaData(); 320 321 // Delete all survey questions, constraints and materials 322 foreach ($this->questions as $question_id) { 323 $this->removeQuestion($question_id); 324 } 325 $this->deleteSurveyRecord(); 326 327 ilUtil::delDir($this->getImportDirectory()); 328 } 329 330 $remove = parent::delete(); 331 332 // always call parent delete function first!! 333 if (!$remove) { 334 return false; 335 } 336 return true; 337 } 338 339 /** 340 * Deletes the survey from the database 341 * 342 * @access public 343 */ 344 public function deleteSurveyRecord() 345 { 346 $ilDB = $this->db; 347 348 $affectedRows = $ilDB->manipulateF( 349 "DELETE FROM svy_svy WHERE survey_id = %s", 350 array('integer'), 351 array($this->getSurveyId()) 352 ); 353 354 $result = $ilDB->queryF( 355 "SELECT questionblock_fi FROM svy_qblk_qst WHERE survey_fi = %s", 356 array('integer'), 357 array($this->getSurveyId()) 358 ); 359 $questionblocks = array(); 360 while ($row = $ilDB->fetchAssoc($result)) { 361 array_push($questionblocks, $row["questionblock_fi"]); 362 } 363 if (count($questionblocks)) { 364 $affectedRows = $ilDB->manipulate("DELETE FROM svy_qblk WHERE " . $ilDB->in('questionblock_id', $questionblocks, false, 'integer')); 365 } 366 $affectedRows = $ilDB->manipulateF( 367 "DELETE FROM svy_qblk_qst WHERE survey_fi = %s", 368 array('integer'), 369 array($this->getSurveyId()) 370 ); 371 $this->deleteAllUserData(false); 372 373 $affectedRows = $ilDB->manipulateF( 374 "DELETE FROM svy_anonymous WHERE survey_fi = %s", 375 array('integer'), 376 array($this->getSurveyId()) 377 ); 378 379 // delete export files 380 $svy_data_dir = ilUtil::getDataDir() . "/svy_data"; 381 $directory = $svy_data_dir . "/svy_" . $this->getId(); 382 if (is_dir($directory)) { 383 ilUtil::delDir($directory); 384 } 385 386 $mobs = ilObjMediaObject::_getMobsOfObject("svy:html", $this->getId()); 387 // remaining usages are not in text anymore -> delete them 388 // and media objects (note: delete method of ilObjMediaObject 389 // checks whether object is used in another context; if yes, 390 // the object is not deleted!) 391 foreach ($mobs as $mob) { 392 ilObjMediaObject::_removeUsage($mob, "svy:html", $this->getId()); 393 $mob_obj = new ilObjMediaObject($mob); 394 $mob_obj->delete(); 395 } 396 } 397 398 /** 399 * Deletes all user data of a survey 400 * 401 * @access public 402 * @param bool $reset_LP notice that the LP can only be reset it the determining components still exist 403 */ 404 public function deleteAllUserData($reset_LP = true) 405 { 406 $ilDB = $this->db; 407 408 $result = $ilDB->queryF( 409 "SELECT finished_id FROM svy_finished WHERE survey_fi = %s", 410 array('integer'), 411 array($this->getSurveyId()) 412 ); 413 $active_array = array(); 414 while ($row = $ilDB->fetchAssoc($result)) { 415 array_push($active_array, $row["finished_id"]); 416 } 417 418 $affectedRows = $ilDB->manipulateF( 419 "DELETE FROM svy_finished WHERE survey_fi = %s", 420 array('integer'), 421 array($this->getSurveyId()) 422 ); 423 424 foreach ($active_array as $active_fi) { 425 $affectedRows = $ilDB->manipulateF( 426 "DELETE FROM svy_answer WHERE active_fi = %s", 427 array('integer'), 428 array($active_fi) 429 ); 430 $affectedRows = $ilDB->manipulateF( 431 "DELETE FROM svy_times WHERE finished_fi = %s", 432 array('integer'), 433 array($active_fi) 434 ); 435 } 436 437 if ($reset_LP) { 438 $lp_obj = ilObjectLP::getInstance($this->getId()); 439 $lp_obj->resetLPDataForCompleteObject(); 440 } 441 } 442 443 /** 444 * Deletes the user data of a given array of survey participants 445 * 446 * @access public 447 */ 448 public function removeSelectedSurveyResults($finished_ids) 449 { 450 $ilDB = $this->db; 451 452 $user_ids[] = array(); 453 454 foreach ($finished_ids as $finished_id) { 455 $result = $ilDB->queryF( 456 "SELECT finished_id FROM svy_finished WHERE finished_id = %s", 457 array('integer'), 458 array($finished_id) 459 ); 460 $row = $ilDB->fetchAssoc($result); 461 462 if ($row["user_fi"]) { 463 $user_ids[] = $row["user_fi"]; 464 } 465 466 $affectedRows = $ilDB->manipulateF( 467 "DELETE FROM svy_answer WHERE active_fi = %s", 468 array('integer'), 469 array($row["finished_id"]) 470 ); 471 472 $affectedRows = $ilDB->manipulateF( 473 "DELETE FROM svy_finished WHERE finished_id = %s", 474 array('integer'), 475 array($finished_id) 476 ); 477 478 $affectedRows = $ilDB->manipulateF( 479 "DELETE FROM svy_times WHERE finished_fi = %s", 480 array('integer'), 481 array($row["finished_id"]) 482 ); 483 } 484 485 if (sizeof($user_ids)) { 486 $lp_obj = ilObjectLP::getInstance($this->getId()); 487 $lp_obj->resetLPDataForUserIds($user_ids); 488 } 489 } 490 491 public function &getSurveyParticipants($finished_ids = null, $force_non_anonymous = false, $include_invites = false) 492 { 493 $ilDB = $this->db; 494 495 $sql = "SELECT * FROM svy_finished" . 496 " WHERE survey_fi = " . $ilDB->quote($this->getSurveyId(), "integer"); 497 if ($finished_ids) { 498 $sql .= " AND " . $ilDB->in("finished_id", $finished_ids, "", "integer"); 499 } 500 501 $result = $ilDB->query($sql); 502 $participants = array(); 503 if ($result->numRows() > 0) { 504 while ($row = $ilDB->fetchAssoc($result)) { 505 $userdata = $this->getUserDataFromActiveId($row["finished_id"], $force_non_anonymous); 506 $userdata["finished"] = (bool) $row["state"]; 507 $userdata["finished_tstamp"] = $row["tstamp"]; 508 $participants[$userdata["sortname"] . $userdata["active_id"]] = $userdata; 509 } 510 } 511 $participant_ids = array_column($participants, "usr_id"); 512 if ($include_invites) { 513 foreach ($this->invitation_manager->getAllForSurvey($this->getSurveyId()) as $usr_id) { 514 if (!in_array($usr_id, $participant_ids)) { 515 $name = ilObjUser::_lookupName($usr_id); 516 $participants[$name["lastname"] . "," . $name["firstname"] . $usr_id] = [ 517 "fullname" => ilObjUser::_lookupFullname($usr_id), 518 "sortname" => $name["lastname"] . "," . $name["firstname"], 519 "fistname" => $name["firstname"], 520 "lastname" => $name["lastname"], 521 "login" => $name["login"], 522 "gender" => "", 523 "usr_id" => $usr_id, 524 "finished" => false, 525 "finished_tstamp" => 0, 526 "invited" => true 527 ]; 528 } 529 } 530 } 531 532 return $participants; 533 } 534 535 /** 536 * Returns 1, if a survey is complete for use 537 * 538 * @return boolean 1, if the survey is complete for use, otherwise 0 539 * @access public 540 */ 541 public function isComplete() 542 { 543 if (($this->getTitle()) and (count($this->questions))) { 544 return 1; 545 } else { 546 return 0; 547 } 548 } 549 550 /** 551 * Saves the completion status of the survey 552 * 553 * @access public 554 */ 555 public function saveCompletionStatus() 556 { 557 $ilDB = $this->db; 558 559 $complete = 0; 560 if ($this->isComplete()) { 561 $complete = 1; 562 } 563 if ($this->getSurveyId() > 0) { 564 $affectedRows = $ilDB->manipulateF( 565 "UPDATE svy_svy SET complete = %s, tstamp = %s WHERE survey_id = %s", 566 array('text','integer','integer'), 567 array($this->isComplete(), time(), $this->getSurveyId()) 568 ); 569 } 570 } 571 572 /** 573 * Takes a question and creates a copy of the question for use in the survey 574 * 575 * @param integer $question_id The database id of the question 576 * @result integer The database id of the copied question 577 * @access public 578 */ 579 public function duplicateQuestionForSurvey($question_id, $a_force = false) 580 { 581 $ilUser = $this->user; 582 583 $questiontype = $this->getQuestionType($question_id); 584 $question_gui = $this->getQuestionGUI($questiontype, $question_id); 585 586 // check if question is a pool question at all, if not do nothing 587 if ($this->getId() == $question_gui->object->getObjId() && !$a_force) { 588 return $question_id; 589 } 590 591 $duplicate_id = $question_gui->object->duplicate(true, "", "", "", $this->getId()); 592 return $duplicate_id; 593 } 594 595 /** 596 * Inserts a question in the survey and saves the relation to the database 597 * 598 * @access public 599 */ 600 public function insertQuestion($question_id) 601 { 602 $ilDB = $this->db; 603 604 $this->log->debug("insert question, id:" . $question_id); 605 606 if (!SurveyQuestion::_isComplete($question_id)) { 607 $this->log->debug("question is not complete"); 608 return false; 609 } else { 610 // get maximum sequence index in test 611 // @todo: refactor this 612 $result = $ilDB->queryF( 613 "SELECT survey_question_id FROM svy_svy_qst WHERE survey_fi = %s", 614 array('integer'), 615 array($this->getSurveyId()) 616 ); 617 $sequence = $result->numRows(); 618 $duplicate_id = $this->duplicateQuestionForSurvey($question_id); 619 $this->log->debug("duplicate, id: " . $question_id . ", duplicate id: " . $duplicate_id); 620 621 // check if question is not already in the survey, see #22018 622 if ($this->isQuestionInSurvey($duplicate_id)) { 623 return false; 624 } 625 626 $next_id = $ilDB->nextId('svy_svy_qst'); 627 $affectedRows = $ilDB->manipulateF( 628 "INSERT INTO svy_svy_qst (survey_question_id, survey_fi, question_fi, sequence, tstamp) VALUES (%s, %s, %s, %s, %s)", 629 array('integer', 'integer', 'integer', 'integer', 'integer'), 630 array($next_id, $this->getSurveyId(), $duplicate_id, $sequence, time()) 631 ); 632 633 $this->log->debug("added entry to svy_svy_qst, id: " . $next_id . ", question id: " . $duplicate_id . ", sequence: " . $sequence); 634 635 $this->loadQuestionsFromDb(); 636 return true; 637 } 638 } 639 640 /** 641 * Check if a question is already in the survey 642 * 643 * @param question id (as primary key from svy_question table) 644 * @return bool 645 */ 646 public function isQuestionInSurvey($a_question_fi) 647 { 648 global $DIC; 649 //return false; 650 $ilDB = $DIC->database(); 651 652 $set = $ilDB->query("SELECT * FROM svy_svy_qst " . 653 " WHERE survey_fi = " . $ilDB->quote($this->getSurveyId(), "integer") . 654 " AND question_fi = " . $ilDB->quote($a_question_fi, "integer")); 655 if ($rec = $ilDB->fetchAssoc($set)) { 656 return true; 657 } 658 return false; 659 } 660 661 662 663 /** 664 * Inserts a questionblock in the survey and saves the relation to the database 665 * 666 * @access public 667 */ 668 public function insertQuestionblock($questionblock_id) 669 { 670 $ilDB = $this->db; 671 $result = $ilDB->queryF( 672 "SELECT svy_qblk.title, svy_qblk.show_questiontext, svy_qblk.show_blocktitle," . 673 " svy_qblk_qst.question_fi FROM svy_qblk, svy_qblk_qst, svy_svy_qst" . 674 " WHERE svy_qblk.questionblock_id = svy_qblk_qst.questionblock_fi" . 675 " AND svy_svy_qst.question_fi = svy_qblk_qst.question_fi" . 676 " AND svy_qblk.questionblock_id = %s" . 677 " ORDER BY svy_svy_qst.sequence", 678 array('integer'), 679 array($questionblock_id) 680 ); 681 $questions = array(); 682 $show_questiontext = 0; 683 $show_blocktitle = 0; 684 while ($row = $ilDB->fetchAssoc($result)) { 685 $duplicate_id = $this->duplicateQuestionForSurvey($row["question_fi"]); 686 array_push($questions, $duplicate_id); 687 $title = $row["title"]; 688 $show_questiontext = $row["show_questiontext"]; 689 $show_blocktitle = $row["show_blocktitle"]; 690 } 691 $this->createQuestionblock($title, $show_questiontext, $show_blocktitle, $questions); 692 } 693 694 public function saveUserSettings($usr_id, $key, $title, $value) 695 { 696 $ilDB = $this->db; 697 698 $next_id = $ilDB->nextId('svy_settings'); 699 $affectedRows = $ilDB->insert("svy_settings", array( 700 "settings_id" => array("integer", $next_id), 701 "usr_id" => array("integer", $usr_id), 702 "keyword" => array("text", $key), 703 "title" => array("text", $title), 704 "value" => array("clob", $value) 705 )); 706 } 707 708 public function deleteUserSettings($id) 709 { 710 $ilDB = $this->db; 711 712 $affectedRows = $ilDB->manipulateF( 713 "DELETE FROM svy_settings WHERE settings_id = %s", 714 array('integer'), 715 array($id) 716 ); 717 return $affectedRows; 718 } 719 720 public function getUserSettings($usr_id, $key) 721 { 722 $ilDB = $this->db; 723 724 $result = $ilDB->queryF( 725 "SELECT * FROM svy_settings WHERE usr_id = %s AND keyword = %s", 726 array('integer', 'text'), 727 array($usr_id, $key) 728 ); 729 $found = array(); 730 if ($result->numRows()) { 731 while ($row = $ilDB->fetchAssoc($result)) { 732 $found[$row['settings_id']] = $row; 733 } 734 } 735 return $found; 736 } 737 738 /** 739 * Saves a survey object to a database 740 * 741 * @access public 742 */ 743 public function saveToDb() 744 { 745 $ilDB = $this->db; 746 747 // date handling 748 $rmd_start = $this->getReminderStart(); 749 if (is_object($rmd_start)) { 750 $rmd_start = $rmd_start->get(IL_CAL_DATE); 751 } 752 $rmd_end = $this->getReminderEnd(); 753 if (is_object($rmd_end)) { 754 $rmd_end = $rmd_end->get(IL_CAL_DATE); 755 } 756 757 if ($this->getSurveyId() < 1) { 758 $next_id = $ilDB->nextId('svy_svy'); 759 $affectedRows = $ilDB->insert("svy_svy", array( 760 "survey_id" => array("integer", $next_id), 761 "obj_fi" => array("integer", $this->getId()), 762 "author" => array("text", $this->getAuthor()), 763 "introduction" => array("clob", ilRTE::_replaceMediaObjectImageSrc($this->getIntroduction(), 0)), 764 "outro" => array("clob", ilRTE::_replaceMediaObjectImageSrc($this->getOutro(), 0)), 765 "startdate" => array("text", $this->getStartDate()), 766 "enddate" => array("text", $this->getEndDate()), 767 "evaluation_access" => array("text", $this->getEvaluationAccess()), 768 "complete" => array("text", $this->isComplete()), 769 "created" => array("integer", time()), 770 "anonymize" => array("text", $this->getAnonymize()), 771 "show_question_titles" => array("text", $this->getShowQuestionTitles()), 772 "mailnotification" => array('integer', ($this->getMailNotification()) ? 1 : 0), 773 "mailaddresses" => array('text', strlen($this->getMailAddresses()) ? $this->getMailAddresses() : null), 774 "mailparticipantdata" => array('text', strlen($this->getMailParticipantData()) ? $this->getMailParticipantData() : null), 775 "tstamp" => array("integer", time()), 776 "template_id" => array("integer", $this->getTemplate()), 777 "pool_usage" => array("integer", $this->getPoolUsage()), 778 // Mode type 779 "mode" => array("integer", $this->getMode()), 780 // 360° 781 "mode_360_self_eval" => array("integer", $this->get360SelfEvaluation()), 782 "mode_360_self_rate" => array("integer", $this->get360SelfRaters()), 783 "mode_360_self_appr" => array("integer", $this->get360SelfAppraisee()), 784 "mode_360_results" => array("integer", $this->get360Results()), 785 // competences 786 "mode_skill_service" => array("integer", (int) $this->getSkillService()), 787 // Self Evaluation Only 788 "mode_self_eval_results" => array("integer", ilObjSurvey::RESULTS_SELF_EVAL_OWN), 789 // reminder/notification 790 "reminder_status" => array("integer", (int) $this->getReminderStatus()), 791 "reminder_start" => array("datetime", $rmd_start), 792 "reminder_end" => array("datetime", $rmd_end), 793 "reminder_frequency" => array("integer", (int) $this->getReminderFrequency()), 794 "reminder_target" => array("integer", (int) $this->getReminderTarget()), 795 "reminder_last_sent" => array("datetime", $this->getReminderLastSent()), 796 "reminder_tmpl" => array("text", $this->getReminderTemplate(true)), 797 "tutor_ntf_status" => array("integer", (int) $this->getTutorNotificationStatus()), 798 "tutor_ntf_reci" => array("text", implode(";", (array) $this->getTutorNotificationRecipients())), 799 "tutor_ntf_target" => array("integer", (int) $this->getTutorNotificationTarget()), 800 "own_results_view" => array("integer", $this->hasViewOwnResults()), 801 "own_results_mail" => array("integer", $this->hasMailOwnResults()), 802 "tutor_res_status" => array("integer", (int) $this->getTutorResultsStatus()), 803 "tutor_res_reci" => array("text", implode(";", (array) $this->getTutorResultsRecipients())), 804 "confirmation_mail" => array("integer", $this->hasMailConfirmation()), 805 "anon_user_list" => array("integer", $this->hasAnonymousUserList()) 806 )); 807 $this->setSurveyId($next_id); 808 } else { 809 $affectedRows = $ilDB->update("svy_svy", array( 810 "author" => array("text", $this->getAuthor()), 811 "introduction" => array("clob", ilRTE::_replaceMediaObjectImageSrc($this->getIntroduction(), 0)), 812 "outro" => array("clob", ilRTE::_replaceMediaObjectImageSrc($this->getOutro(), 0)), 813 "startdate" => array("text", $this->getStartDate()), 814 "enddate" => array("text", $this->getEndDate()), 815 "evaluation_access" => array("text", $this->getEvaluationAccess()), 816 "complete" => array("text", $this->isComplete()), 817 "anonymize" => array("text", $this->getAnonymize()), 818 "show_question_titles" => array("text", $this->getShowQuestionTitles()), 819 "mailnotification" => array('integer', ($this->getMailNotification()) ? 1 : 0), 820 "mailaddresses" => array('text', strlen($this->getMailAddresses()) ? $this->getMailAddresses() : null), 821 "mailparticipantdata" => array('text', strlen($this->getMailParticipantData()) ? $this->getMailParticipantData() : null), 822 "tstamp" => array("integer", time()), 823 "template_id" => array("integer", $this->getTemplate()), 824 "pool_usage" => array("integer", $this->getPoolUsage()), 825 //MODE TYPE 826 "mode" => array("integer", $this->getMode()), 827 // 360° 828 "mode_360_self_eval" => array("integer", $this->get360SelfEvaluation()), 829 "mode_360_self_rate" => array("integer", $this->get360SelfRaters()), 830 "mode_360_self_appr" => array("integer", $this->get360SelfAppraisee()), 831 "mode_360_results" => array("integer", $this->get360Results()), 832 // Competences 833 "mode_skill_service" => array("integer", (int) $this->getSkillService()), 834 // Self Evaluation Only 835 "mode_self_eval_results" => array("integer", $this->getSelfEvaluationResults()), 836 // reminder/notification 837 "reminder_status" => array("integer", $this->getReminderStatus()), 838 "reminder_start" => array("datetime", $rmd_start), 839 "reminder_end" => array("datetime", $rmd_end), 840 "reminder_frequency" => array("integer", $this->getReminderFrequency()), 841 "reminder_target" => array("integer", $this->getReminderTarget()), 842 "reminder_last_sent" => array("datetime", $this->getReminderLastSent()), 843 "reminder_tmpl" => array("text", $this->getReminderTemplate()), 844 "tutor_ntf_status" => array("integer", $this->getTutorNotificationStatus()), 845 "tutor_ntf_reci" => array("text", implode(";", (array) $this->getTutorNotificationRecipients())), 846 "tutor_ntf_target" => array("integer", $this->getTutorNotificationTarget()), 847 "own_results_view" => array("integer", $this->hasViewOwnResults()), 848 "own_results_mail" => array("integer", $this->hasMailOwnResults()), 849 "tutor_res_status" => array("integer", (int) $this->getTutorResultsStatus()), 850 "tutor_res_reci" => array("text", implode(";", (array) $this->getTutorResultsRecipients())), 851 "confirmation_mail" => array("integer", $this->hasMailConfirmation()), 852 "anon_user_list" => array("integer", $this->hasAnonymousUserList()) 853 ), array( 854 "survey_id" => array("integer", $this->getSurveyId()) 855 )); 856 } 857 if ($affectedRows) { 858 // save questions to db 859 $this->saveQuestionsToDb(); 860 } 861 862 // moved activation to ilObjectActivation 863 if ($this->ref_id) { 864 ilObjectActivation::getItem($this->ref_id); 865 866 $item = new ilObjectActivation; 867 if (!$this->isActivationLimited()) { 868 $item->setTimingType(ilObjectActivation::TIMINGS_DEACTIVATED); 869 } else { 870 $item->setTimingType(ilObjectActivation::TIMINGS_ACTIVATION); 871 $item->setTimingStart($this->getActivationStartDate()); 872 $item->setTimingEnd($this->getActivationEndDate()); 873 $item->toggleVisible($this->getActivationVisibility()); 874 } 875 876 $item->update($this->ref_id); 877 } 878 } 879 880 /** 881 * Saves the survey questions to the database 882 * 883 * @access public 884 * @see $questions 885 */ 886 public function saveQuestionsToDb() 887 { 888 $ilDB = $this->db; 889 890 $this->log->debug("save questions"); 891 892 // gather old questions state 893 $old_questions = array(); 894 $result = $ilDB->queryF( 895 "SELECT survey_question_id,question_fi,sequence" . 896 " FROM svy_svy_qst WHERE survey_fi = %s", 897 array('integer'), 898 array($this->getSurveyId()) 899 ); 900 while ($row = $ilDB->fetchAssoc($result)) { 901 $old_questions[$row["question_fi"]] = $row; // problem, as soon as duplicates exist, they will be hidden here 902 } 903 904 // #15231 - diff with current questions state 905 $insert = $update = $delete = array(); 906 foreach ($this->questions as $seq => $fi) { 907 if (!array_key_exists($fi, $old_questions)) { // really new fi IDs 908 $insert[] = $fi; // this should be ok, should not create duplicates here 909 } elseif ($old_questions[$fi]["sequence"] != $seq) { // we are updating one of the duplicates (if any) 910 $update[$fi] = $old_questions[$fi]["survey_question_id"]; 911 } 912 // keep track of still relevant questions 913 unset($old_questions[$fi]); // deleting old question, if they are not in current array 914 } 915 916 // delete obsolete question relations 917 if (sizeof($old_questions)) { 918 $del_ids = array(); 919 foreach ($old_questions as $fi => $old) { 920 $del_ids[] = $old["survey_question_id"]; 921 } 922 $ilDB->manipulate($q = "DELETE FROM svy_svy_qst" . 923 " WHERE " . $ilDB->in("survey_question_id", $del_ids, "", "integer")); 924 $this->log->debug("delete: " . $q); 925 } 926 unset($old_questions); 927 928 // create/update question relations 929 foreach ($this->questions as $seq => $fi) { 930 if (in_array($fi, $insert)) { 931 // check if question is not already in the survey, see #22018 932 if (!$this->isQuestionInSurvey($fi)) { 933 $next_id = $ilDB->nextId('svy_svy_qst'); 934 $ilDB->manipulateF( 935 "INSERT INTO svy_svy_qst" . 936 " (survey_question_id, survey_fi, question_fi, heading, sequence, tstamp)" . 937 " VALUES (%s, %s, %s, %s, %s, %s)", 938 array('integer', 'integer', 'integer', 'text', 'integer', 'integer'), 939 array($next_id, $this->getSurveyId(), $fi, null, $seq, time()) 940 ); 941 $this->log->debug("insert svy_svy_qst, id:" . $next_id . ", fi: " . $fi . ", seq:" . $seq); 942 } 943 } elseif (array_key_exists($fi, $update)) { 944 $ilDB->manipulate("UPDATE svy_svy_qst" . 945 " SET sequence = " . $ilDB->quote($seq, "integer") . 946 ", tstamp = " . $ilDB->quote(time(), "integer") . 947 " WHERE survey_question_id = " . $ilDB->quote($update[$fi], "integer")); 948 $this->log->debug("update svy_svy_qst, id:" . $update[$fi] . ", fi: " . $fi . ", seq:" . $seq); 949 } 950 } 951 } 952 953 /** 954 * Checks for an anomyous survey id in the database an returns the id 955 * 956 * @param string $id A survey access code 957 * @result object Anonymous survey id if found, empty string otherwise 958 * @access public 959 */ 960 public function getAnonymousId($id) 961 { 962 $ilDB = $this->db; 963 $result = $ilDB->queryF( 964 "SELECT anonymous_id FROM svy_finished WHERE anonymous_id = %s", 965 array('text'), 966 array($id) 967 ); 968 if ($result->numRows()) { 969 $row = $ilDB->fetchAssoc($result); 970 return $row["anonymous_id"]; 971 } else { 972 return ""; 973 } 974 } 975 976 /** 977 * Returns a question gui object to a given questiontype and question id 978 * 979 * @result object Resulting question gui object 980 * @access public 981 */ 982 public function getQuestionGUI($questiontype, $question_id) 983 { 984 return SurveyQuestionGUI::_getQuestionGUI($questiontype, $question_id); 985 } 986 987 /** 988 * Returns the question type of a question with a given id 989 * 990 * @param integer $question_id The database id of the question 991 * @result string The question type string 992 * @access private 993 */ 994 public function getQuestionType($question_id) 995 { 996 $ilDB = $this->db; 997 if ($question_id < 1) { 998 return -1; 999 } 1000 $result = $ilDB->queryF( 1001 "SELECT type_tag FROM svy_question, svy_qtype WHERE svy_question.question_id = %s AND " . 1002 "svy_question.questiontype_fi = svy_qtype.questiontype_id", 1003 array('integer'), 1004 array($question_id) 1005 ); 1006 if ($result->numRows() == 1) { 1007 $data = $ilDB->fetchAssoc($result); 1008 return $data["type_tag"]; 1009 } else { 1010 return ""; 1011 } 1012 } 1013 1014 /** 1015 * Returns the survey database id 1016 * 1017 * @result integer survey database id 1018 * @access public 1019 */ 1020 public function getSurveyId() 1021 { 1022 return $this->survey_id; 1023 } 1024 1025 /** 1026 * set anonymize status 1027 */ 1028 public function setAnonymize($a_anonymize) 1029 { 1030 switch ($a_anonymize) { 1031 case self::ANONYMIZE_OFF: 1032 case self::ANONYMIZE_ON: 1033 case self::ANONYMIZE_FREEACCESS: 1034 case self::ANONYMIZE_CODE_ALL: 1035 $this->anonymize = $a_anonymize; 1036 break; 1037 default: 1038 $this->anonymize = self::ANONYMIZE_OFF; 1039 break; 1040 } 1041 } 1042 1043 /** 1044 * get anonymize status 1045 * 1046 * @return integer status 1047 */ 1048 public function getAnonymize() 1049 { 1050 return ($this->anonymize) ? $this->anonymize : 0; 1051 } 1052 1053 /** 1054 * Checks if the survey is accessable without a survey code 1055 * 1056 * @return boolean status 1057 */ 1058 public function isAccessibleWithoutCode() 1059 { 1060 return ($this->getAnonymize() == self::ANONYMIZE_OFF || 1061 $this->getAnonymize() == self::ANONYMIZE_FREEACCESS); 1062 } 1063 1064 /** 1065 * Checks if the survey results are to be anonymized 1066 * 1067 * @return boolean status 1068 */ 1069 public function hasAnonymizedResults() 1070 { 1071 return ($this->getAnonymize() == self::ANONYMIZE_ON || 1072 $this->getAnonymize() == self::ANONYMIZE_FREEACCESS); 1073 } 1074 1075 /** 1076 * Loads a survey object from a database 1077 * 1078 * @access public 1079 */ 1080 public function loadFromDb() 1081 { 1082 $ilDB = $this->db; 1083 $result = $ilDB->queryF( 1084 "SELECT * FROM svy_svy WHERE obj_fi = %s", 1085 array('integer'), 1086 array($this->getId()) 1087 ); 1088 if ($result->numRows() == 1) { 1089 $data = $ilDB->fetchAssoc($result); 1090 $this->setSurveyId($data["survey_id"]); 1091 $this->setAuthor($data["author"]); 1092 $this->setIntroduction(ilRTE::_replaceMediaObjectImageSrc($data["introduction"], 1)); 1093 if (strcmp($data["outro"], "survey_finished") == 0) { 1094 $this->setOutro($this->lng->txt("survey_finished")); 1095 } else { 1096 $this->setOutro(ilRTE::_replaceMediaObjectImageSrc($data["outro"], 1)); 1097 } 1098 $this->setShowQuestionTitles($data["show_question_titles"]); 1099 $this->setStartDate($data["startdate"]); 1100 $this->setEndDate($data["enddate"]); 1101 $this->setAnonymize($data["anonymize"]); 1102 $this->setEvaluationAccess($data["evaluation_access"]); 1103 $this->loadQuestionsFromDb(); 1104 $this->setMailNotification($data['mailnotification']); 1105 $this->setMailAddresses($data['mailaddresses']); 1106 $this->setMailParticipantData($data['mailparticipantdata']); 1107 $this->setTemplate($data['template_id']); 1108 $this->setPoolUsage($data['pool_usage']); 1109 // Mode 1110 $this->setMode($data['mode']); 1111 // 360° 1112 $this->set360SelfEvaluation($data['mode_360_self_eval']); 1113 $this->set360SelfRaters($data['mode_360_self_rate']); 1114 $this->set360SelfAppraisee($data['mode_360_self_appr']); 1115 $this->set360Results($data['mode_360_results']); 1116 // Mode self evaluated 1117 $this->setSelfEvaluationResults($data['mode_self_eval_results']); 1118 // Competences 1119 $this->setSkillService($data['mode_skill_service']); 1120 // reminder/notification 1121 $this->setReminderStatus($data["reminder_status"]); 1122 $this->setReminderStart($data["reminder_start"] ? new ilDate($data["reminder_start"], IL_CAL_DATE) : null); 1123 $this->setReminderEnd($data["reminder_end"] ? new ilDate($data["reminder_end"], IL_CAL_DATE) : null); 1124 $this->setReminderFrequency($data["reminder_frequency"]); 1125 $this->setReminderTarget($data["reminder_target"]); 1126 $this->setReminderLastSent($data["reminder_last_sent"]); 1127 $this->setReminderTemplate($data["reminder_tmpl"]); 1128 $this->setTutorNotificationStatus($data["tutor_ntf_status"]); 1129 $this->setTutorNotificationRecipients(explode(";", $data["tutor_ntf_reci"])); 1130 $this->setTutorNotificationTarget($data["tutor_ntf_target"]); 1131 $this->setTutorResultsStatus($data["tutor_res_status"]); 1132 $this->setTutorResultsRecipients(explode(";", $data["tutor_res_reci"])); 1133 1134 $this->setViewOwnResults($data["own_results_view"]); 1135 $this->setMailOwnResults($data["own_results_mail"]); 1136 $this->setMailConfirmation($data["confirmation_mail"]); 1137 1138 $this->setAnonymousUserList($data["anon_user_list"]); 1139 } 1140 1141 // moved activation to ilObjectActivation 1142 if ($this->ref_id) { 1143 $activation = ilObjectActivation::getItem($this->ref_id); 1144 switch ($activation["timing_type"]) { 1145 case ilObjectActivation::TIMINGS_ACTIVATION: 1146 $this->setActivationLimited(true); 1147 $this->setActivationStartDate($activation["timing_start"]); 1148 $this->setActivationEndDate($activation["timing_end"]); 1149 $this->setActivationVisibility($activation["visible"]); 1150 break; 1151 1152 default: 1153 $this->setActivationLimited(false); 1154 break; 1155 } 1156 } 1157 } 1158 1159 /** 1160 * Loads the survey questions from the database 1161 * 1162 * @access public 1163 * @see $questions 1164 */ 1165 public function loadQuestionsFromDb() 1166 { 1167 $ilDB = $this->db; 1168 $this->questions = array(); 1169 $result = $ilDB->queryF( 1170 "SELECT * FROM svy_svy_qst WHERE survey_fi = %s ORDER BY sequence", 1171 array('integer'), 1172 array($this->getSurveyId()) 1173 ); 1174 while ($data = $ilDB->fetchAssoc($result)) { 1175 $this->questions[$data["sequence"]] = $data["question_fi"]; 1176 } 1177 } 1178 1179 /** 1180 * Remove duplicate sequence entries, see #22018 1181 */ 1182 public function fixSequenceStructure() 1183 { 1184 global $DIC; 1185 1186 $ilDB = $DIC->database(); 1187 //return; 1188 // we keep all survey question ids with their lowest sequence 1189 $result = $ilDB->queryF( 1190 "SELECT * FROM svy_svy_qst WHERE survey_fi = %s ORDER BY sequence", 1191 array('integer'), 1192 array($this->getSurveyId()) 1193 ); 1194 1195 // step 1: find duplicates -> $to_delete_ids 1196 $fis = array(); 1197 $to_delete_ids = array(); 1198 while ($data = $ilDB->fetchAssoc($result)) { 1199 if (in_array($data["question_fi"], $fis)) { // found a duplicate 1200 $to_delete_ids[] = $data["survey_question_id"]; 1201 } else { 1202 $fis[] = $data["question_fi"]; 1203 } 1204 } 1205 1206 // step 2: we delete the duplicates 1207 if (count($to_delete_ids) > 0) { 1208 $ilDB->manipulate($q = "DELETE FROM svy_svy_qst" . 1209 " WHERE " . $ilDB->in("survey_question_id", $to_delete_ids, false, "integer") . 1210 " AND survey_fi = " . $ilDB->quote($this->getSurveyId(), "integer")); 1211 $this->log->debug("delete: " . $q); 1212 1213 $ilDB->manipulate($q = "DELETE FROM svy_qblk_qst " . 1214 " WHERE " . $ilDB->in("question_fi", $fis, true, "integer") . 1215 " AND survey_fi = " . $ilDB->quote($this->getSurveyId(), "integer")); 1216 $this->log->debug("delete: " . $q); 1217 } 1218 1219 // step 3: we fix the sequence 1220 $set = $ilDB->query("SELECT * FROM svy_svy_qst " . 1221 " WHERE survey_fi = " . $ilDB->quote($this->getSurveyId(), "integer") . " ORDER BY sequence"); 1222 $seq = 0; 1223 while ($rec = $ilDB->fetchAssoc($set)) { 1224 $ilDB->manipulate( 1225 $q = "UPDATE svy_svy_qst SET " . 1226 " sequence = " . $ilDB->quote($seq++, "integer") . 1227 " WHERE survey_question_id = " . $ilDB->quote($rec["survey_question_id"], "integer") 1228 ); 1229 $this->log->debug("update: " . $q); 1230 } 1231 } 1232 1233 1234 /** 1235 * Sets the authors name of the ilObjSurvey object 1236 * 1237 * @param string $author A string containing the name of the test author 1238 * @access public 1239 * @see $author 1240 */ 1241 public function setAuthor($author = "") 1242 { 1243 $this->author = $author; 1244 } 1245 1246 /** 1247 * Saves an authors name into the lifecycle metadata if no lifecycle metadata exists 1248 * This will only be called for conversion of "old" tests where the author hasn't been 1249 * stored in the lifecycle metadata 1250 * 1251 * @param string $a_author A string containing the name of the test author 1252 * @access private 1253 * @see $author 1254 */ 1255 public function saveAuthorToMetadata($a_author = "") 1256 { 1257 $md = new ilMD($this->getId(), 0, $this->getType()); 1258 $md_life = &$md->getLifecycle(); 1259 if (!$md_life) { 1260 if (strlen($a_author) == 0) { 1261 $ilUser = $this->user; 1262 $a_author = $ilUser->getFullname(); 1263 } 1264 1265 $md_life = &$md->addLifecycle(); 1266 $md_life->save(); 1267 $con = &$md_life->addContribute(); 1268 $con->setRole("Author"); 1269 $con->save(); 1270 $ent = &$con->addEntity(); 1271 $ent->setEntity($a_author); 1272 $ent->save(); 1273 } 1274 } 1275 1276 /** 1277 * Gets the authors name of the ilObjSurvey object 1278 * 1279 * @return string The string containing the name of the test author 1280 * @access public 1281 * @see $author 1282 */ 1283 public function getAuthor() 1284 { 1285 $author = array(); 1286 $md = new ilMD($this->getId(), 0, $this->getType()); 1287 $md_life = &$md->getLifecycle(); 1288 if ($md_life) { 1289 $ids = &$md_life->getContributeIds(); 1290 foreach ($ids as $id) { 1291 $md_cont = &$md_life->getContribute($id); 1292 if (strcmp($md_cont->getRole(), "Author") == 0) { 1293 $entids = &$md_cont->getEntityIds(); 1294 foreach ($entids as $entid) { 1295 $md_ent = &$md_cont->getEntity($entid); 1296 array_push($author, $md_ent->getEntity()); 1297 } 1298 } 1299 } 1300 } 1301 return join(",", $author); 1302 } 1303 1304 /** 1305 * Gets the status of the display_question_titles attribute 1306 * 1307 * @return integer The status of the display_question_titles attribute 1308 * @see $display_question_titles 1309 */ 1310 public function getShowQuestionTitles() 1311 { 1312 return ($this->display_question_titles) ? 1 : 0; 1313 } 1314 1315 /** 1316 * Sets the status of the display_question_titles attribute 1317 * 1318 * @param integer $a_show The status of the display_question_titles attribute 1319 * @see $display_question_titles 1320 */ 1321 public function setShowQuestionTitles($a_show) 1322 { 1323 $this->display_question_titles = ($a_show) ? 1 : 0; 1324 } 1325 1326 /** 1327 * Sets the question titles visible during the query 1328 * 1329 * @access public 1330 * @see $display_question_titles 1331 */ 1332 public function showQuestionTitles() 1333 { 1334 $this->display_question_titles = 1; 1335 } 1336 1337 /** 1338 * Sets the question titles hidden during the query 1339 * 1340 * @access public 1341 * @see $display_question_titles 1342 */ 1343 public function hideQuestionTitles() 1344 { 1345 $this->display_question_titles = 0; 1346 } 1347 1348 /** 1349 * Sets the introduction text 1350 * 1351 * @param string $introduction A string containing the introduction 1352 * @see $introduction 1353 */ 1354 public function setIntroduction($introduction = "") 1355 { 1356 $this->introduction = $introduction; 1357 } 1358 1359 /** 1360 * Sets the outro text 1361 * 1362 * @param string $outro A string containing the outro 1363 * @see $outro 1364 */ 1365 public function setOutro($outro = "") 1366 { 1367 $this->outro = $outro; 1368 } 1369 1370 1371 /** 1372 * Gets the start date of the survey 1373 * 1374 * @return string Survey start date (YYYY-MM-DD) 1375 * @access public 1376 * @see $start_date 1377 */ 1378 public function getStartDate() 1379 { 1380 return (strlen($this->start_date)) ? $this->start_date : null; 1381 } 1382 1383 /** 1384 * Checks if the survey can be started 1385 * 1386 * @return array An array containing the following keys: result (boolean) and messages (array) 1387 * @access public 1388 */ 1389 public function canStartSurvey($anonymous_id = null, $a_no_rbac = false) 1390 { 1391 $ilAccess = $this->access; 1392 1393 $result = true; 1394 $messages = array(); 1395 $edit_settings = false; 1396 // check start date 1397 if (preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getStartDate(), $matches)) { 1398 $epoch_time = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]); 1399 $now = time(); 1400 if ($now < $epoch_time) { 1401 array_push($messages, $this->lng->txt('start_date_not_reached') . ' (' . 1402 ilDatePresentation::formatDate(new ilDateTime($this->getStartDate(), IL_CAL_TIMESTAMP)) . ")"); 1403 $result = false; 1404 $edit_settings = true; 1405 } 1406 } 1407 // check end date 1408 if (preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getEndDate(), $matches)) { 1409 $epoch_time = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]); 1410 $now = time(); 1411 if ($now > $epoch_time) { 1412 array_push($messages, $this->lng->txt('end_date_reached') . ' (' . 1413 ilDatePresentation::formatDate(new ilDateTime($this->getEndDate(), IL_CAL_TIMESTAMP)) . ")"); 1414 $result = false; 1415 $edit_settings = true; 1416 } 1417 } 1418 1419 // check online status 1420 if ($this->getOfflineStatus()) { 1421 array_push($messages, $this->lng->txt("survey_is_offline")); 1422 $result = false; 1423 $edit_settings = true; 1424 } 1425 // check rbac permissions 1426 if (!$a_no_rbac && !$ilAccess->checkAccess("read", "", $this->ref_id)) { 1427 array_push($messages, $this->lng->txt("cannot_participate_survey")); 1428 $result = false; 1429 } 1430 /* 1431 // 2. check previous access 1432 if (!$result["error"]) 1433 { 1434 $ilUser = $this->user; 1435 $survey_started = $this->isSurveyStarted($ilUser->getId(), $anonymous_id); 1436 if ($survey_started === 1) 1437 { 1438 array_push($messages, $this->lng->txt("already_completed_survey")); 1439 $result = FALSE; 1440 } 1441 } 1442 */ 1443 return array( 1444 "result" => $result, 1445 "messages" => $messages, 1446 "edit_settings" => $edit_settings 1447 ); 1448 } 1449 1450 /** 1451 * Sets the start date of the survey 1452 * 1453 * @param string $start_data Survey start date (YYYYMMDDHHMMSS) 1454 * @access public 1455 * @see $start_date 1456 */ 1457 public function setStartDate($start_date = "") 1458 { 1459 $this->start_date = $start_date; 1460 } 1461 1462 /** 1463 * Sets the start date of the survey 1464 * 1465 * @param string $start_date Survey start date (YYYY-MM-DD) 1466 * @param string $start_time Survey start time (HH:MM:SS) 1467 * @access public 1468 * @see $start_date 1469 */ 1470 public function setStartDateAndTime($start_date = "", $start_time) 1471 { 1472 $y = ''; 1473 $m = ''; 1474 $d = ''; 1475 $h = ''; 1476 $i = ''; 1477 $s = ''; 1478 if (preg_match("/(\d{4})-(\d{2})-(\d{2})/", $start_date, $matches)) { 1479 $y = $matches[1]; 1480 $m = $matches[2]; 1481 $d = $matches[3]; 1482 } 1483 if (preg_match("/(\d{2}):(\d{2}):(\d{2})/", $start_time, $matches)) { 1484 $h = $matches[1]; 1485 $i = $matches[2]; 1486 $s = $matches[3]; 1487 } 1488 $this->start_date = sprintf('%04d%02d%02d%02d%02d%02d', $y, $m, $d, $h, $i, $s); 1489 } 1490 1491 /** 1492 * Gets the end date of the survey 1493 * 1494 * @return string Survey end date (YYYY-MM-DD) 1495 * @access public 1496 * @see $end_date 1497 */ 1498 public function getEndDate() 1499 { 1500 return (strlen($this->end_date)) ? $this->end_date : null; 1501 } 1502 1503 /** 1504 * Sets the end date of the survey 1505 * 1506 * @param string $end_date Survey end date (YYYYMMDDHHMMSS) 1507 * @access public 1508 * @see $end_date 1509 */ 1510 public function setEndDate($end_date = "") 1511 { 1512 $this->end_date = $end_date; 1513 } 1514 1515 /** 1516 * Sets the end date of the survey 1517 * 1518 * @param string $end_date Survey end date (YYYY-MM-DD) 1519 * @param string $end_time Survey end time (HH:MM:SS) 1520 * @access public 1521 * @see $start_date 1522 */ 1523 public function setEndDateAndTime($end_date = "", $end_time) 1524 { 1525 $y = ''; 1526 $m = ''; 1527 $d = ''; 1528 $h = ''; 1529 $i = ''; 1530 $s = ''; 1531 if (preg_match("/(\d{4})-(\d{2})-(\d{2})/", $end_date, $matches)) { 1532 $y = $matches[1]; 1533 $m = $matches[2]; 1534 $d = $matches[3]; 1535 } 1536 if (preg_match("/(\d{2}):(\d{2}):(\d{2})/", $end_time, $matches)) { 1537 $h = $matches[1]; 1538 $i = $matches[2]; 1539 $s = $matches[3]; 1540 } 1541 $this->end_date = sprintf('%04d%02d%02d%02d%02d%02d', $y, $m, $d, $h, $i, $s); 1542 } 1543 1544 /** 1545 * Gets the learners evaluation access 1546 * 1547 * @return integer The evaluation access 1548 * @access public 1549 * @see $evaluation_access 1550 */ 1551 public function getEvaluationAccess() 1552 { 1553 return ($this->evaluation_access) ? $this->evaluation_access : self::EVALUATION_ACCESS_OFF; 1554 } 1555 1556 /** 1557 * Sets the learners evaluation access 1558 * 1559 * @param integer $evaluation_access The evaluation access 1560 * @access public 1561 * @see $evaluation_access 1562 */ 1563 public function setEvaluationAccess($evaluation_access = self::EVALUATION_ACCESS_OFF) 1564 { 1565 $this->evaluation_access = ($evaluation_access) ? $evaluation_access : self::EVALUATION_ACCESS_OFF; 1566 } 1567 1568 public function setActivationVisibility($a_value) 1569 { 1570 $this->activation_visibility = (bool) $a_value; 1571 } 1572 1573 public function getActivationVisibility() 1574 { 1575 return $this->activation_visibility; 1576 } 1577 1578 public function isActivationLimited() 1579 { 1580 return (bool) $this->activation_limited; 1581 } 1582 1583 public function setActivationLimited($a_value) 1584 { 1585 $this->activation_limited = (bool) $a_value; 1586 } 1587 1588 /** 1589 * Gets the introduction text 1590 * 1591 * @return string The introduction of the survey object 1592 * @access public 1593 * @see $introduction 1594 */ 1595 public function getIntroduction() 1596 { 1597 return (strlen($this->introduction)) ? $this->introduction : null; 1598 } 1599 1600 /** 1601 * Gets the outro text 1602 * 1603 * @return string The outro of the survey object 1604 * @access public 1605 * @see $outro 1606 */ 1607 public function getOutro() 1608 { 1609 return (strlen($this->outro)) ? $this->outro : null; 1610 } 1611 1612 /** 1613 * Gets the question id's of the questions which are already in the survey 1614 * 1615 * @return array The questions of the survey 1616 * @access public 1617 */ 1618 public function &getExistingQuestions() 1619 { 1620 $ilDB = $this->db; 1621 $existing_questions = array(); 1622 $result = $ilDB->queryF( 1623 "SELECT svy_question.original_id FROM svy_question, svy_svy_qst WHERE " . 1624 "svy_svy_qst.survey_fi = %s AND svy_svy_qst.question_fi = svy_question.question_id", 1625 array('integer'), 1626 array($this->getSurveyId()) 1627 ); 1628 while ($data = $ilDB->fetchAssoc($result)) { 1629 if ($data["original_id"]) { 1630 array_push($existing_questions, $data["original_id"]); 1631 } 1632 } 1633 return $existing_questions; 1634 } 1635 1636 /** 1637 * Get the titles of all available survey question pools 1638 * 1639 * @return array An array of survey question pool titles 1640 * @access public 1641 */ 1642 public function &getQuestionpoolTitles($could_be_offline = false, $showPath = false) 1643 { 1644 return ilObjSurveyQuestionPool::_getAvailableQuestionpools($use_object_id = true, $could_be_offline, $showPath); 1645 } 1646 1647 /** 1648 * Move questions and/or questionblocks to another position 1649 * 1650 * @param array $move_questions An array with the question id's of the questions to move 1651 * @param integer $target_index The question id of the target position 1652 * @param integer $insert_mode 0, if insert before the target position, 1 if insert after the target position 1653 * @access public 1654 */ 1655 public function moveQuestions($move_questions, $target_index, $insert_mode) 1656 { 1657 $array_pos = array_search($target_index, $this->questions); 1658 if ($insert_mode == 0) { 1659 $part1 = array_slice($this->questions, 0, $array_pos); 1660 $part2 = array_slice($this->questions, $array_pos); 1661 } elseif ($insert_mode == 1) { 1662 $part1 = array_slice($this->questions, 0, $array_pos + 1); 1663 $part2 = array_slice($this->questions, $array_pos + 1); 1664 } 1665 $found = 0; 1666 foreach ($move_questions as $question_id) { 1667 if (!(array_search($question_id, $part1) === false)) { 1668 unset($part1[array_search($question_id, $part1)]); 1669 $found++; 1670 } 1671 if (!(array_search($question_id, $part2) === false)) { 1672 unset($part2[array_search($question_id, $part2)]); 1673 $found++; 1674 } 1675 } 1676 // sanity check: do not move questions if they have not be found in the array 1677 if ($found != count($move_questions)) { 1678 return; 1679 } 1680 $part1 = array_values($part1); 1681 $part2 = array_values($part2); 1682 $this->questions = array_values(array_merge($part1, $move_questions, $part2)); 1683 foreach ($move_questions as $question_id) { 1684 $constraints = $this->getConstraints($question_id); 1685 foreach ($constraints as $idx => $constraint) { 1686 foreach ($part2 as $next_question_id) { 1687 if ($constraint["question"] == $next_question_id) { 1688 // constraint concerning a question that follows -> delete constraint 1689 $this->deleteConstraint($constraint["id"]); 1690 } 1691 } 1692 } 1693 } 1694 $this->saveQuestionsToDb(); 1695 } 1696 1697 /** 1698 * Remove a question from the survey 1699 * 1700 * @param integer $question_id The database id of the question 1701 * @access public 1702 */ 1703 public function removeQuestion($question_id) 1704 { 1705 $question = self::_instanciateQuestion($question_id); 1706 #20610 if no question found, do nothing. 1707 if ($question) { 1708 $question->delete($question_id); 1709 $this->removeConstraintsConcerningQuestion($question_id); 1710 } 1711 } 1712 1713 /** 1714 * Remove constraints concerning a question with a given question_id 1715 * 1716 * @param integer $question_id The database id of the question 1717 * @access public 1718 */ 1719 public function removeConstraintsConcerningQuestion($question_id) 1720 { 1721 $ilDB = $this->db; 1722 $result = $ilDB->queryF( 1723 "SELECT constraint_fi FROM svy_qst_constraint WHERE question_fi = %s AND survey_fi = %s", 1724 array('integer','integer'), 1725 array($question_id, $this->getSurveyId()) 1726 ); 1727 if ($result->numRows() > 0) { 1728 $remove_constraints = array(); 1729 while ($row = $ilDB->fetchAssoc($result)) { 1730 array_push($remove_constraints, $row["constraint_fi"]); 1731 } 1732 $affectedRows = $ilDB->manipulateF( 1733 "DELETE FROM svy_qst_constraint WHERE question_fi = %s AND survey_fi = %s", 1734 array('integer','integer'), 1735 array($question_id, $this->getSurveyId()) 1736 ); 1737 foreach ($remove_constraints as $key => $constraint_id) { 1738 $affectedRows = $ilDB->manipulateF( 1739 "DELETE FROM svy_constraint WHERE constraint_id = %s", 1740 array('integer'), 1741 array($constraint_id) 1742 ); 1743 } 1744 } 1745 } 1746 1747 /** 1748 * Remove questions from the survey 1749 * 1750 * @param array $remove_questions An array with the question id's of the questions to remove 1751 * @param array $remove_questionblocks An array with the questionblock id's of the questions blocks to remove 1752 * @access public 1753 */ 1754 public function removeQuestions($remove_questions, $remove_questionblocks) 1755 { 1756 $ilDB = $this->db; 1757 1758 $block_sizes = array(); 1759 foreach ($this->getSurveyQuestions() as $question_id => $data) { 1760 if (in_array($question_id, $remove_questions) or in_array($data["questionblock_id"], $remove_questionblocks)) { 1761 unset($this->questions[array_search($question_id, $this->questions)]); 1762 $this->removeQuestion($question_id); 1763 } elseif ($data["questionblock_id"]) { 1764 $block_sizes[$data["questionblock_id"]]++; 1765 } 1766 } 1767 1768 // blocks with just 1 question need to be deleted 1769 foreach ($block_sizes as $block_id => $size) { 1770 if ($size < 2) { 1771 $remove_questionblocks[] = $block_id; 1772 } 1773 } 1774 1775 foreach (array_unique($remove_questionblocks) as $questionblock_id) { 1776 $affectedRows = $ilDB->manipulateF( 1777 "DELETE FROM svy_qblk WHERE questionblock_id = %s", 1778 array('integer'), 1779 array($questionblock_id) 1780 ); 1781 $affectedRows = $ilDB->manipulateF( 1782 "DELETE FROM svy_qblk_qst WHERE questionblock_fi = %s AND survey_fi = %s", 1783 array('integer','integer'), 1784 array($questionblock_id, $this->getSurveyId()) 1785 ); 1786 } 1787 1788 $this->questions = array_values($this->questions); 1789 $this->saveQuestionsToDb(); 1790 } 1791 1792 /** 1793 * Unfolds question blocks of a question pool 1794 * 1795 * @param array $questionblocks An array of question block id's 1796 * @access public 1797 */ 1798 public function unfoldQuestionblocks($questionblocks) 1799 { 1800 $ilDB = $this->db; 1801 foreach ($questionblocks as $index) { 1802 $affectedRows = $ilDB->manipulateF( 1803 "DELETE FROM svy_qblk WHERE questionblock_id = %s", 1804 array('integer'), 1805 array($index) 1806 ); 1807 $affectedRows = $ilDB->manipulateF( 1808 "DELETE FROM svy_qblk_qst WHERE questionblock_fi = %s AND survey_fi = %s", 1809 array('integer','integer'), 1810 array($index, $this->getSurveyId()) 1811 ); 1812 } 1813 } 1814 1815 public function removeQuestionFromBlock($question_id, $questionblock_id) 1816 { 1817 $ilDB = $this->db; 1818 1819 $affectedRows = $ilDB->manipulateF( 1820 "DELETE FROM svy_qblk_qst WHERE questionblock_fi = %s AND survey_fi = %s AND question_fi = %s", 1821 array('integer','integer','integer'), 1822 array($questionblock_id, $this->getSurveyId(), $question_id) 1823 ); 1824 } 1825 1826 public function addQuestionToBlock($question_id, $questionblock_id) 1827 { 1828 $ilDB = $this->db; 1829 1830 // see #22018 1831 if (!$this->isQuestionInAnyBlock($question_id)) { 1832 $next_id = $ilDB->nextId('svy_qblk_qst'); 1833 $affectedRows = $ilDB->manipulateF( 1834 "INSERT INTO svy_qblk_qst (qblk_qst_id, survey_fi, questionblock_fi, " . 1835 "question_fi) VALUES (%s, %s, %s, %s)", 1836 array('integer', 'integer', 'integer', 'integer'), 1837 array($next_id, $this->getSurveyId(), $questionblock_id, $question_id) 1838 ); 1839 1840 $this->deleteConstraints($question_id); // #13713 1841 } 1842 } 1843 1844 /** 1845 * Is question already in a block? 1846 * 1847 * @param int $a_question_fi question id as in svy_question 1848 * @return bool 1849 */ 1850 public function isQuestionInAnyBlock($a_question_fi) 1851 { 1852 global $DIC; 1853 1854 $ilDB = $DIC->database(); 1855 1856 $set = $ilDB->query("SELECT * FROM svy_qblk_qst " . 1857 " WHERE survey_fi = " . $ilDB->quote($this->getSurveyId(), "integer") . 1858 " AND question_fi = " . $ilDB->quote($a_question_fi, "integer")); 1859 if ($rec = $ilDB->fetchAssoc($set)) { 1860 return true; 1861 } 1862 return false; 1863 } 1864 1865 1866 /** 1867 * Returns the question titles of all questions of a question block 1868 * 1869 * @result array The titles of the the question block questions 1870 * @access public 1871 */ 1872 public function &getQuestionblockQuestions($questionblock_id) 1873 { 1874 $ilDB = $this->db; 1875 $titles = array(); 1876 $result = $ilDB->queryF( 1877 "SELECT svy_question.title, svy_qblk_qst.question_fi, svy_qblk_qst.survey_fi FROM " . 1878 "svy_qblk, svy_qblk_qst, svy_question WHERE svy_qblk.questionblock_id = svy_qblk_qst.questionblock_fi AND " . 1879 "svy_question.question_id = svy_qblk_qst.question_fi AND svy_qblk.questionblock_id = %s", 1880 array('integer'), 1881 array($questionblock_id) 1882 ); 1883 $survey_id = ""; 1884 while ($row = $ilDB->fetchAssoc($result)) { 1885 $titles[$row["question_fi"]] = $row["title"]; 1886 $survey_id = $row["survey_fi"]; 1887 } 1888 $result = $ilDB->queryF( 1889 "SELECT question_fi, sequence FROM svy_svy_qst WHERE survey_fi = %s ORDER BY sequence", 1890 array('integer'), 1891 array($survey_id) 1892 ); 1893 $resultarray = array(); 1894 $counter = 1; 1895 while ($row = $ilDB->fetchAssoc($result)) { 1896 if (array_key_exists($row["question_fi"], $titles)) { 1897 $resultarray[$counter++] = $titles[$row["question_fi"]]; 1898 } 1899 } 1900 return $resultarray; 1901 } 1902 1903 /** 1904 * Returns the question id's of all questions of a question block 1905 * 1906 * @result array The id's of the the question block questions 1907 * @access public 1908 */ 1909 public function &getQuestionblockQuestionIds($questionblock_id) 1910 { 1911 $ilDB = $this->db; 1912 1913 // we need a correct order here, see #22011 1914 $result = $ilDB->queryF( 1915 "SELECT a.question_fi FROM svy_qblk_qst a JOIN svy_svy_qst b ON (a.question_fi = b.question_fi) " . 1916 " WHERE a.questionblock_fi = %s ORDER BY b.sequence", 1917 array("integer"), 1918 array($questionblock_id) 1919 ); 1920 $ids = array(); 1921 if ($result->numRows()) { 1922 while ($data = $ilDB->fetchAssoc($result)) { 1923 if (!in_array($data['question_fi'], $ids)) { // no duplicates, see #22018 1924 array_push($ids, $data['question_fi']); 1925 } 1926 } 1927 } 1928 1929 return $ids; 1930 } 1931 1932 /** 1933 * Returns the database row for a given question block 1934 * 1935 * @param integer $questionblock_id The database id of the question block 1936 * @result array The database row of the question block 1937 * @access public 1938 */ 1939 public static function _getQuestionblock($questionblock_id) 1940 { 1941 global $DIC; 1942 1943 $ilDB = $DIC->database(); 1944 $result = $ilDB->queryF( 1945 "SELECT * FROM svy_qblk WHERE questionblock_id = %s", 1946 array('integer'), 1947 array($questionblock_id) 1948 ); 1949 $row = $ilDB->fetchAssoc($result); 1950 return $row; 1951 } 1952 1953 /** 1954 * Adds a questionblock to the database 1955 * 1956 * @param string $title The questionblock title 1957 * @param integer $owner The database id of the owner 1958 * @return integer The database id of the newly created questionblock 1959 * @access public 1960 */ 1961 public static function _addQuestionblock($title = "", $owner = 0, $show_questiontext = true, $show_blocktitle = false) 1962 { 1963 global $DIC; 1964 1965 $ilDB = $DIC->database(); 1966 $next_id = $ilDB->nextId('svy_qblk'); 1967 $ilDB->manipulateF( 1968 "INSERT INTO svy_qblk (questionblock_id, title, show_questiontext," . 1969 " show_blocktitle, owner_fi, tstamp) " . 1970 "VALUES (%s, %s, %s, %s, %s, %s)", 1971 array('integer','text','integer','integer','integer','integer'), 1972 array($next_id, $title, $show_questiontext, $show_blocktitle, $owner, time()) 1973 ); 1974 return $next_id; 1975 } 1976 1977 /** 1978 * Creates a question block for the survey 1979 * 1980 * @param string $title The title of the question block 1981 * @param array $questions An array with the database id's of the question block questions 1982 * @access public 1983 */ 1984 public function createQuestionblock($title, $show_questiontext, $show_blocktitle, $questions) 1985 { 1986 $ilDB = $this->db; 1987 1988 // if the selected questions are not in a continous selection, move all questions of the 1989 // questionblock at the position of the first selected question 1990 $this->moveQuestions($questions, $questions[0], 0); 1991 1992 // now save the question block 1993 $ilUser = $this->user; 1994 $next_id = $ilDB->nextId('svy_qblk'); 1995 $affectedRows = $ilDB->manipulateF( 1996 "INSERT INTO svy_qblk (questionblock_id, title, show_questiontext," . 1997 " show_blocktitle, owner_fi, tstamp) VALUES (%s, %s, %s, %s, %s, %s)", 1998 array('integer','text','text','text','integer','integer'), 1999 array($next_id, $title, $show_questiontext, $show_blocktitle, $ilUser->getId(), time()) 2000 ); 2001 if ($affectedRows) { 2002 $questionblock_id = $next_id; 2003 foreach ($questions as $index) { 2004 if (!$this->isQuestionInAnyBlock($index)) { 2005 $next_id = $ilDB->nextId('svy_qblk_qst'); // #22018 2006 $affectedRows = $ilDB->manipulateF( 2007 "INSERT INTO svy_qblk_qst (qblk_qst_id, survey_fi, questionblock_fi, " . 2008 "question_fi) VALUES (%s, %s, %s, %s)", 2009 array('integer', 'integer', 'integer', 'integer'), 2010 array($next_id, $this->getSurveyId(), $questionblock_id, $index) 2011 ); 2012 $this->deleteConstraints($index); 2013 } 2014 } 2015 } 2016 } 2017 2018 /** 2019 * Modifies a question block 2020 * 2021 * @param integer $questionblock_id The database id of the question block 2022 * @param string $title The title of the question block 2023 * @access public 2024 */ 2025 public function modifyQuestionblock($questionblock_id, $title, $show_questiontext, $show_blocktitle) 2026 { 2027 $ilDB = $this->db; 2028 $affectedRows = $ilDB->manipulateF( 2029 "UPDATE svy_qblk SET title = %s, show_questiontext = %s," . 2030 " show_blocktitle = %s WHERE questionblock_id = %s", 2031 array('text','text','text','integer'), 2032 array($title, $show_questiontext, $show_blocktitle, $questionblock_id) 2033 ); 2034 } 2035 2036 /** 2037 * Deletes the constraints for a question 2038 * 2039 * @param integer $question_id The database id of the question 2040 * @access public 2041 */ 2042 public function deleteConstraints($question_id) 2043 { 2044 $ilDB = $this->db; 2045 $result = $ilDB->queryF( 2046 "SELECT constraint_fi FROM svy_qst_constraint WHERE question_fi = %s AND survey_fi = %s", 2047 array('integer','integer'), 2048 array($question_id, $this->getSurveyId()) 2049 ); 2050 $constraints = array(); 2051 while ($row = $ilDB->fetchAssoc($result)) { 2052 array_push($constraints, $row["constraint_fi"]); 2053 } 2054 foreach ($constraints as $constraint_id) { 2055 $this->deleteConstraint($constraint_id); 2056 } 2057 } 2058 2059 /** 2060 * Deletes a constraint of a question 2061 * 2062 * @param integer $constraint_id The database id of the constraint 2063 * @param integer $question_id The database id of the question 2064 * @access public 2065 */ 2066 public function deleteConstraint($constraint_id) 2067 { 2068 $ilDB = $this->db; 2069 $affectedRows = $ilDB->manipulateF( 2070 "DELETE FROM svy_constraint WHERE constraint_id = %s", 2071 array('integer'), 2072 array($constraint_id) 2073 ); 2074 $affectedRows = $ilDB->manipulateF( 2075 "DELETE FROM svy_qst_constraint WHERE constraint_fi = %s", 2076 array('integer'), 2077 array($constraint_id) 2078 ); 2079 } 2080 2081 /** 2082 * Returns the survey questions and questionblocks in an array 2083 * 2084 * @access public 2085 */ 2086 public function &getSurveyQuestions($with_answers = false) 2087 { 2088 $ilDB = $this->db; 2089 // get questionblocks 2090 $all_questions = array(); 2091 $result = $ilDB->queryF( 2092 "SELECT svy_qtype.type_tag, svy_qtype.plugin, svy_question.question_id, " . 2093 "svy_svy_qst.heading FROM svy_qtype, svy_question, svy_svy_qst WHERE svy_svy_qst.survey_fi = %s AND " . 2094 "svy_svy_qst.question_fi = svy_question.question_id AND svy_question.questiontype_fi = svy_qtype.questiontype_id " . 2095 "ORDER BY svy_svy_qst.sequence", 2096 array('integer'), 2097 array($this->getSurveyId()) 2098 ); 2099 while ($row = $ilDB->fetchAssoc($result)) { 2100 $add = true; 2101 if ($row["plugin"]) { 2102 if (!$this->isPluginActive($row["type_tag"])) { 2103 $add = false; 2104 } 2105 } 2106 if ($add) { 2107 $question = self::_instanciateQuestion($row["question_id"]); 2108 $questionrow = $question->getQuestionDataArray($row["question_id"]); 2109 foreach ($row as $key => $value) { 2110 $questionrow[$key] = $value; 2111 } 2112 $all_questions[$row["question_id"]] = $questionrow; 2113 $all_questions[$row["question_id"]]["usableForPrecondition"] = $question->usableForPrecondition(); 2114 $all_questions[$row["question_id"]]["availableRelations"] = $question->getAvailableRelations(); 2115 } 2116 } 2117 // get all questionblocks 2118 $questionblocks = array(); 2119 if (count($all_questions)) { 2120 $result = $ilDB->queryF( 2121 "SELECT svy_qblk.*, svy_qblk_qst.question_fi FROM svy_qblk, svy_qblk_qst WHERE " . 2122 "svy_qblk.questionblock_id = svy_qblk_qst.questionblock_fi AND svy_qblk_qst.survey_fi = %s " . 2123 "AND " . $ilDB->in('svy_qblk_qst.question_fi', array_keys($all_questions), false, 'integer'), 2124 array('integer'), 2125 array($this->getSurveyId()) 2126 ); 2127 while ($row = $ilDB->fetchAssoc($result)) { 2128 $questionblocks[$row['question_fi']] = $row; 2129 } 2130 } 2131 2132 foreach ($all_questions as $question_id => $row) { 2133 $constraints = $this->getConstraints($question_id); 2134 if (isset($questionblocks[$question_id])) { 2135 $all_questions[$question_id]["questionblock_title"] = $questionblocks[$question_id]['title']; 2136 $all_questions[$question_id]["questionblock_id"] = $questionblocks[$question_id]['questionblock_id']; 2137 $all_questions[$question_id]["constraints"] = $constraints; 2138 } else { 2139 $all_questions[$question_id]["questionblock_title"] = ""; 2140 $all_questions[$question_id]["questionblock_id"] = ""; 2141 $all_questions[$question_id]["constraints"] = $constraints; 2142 } 2143 if ($with_answers) { 2144 $answers = array(); 2145 $result = $ilDB->queryF( 2146 "SELECT svy_variable.*, svy_category.title FROM svy_variable, svy_category " . 2147 "WHERE svy_variable.question_fi = %s AND svy_variable.category_fi = svy_category.category_id " . 2148 "ORDER BY sequence ASC", 2149 array('integer'), 2150 array($question_id) 2151 ); 2152 if ($result->numRows() > 0) { 2153 while ($data = $ilDB->fetchAssoc($result)) { 2154 array_push($answers, $data["title"]); 2155 } 2156 } 2157 $all_questions[$question_id]["answers"] = $answers; 2158 } 2159 } 2160 return $all_questions; 2161 } 2162 2163 /** 2164 * Sets the obligatory states for questions in a survey from the questions form 2165 * 2166 * @param array $obligatory_questions The questions which should be set obligatory from the questions form, the remaining questions should be setted not obligatory 2167 * @access public 2168 */ 2169 public function setObligatoryStates($obligatory_questions) 2170 { 2171 $ilDB = $this->db; 2172 $result = $ilDB->queryF( 2173 "SELECT * FROM svy_svy_qst WHERE survey_fi = %s", 2174 array('integer'), 2175 array($this->getSurveyId()) 2176 ); 2177 if ($result->numRows()) { 2178 while ($row = $ilDB->fetchAssoc($result)) { 2179 if (!array_key_exists($row["question_fi"], $obligatory_questions)) { 2180 $obligatory_questions[$row["question_fi"]] = 0; 2181 } 2182 } 2183 } 2184 2185 // set the obligatory states in the database 2186 foreach ($obligatory_questions as $question_fi => $obligatory) { 2187 // #12420 2188 $ilDB->manipulate("UPDATE svy_question" . 2189 " SET obligatory = " . $ilDB->quote($obligatory, "integer") . 2190 " WHERE question_id = " . $ilDB->quote($question_fi, "integer")); 2191 } 2192 } 2193 2194 /** 2195 * Returns the survey pages in an array (a page contains one or more questions) 2196 * 2197 * @access public 2198 */ 2199 public function &getSurveyPages() 2200 { 2201 $ilDB = $this->db; 2202 // get questionblocks 2203 $all_questions = array(); 2204 $result = $ilDB->queryF( 2205 "SELECT svy_question.*, svy_qtype.type_tag, svy_svy_qst.heading FROM " . 2206 "svy_question, svy_qtype, svy_svy_qst WHERE svy_svy_qst.survey_fi = %s AND " . 2207 "svy_svy_qst.question_fi = svy_question.question_id AND svy_question.questiontype_fi = svy_qtype.questiontype_id " . 2208 "ORDER BY svy_svy_qst.sequence", 2209 array('integer'), 2210 array($this->getSurveyId()) 2211 ); 2212 while ($row = $ilDB->fetchAssoc($result)) { 2213 $all_questions[$row["question_id"]] = $row; 2214 } 2215 // get all questionblocks 2216 $questionblocks = array(); 2217 if (count($all_questions)) { 2218 $result = $ilDB->queryF( 2219 "SELECT svy_qblk.*, svy_qblk_qst.question_fi FROM svy_qblk, svy_qblk_qst " . 2220 "WHERE svy_qblk.questionblock_id = svy_qblk_qst.questionblock_fi AND svy_qblk_qst.survey_fi = %s " . 2221 "AND " . $ilDB->in('svy_qblk_qst.question_fi', array_keys($all_questions), false, 'integer'), 2222 array('integer'), 2223 array($this->getSurveyId()) 2224 ); 2225 while ($row = $ilDB->fetchAssoc($result)) { 2226 $questionblocks[$row['question_fi']] = $row; 2227 } 2228 } 2229 2230 $all_pages = array(); 2231 $pageindex = -1; 2232 $currentblock = ""; 2233 foreach ($all_questions as $question_id => $row) { 2234 $constraints = array(); 2235 if (isset($questionblocks[$question_id])) { 2236 if (!$currentblock or ($currentblock != $questionblocks[$question_id]['questionblock_id'])) { 2237 $pageindex++; 2238 } 2239 $all_questions[$question_id]['page'] = $pageindex; 2240 $all_questions[$question_id]["questionblock_title"] = $questionblocks[$question_id]['title']; 2241 $all_questions[$question_id]["questionblock_id"] = $questionblocks[$question_id]['questionblock_id']; 2242 $all_questions[$question_id]["questionblock_show_questiontext"] = $questionblocks[$question_id]['show_questiontext']; 2243 $all_questions[$question_id]["questionblock_show_blocktitle"] = $questionblocks[$question_id]['show_blocktitle']; 2244 $currentblock = $questionblocks[$question_id]['questionblock_id']; 2245 $constraints = $this->getConstraints($question_id); 2246 $all_questions[$question_id]["constraints"] = $constraints; 2247 } else { 2248 $pageindex++; 2249 $all_questions[$question_id]['page'] = $pageindex; 2250 $all_questions[$question_id]["questionblock_title"] = ""; 2251 $all_questions[$question_id]["questionblock_id"] = ""; 2252 $all_questions[$question_id]["questionblock_show_questiontext"] = 1; 2253 $all_questions[$question_id]["questionblock_show_blocktitle"] = 1; 2254 $currentblock = ""; 2255 $constraints = $this->getConstraints($question_id); 2256 $all_questions[$question_id]["constraints"] = $constraints; 2257 } 2258 if (!isset($all_pages[$pageindex])) { 2259 $all_pages[$pageindex] = array(); 2260 } 2261 array_push($all_pages[$pageindex], $all_questions[$question_id]); 2262 } 2263 // calculate position percentage for every page 2264 $max = count($all_pages); 2265 $counter = 1; 2266 foreach ($all_pages as $index => $block) { 2267 foreach ($block as $blockindex => $question) { 2268 $all_pages[$index][$blockindex]["position"] = $counter / $max; 2269 } 2270 $counter++; 2271 } 2272 2273 return $all_pages; 2274 } 2275 2276 /** 2277 * Returns the next "page" of a running test 2278 * 2279 * @param integer $active_page_question_id The database id of one of the questions on that page 2280 * @param integer $direction The direction of the next page (-1 = previous page, 1 = next page) 2281 * @return mixed An array containing the question id's of the questions on the next page if there is a next page, 0 if the next page is before the start page, 1 if the next page is after the last page 2282 * @access public 2283 */ 2284 public function getNextPage($active_page_question_id, $direction) 2285 { 2286 $foundpage = -1; 2287 $pages = &$this->getSurveyPages(); 2288 if (strcmp($active_page_question_id, "") == 0) { 2289 return $pages[0]; 2290 } 2291 foreach ($pages as $key => $question_array) { 2292 foreach ($question_array as $question) { 2293 if ($active_page_question_id == $question["question_id"]) { 2294 $foundpage = $key; 2295 } 2296 } 2297 } 2298 if ($foundpage == -1) { 2299 // error: page not found 2300 } else { 2301 $foundpage += $direction; 2302 if ($foundpage < 0) { 2303 return 0; 2304 } 2305 if ($foundpage >= count($pages)) { 2306 return 1; 2307 } 2308 return $pages[$foundpage]; 2309 } 2310 } 2311 2312 /** 2313 * Returns the available question pools for the active user 2314 * 2315 * @return array The available question pools 2316 * @access public 2317 */ 2318 public function &getAvailableQuestionpools($use_obj_id = false, $could_be_offline = false, $showPath = false, $permission = "read") 2319 { 2320 return ilObjSurveyQuestionPool::_getAvailableQuestionpools($use_obj_id, $could_be_offline, $showPath, $permission); 2321 } 2322 2323 /** 2324 * Returns a precondition with a given id 2325 * 2326 * @access public 2327 */ 2328 public function getPrecondition($id) 2329 { 2330 $ilDB = $this->db; 2331 2332 $result_array = array(); 2333 $result = $ilDB->queryF( 2334 "SELECT svy_constraint.*, svy_relation.*, svy_qst_constraint.question_fi ref_question_fi FROM svy_qst_constraint, svy_constraint, " . 2335 "svy_relation WHERE svy_constraint.relation_fi = svy_relation.relation_id AND " . 2336 "svy_qst_constraint.constraint_fi = svy_constraint.constraint_id AND svy_constraint.constraint_id = %s", 2337 array('integer'), 2338 array($id) 2339 ); 2340 $pc = array(); 2341 if ($result->numRows()) { 2342 $pc = $ilDB->fetchAssoc($result); 2343 } 2344 return $pc; 2345 } 2346 2347 /** 2348 * Returns the constraints to a given question or questionblock 2349 * 2350 * @access public 2351 */ 2352 public function getConstraints($question_id) 2353 { 2354 $ilDB = $this->db; 2355 2356 $result_array = array(); 2357 $result = $ilDB->queryF( 2358 "SELECT svy_constraint.*, svy_relation.* FROM svy_qst_constraint, svy_constraint, svy_relation " . 2359 "WHERE svy_constraint.relation_fi = svy_relation.relation_id AND " . 2360 "svy_qst_constraint.constraint_fi = svy_constraint.constraint_id AND svy_qst_constraint.question_fi = %s " . 2361 "AND svy_qst_constraint.survey_fi = %s", 2362 array('integer','integer'), 2363 array($question_id, $this->getSurveyId()) 2364 ); 2365 while ($row = $ilDB->fetchAssoc($result)) { 2366 $question_type = SurveyQuestion::_getQuestionType($row["question_fi"]); 2367 SurveyQuestion::_includeClass($question_type); 2368 $question = new $question_type(); 2369 $question->loadFromDb($row["question_fi"]); 2370 $valueoutput = $question->getPreconditionValueOutput($row["value"]); 2371 array_push($result_array, array("id" => $row["constraint_id"], "question" => $row["question_fi"], "short" => $row["shortname"], "long" => $row["longname"], "value" => $row["value"], "conjunction" => $row["conjunction"], "valueoutput" => $valueoutput)); 2372 } 2373 return $result_array; 2374 } 2375 2376 /** 2377 * Returns the constraints to a given question or questionblock 2378 * 2379 * @access public 2380 */ 2381 public static function _getConstraints($survey_id) 2382 { 2383 global $DIC; 2384 2385 $ilDB = $DIC->database(); 2386 $result_array = array(); 2387 $result = $ilDB->queryF( 2388 "SELECT svy_qst_constraint.question_fi as for_question, svy_constraint.*, svy_relation.* " . 2389 "FROM svy_qst_constraint, svy_constraint, svy_relation WHERE svy_constraint.relation_fi = svy_relation.relation_id " . 2390 "AND svy_qst_constraint.constraint_fi = svy_constraint.constraint_id AND svy_qst_constraint.survey_fi = %s", 2391 array('integer'), 2392 array($survey_id) 2393 ); 2394 while ($row = $ilDB->fetchAssoc($result)) { 2395 array_push($result_array, array("id" => $row["constraint_id"], "for_question" => $row["for_question"], "question" => $row["question_fi"], "short" => $row["shortname"], "long" => $row["longname"], "relation_id" => $row["relation_id"], "value" => $row["value"], 'conjunction' => $row['conjunction'])); 2396 } 2397 return $result_array; 2398 } 2399 2400 2401 /** 2402 * Returns all variables of a question 2403 * 2404 * @access public 2405 */ 2406 public function &getVariables($question_id) 2407 { 2408 $ilDB = $this->db; 2409 2410 $result_array = array(); 2411 $result = $ilDB->queryF( 2412 "SELECT svy_variable.*, svy_category.title FROM svy_variable LEFT JOIN " . 2413 "svy_category ON svy_variable.category_fi = svy_category.category_id WHERE svy_variable.question_fi = %s " . 2414 "ORDER BY svy_variable.sequence", 2415 array('integer'), 2416 array($question_id) 2417 ); 2418 while ($row = $ilDB->fetchObject($result)) { 2419 $result_array[$row->sequence] = $row; 2420 } 2421 return $result_array; 2422 } 2423 2424 /** 2425 * Adds a constraint 2426 * 2427 * @param integer $if_question_id The question id of the question which defines a precondition 2428 * @param integer $relation The database id of the relation 2429 * @param mixed $value The value compared with the relation 2430 * @access public 2431 */ 2432 public function addConstraint($if_question_id, $relation, $value, $conjunction) 2433 { 2434 $ilDB = $this->db; 2435 2436 $next_id = $ilDB->nextId('svy_constraint'); 2437 $affectedRows = $ilDB->manipulateF( 2438 "INSERT INTO svy_constraint (constraint_id, question_fi, relation_fi, value, conjunction) VALUES " . 2439 "(%s, %s, %s, %s, %s)", 2440 array('integer','integer','integer','float', 'integer'), 2441 array($next_id, $if_question_id, $relation, $value, $conjunction) 2442 ); 2443 if ($affectedRows) { 2444 return $next_id; 2445 } else { 2446 return null; 2447 } 2448 } 2449 2450 2451 /** 2452 * Adds a constraint to a question 2453 * 2454 * @param integer $to_question_id The question id of the question where to add the constraint 2455 * @param integer $constraint_id The id of the constraint 2456 */ 2457 public function addConstraintToQuestion($to_question_id, $constraint_id) 2458 { 2459 $ilDB = $this->db; 2460 2461 $next_id = $ilDB->nextId('svy_qst_constraint'); 2462 $affectedRows = $ilDB->manipulateF( 2463 "INSERT INTO svy_qst_constraint (question_constraint_id, survey_fi, question_fi, " . 2464 "constraint_fi) VALUES (%s, %s, %s, %s)", 2465 array('integer','integer','integer','integer'), 2466 array($next_id, $this->getSurveyId(), $to_question_id, $constraint_id) 2467 ); 2468 } 2469 2470 /** 2471 * Updates a precondition 2472 * 2473 * @param integer $precondition_id The id of the original precondition 2474 * @param integer $to_question_id The question id of the question where to add the constraint 2475 * @param integer $if_question_id The question id of the question which defines a precondition 2476 * @param integer $relation The database id of the relation 2477 * @param mixed $value The value compared with the relation 2478 * @access public 2479 */ 2480 public function updateConstraint($precondition_id, $if_question_id, $relation, $value, $conjunction) 2481 { 2482 $ilDB = $this->db; 2483 $affectedRows = $ilDB->manipulateF( 2484 "UPDATE svy_constraint SET question_fi = %s, relation_fi = %s, value = %s, conjunction = %s " . 2485 "WHERE constraint_id = %s", 2486 array('integer','integer','float','integer','integer'), 2487 array($if_question_id, $relation, $value, $conjunction, $precondition_id) 2488 ); 2489 } 2490 2491 public function updateConjunctionForQuestions($questions, $conjunction) 2492 { 2493 $ilDB = $this->db; 2494 foreach ($questions as $question_id) { 2495 $affectedRows = $ilDB->manipulateF( 2496 "UPDATE svy_constraint SET conjunction = %s " . 2497 "WHERE constraint_id IN (SELECT constraint_fi FROM svy_qst_constraint WHERE svy_qst_constraint.question_fi = %s)", 2498 array('integer','integer'), 2499 array($conjunction, $question_id) 2500 ); 2501 } 2502 } 2503 2504 /** 2505 * Returns all available relations 2506 * 2507 * @access public 2508 */ 2509 public function getAllRelations($short_as_key = false) 2510 { 2511 $ilDB = $this->db; 2512 2513 // #7987 2514 $custom_order = array("equal", "not_equal", "less", "less_or_equal", "more", "more_or_equal"); 2515 $custom_order = array_flip($custom_order); 2516 2517 $result_array = array(); 2518 $result = $ilDB->query("SELECT * FROM svy_relation"); 2519 while ($row = $ilDB->fetchAssoc($result)) { 2520 if ($short_as_key) { 2521 $result_array[$row["shortname"]] = array("short" => $row["shortname"], "long" => $row["longname"], "id" => $row["relation_id"], "order" => $custom_order[$row["longname"]]); 2522 } else { 2523 $result_array[$row["relation_id"]] = array("short" => $row["shortname"], "long" => $row["longname"], "order" => $custom_order[$row["longname"]]); 2524 } 2525 } 2526 2527 $result_array = ilUtil::sortArray($result_array, "order", "ASC", true, true); 2528 foreach ($result_array as $idx => $item) { 2529 unset($result_array[$idx]["order"]); 2530 } 2531 2532 return $result_array; 2533 } 2534 2535 2536 2537 2538 /** 2539 * Deletes the working data of a question in the database 2540 * 2541 * @param integer $question_id The database id of the question 2542 * @param integer $active_id The active id of the user who worked through the question 2543 * @access public 2544 */ 2545 public function deleteWorkingData($question_id, $active_id) 2546 { 2547 $ilDB = $this->db; 2548 2549 $affectedRows = $ilDB->manipulateF( 2550 "DELETE FROM svy_answer WHERE question_fi = %s AND active_fi = %s", 2551 array('integer','integer'), 2552 array($question_id, $active_id) 2553 ); 2554 } 2555 2556 /** 2557 * Gets the working data of question from the database 2558 * 2559 * @param integer $question_id The database id of the question 2560 * @param integer $active_id The active id of the user who worked through the question 2561 * @return array The resulting database dataset as an array 2562 * @access public 2563 */ 2564 public function loadWorkingData($question_id, $active_id) 2565 { 2566 $ilDB = $this->db; 2567 $result_array = array(); 2568 $result = $ilDB->queryF( 2569 "SELECT * FROM svy_answer WHERE question_fi = %s AND active_fi = %s", 2570 array('integer','integer'), 2571 array($question_id, $active_id) 2572 ); 2573 if ($result->numRows() >= 1) { 2574 while ($row = $ilDB->fetchAssoc($result)) { 2575 array_push($result_array, $row); 2576 } 2577 return $result_array; 2578 } else { 2579 return $result_array; 2580 } 2581 } 2582 2583 /** 2584 * Starts the survey creating an entry in the database 2585 * 2586 * @param integer $user_id The database id of the user who starts the survey 2587 * @access public 2588 */ 2589 public function startSurvey($user_id, $anonymous_id, $appraisee_id) 2590 { 2591 $ilDB = $this->db; 2592 2593 if ($this->getAnonymize() && (strlen($anonymous_id) == 0)) { 2594 return; 2595 } 2596 2597 if (strcmp($user_id, "") == 0) { 2598 if ($user_id == ANONYMOUS_USER_ID) { 2599 $user_id = 0; 2600 } 2601 } 2602 $next_id = $ilDB->nextId('svy_finished'); 2603 $affectedRows = $ilDB->manipulateF( 2604 "INSERT INTO svy_finished (finished_id, survey_fi, user_fi, anonymous_id, state, tstamp, appr_id) " . 2605 "VALUES (%s, %s, %s, %s, %s, %s, %s)", 2606 array('integer','integer','integer','text','text','integer','integer'), 2607 array($next_id, $this->getSurveyId(), $user_id, $anonymous_id, 0, time(), $appraisee_id) 2608 ); 2609 return $next_id; 2610 } 2611 2612 /** 2613 * Finishes the survey creating an entry in the database 2614 * 2615 * @param integer $user_id The database id of the user who finishes the survey 2616 * @access public 2617 */ 2618 public function finishSurvey($finished_id) 2619 { 2620 $ilDB = $this->db; 2621 2622 $ilDB->manipulateF( 2623 "UPDATE svy_finished SET state = %s, tstamp = %s" . 2624 " WHERE survey_fi = %s AND finished_id = %s", 2625 array('text','integer','integer','integer'), 2626 array(1, time(), $this->getSurveyId(), $finished_id) 2627 ); 2628 2629 // self eval writes skills on finishing 2630 if ($this->getMode() == ilObjSurvey::MODE_SELF_EVAL) { 2631 $user = $this->getUserDataFromActiveId($finished_id); 2632 $sskill = new ilSurveySkill($this); 2633 $sskill->writeAndAddSelfEvalSkills($user['usr_id']); 2634 } 2635 2636 $this->checkTutorNotification(); 2637 } 2638 2639 /** 2640 * Sets the number of the active survey page 2641 * 2642 * @param integer $finished_id The database id of the active user 2643 * @param integer $page_id The index of the page 2644 * @access public 2645 */ 2646 public function setPage($finished_id, $page_id) 2647 { 2648 $ilDB = $this->db; 2649 2650 $affectedRows = $ilDB->manipulateF( 2651 "UPDATE svy_finished SET lastpage = %s WHERE finished_id = %s", 2652 array('integer','integer'), 2653 array(($page_id) ? $page_id : 0, $finished_id) 2654 ); 2655 } 2656 2657 /** 2658 * @param $a_user_id user who did the survey 2659 * @param $a_anonymize_id 2660 * @param $a_appr_id 2661 */ 2662 public function sendNotificationMail($a_user_id, $a_anonymize_id, $a_appr_id) 2663 { 2664 // #12755 2665 $placeholders = array( 2666 "FIRST_NAME" => "firstname", 2667 "LAST_NAME" => "lastname", 2668 "LOGIN" => "login", 2669 // old style 2670 "firstname" => "firstname" 2671 ); 2672 2673 //mailaddresses is just text split by commas. 2674 //sendMail can send emails if it gets an user id or an email as first parameter. 2675 $recipients = preg_split('/,/', $this->mailaddresses); 2676 foreach ($recipients as $recipient) { 2677 // #11298 2678 $ntf = new ilSystemNotification(); 2679 $ntf->setLangModules(array("survey")); 2680 $ntf->setRefId($this->getRefId()); 2681 $ntf->setSubjectLangId('finished_mail_subject'); 2682 2683 $messagetext = $this->mailparticipantdata; 2684 if (trim($messagetext)) { 2685 if (!$this->hasAnonymizedResults()) { 2686 $data = ilObjUser::_getUserData(array($a_user_id)); 2687 $data = $data[0]; 2688 } 2689 foreach ($placeholders as $key => $mapping) { 2690 if ($this->hasAnonymizedResults()) { // #16480 2691 $messagetext = str_replace('[' . $key . ']', '', $messagetext); 2692 } else { 2693 $messagetext = str_replace('[' . $key . ']', trim($data[$mapping]), $messagetext); 2694 } 2695 } 2696 $ntf->setIntroductionDirect($messagetext); 2697 } else { 2698 $ntf->setIntroductionLangId('survey_notification_finished_introduction'); 2699 } 2700 2701 // 360°? add appraisee data 2702 if ($a_appr_id) { 2703 $ntf->addAdditionalInfo( 2704 'survey_360_appraisee', 2705 ilUserUtil::getNamePresentation($a_appr_id) 2706 ); 2707 } 2708 2709 $active_id = $this->getActiveID($a_user_id, $a_anonymize_id, $a_appr_id); 2710 $ntf->addAdditionalInfo( 2711 'results', 2712 $this->getParticipantTextResults($active_id), 2713 true 2714 ); 2715 2716 $ntf->setGotoLangId('survey_notification_tutor_link'); 2717 $ntf->setReasonLangId('survey_notification_finished_reason'); 2718 2719 if (is_numeric($recipient)) { 2720 $lng = $ntf->getUserLanguage($recipient); 2721 $ntf->sendMail(array($recipient), null, null); 2722 } else { 2723 $recipient = trim($recipient); 2724 $user_ids = ilObjUser::getUserIdsByEmail($recipient); 2725 if (empty($user_ids)) { 2726 $ntf->sendMail(array($recipient), null, null); 2727 } else { 2728 foreach ($user_ids as $user_id) { 2729 $lng = $ntf->getUserLanguage($user_id); 2730 $ntf->sendMail(array($user_id), null, null); 2731 } 2732 } 2733 } 2734 } 2735 } 2736 2737 protected function getParticipantTextResults($active_id) 2738 { 2739 $textresult = ""; 2740 $userResults = &$this->getUserSpecificResults(array($active_id)); 2741 $questions = &$this->getSurveyQuestions(true); 2742 $questioncounter = 1; 2743 foreach ($questions as $question_id => $question_data) { 2744 $textresult .= $questioncounter++ . ". " . $question_data["title"] . "\n"; 2745 $found = $userResults[$question_id][$active_id]; 2746 $text = ""; 2747 if (is_array($found)) { 2748 $text = implode("\n", $found); 2749 } else { 2750 $text = $found; 2751 } 2752 if (strlen($text) == 0) { 2753 $text = self::getSurveySkippedValue(); 2754 } 2755 $text = str_replace("<br />", "\n", $text); 2756 $textresult .= $text . "\n\n"; 2757 } 2758 return $textresult; 2759 } 2760 2761 /** 2762 * Checks if a user already started a survey 2763 * 2764 * @param integer $user_id The database id of the user 2765 * @return mixed false, if the user has not started the survey, 0 if the user has started the survey but not finished it, 1 if the user has finished the survey 2766 * @access public 2767 */ 2768 public function isSurveyStarted($user_id, $anonymize_id, $appr_id = 0) 2769 { 2770 $ilDB = $this->db; 2771 2772 // #15031 - should not matter if code was used by registered or anonymous (each code must be unique) 2773 if ($anonymize_id) { 2774 $result = $ilDB->queryF( 2775 "SELECT * FROM svy_finished" . 2776 " WHERE survey_fi = %s AND anonymous_id = %s AND appr_id = %s", 2777 array('integer','text','integer'), 2778 array($this->getSurveyId(), $anonymize_id, $appr_id) 2779 ); 2780 } else { 2781 $result = $ilDB->queryF( 2782 "SELECT * FROM svy_finished" . 2783 " WHERE survey_fi = %s AND user_fi = %s AND appr_id = %s", 2784 array('integer','integer','integer'), 2785 array($this->getSurveyId(), $user_id, $appr_id) 2786 ); 2787 } 2788 if ($result->numRows() == 0) { 2789 return false; 2790 } else { 2791 $row = $ilDB->fetchAssoc($result); 2792 // yes, we are doing it this way 2793 $_SESSION["finished_id"][$this->getId()] = $row["finished_id"]; 2794 2795 return (int) $row["state"]; 2796 } 2797 } 2798 2799 /** 2800 * Checks if a user already started a survey 2801 * 2802 * @param integer $user_id The database id of the user 2803 * @return mixed false, if the user has not started the survey, 0 if the user has started the survey but not finished it, 1 if the user has finished the survey 2804 * @access public 2805 */ 2806 public function getActiveID($user_id, $anonymize_id, $appr_id) 2807 { 2808 $ilDB = $this->db; 2809 2810 // see self::isSurveyStarted() 2811 2812 // #15031 - should not matter if code was used by registered or anonymous (each code must be unique) 2813 if ($anonymize_id) { 2814 $result = $ilDB->queryF( 2815 "SELECT finished_id FROM svy_finished" . 2816 " WHERE survey_fi = %s AND anonymous_id = %s AND appr_id = %s", 2817 array('integer','text','integer'), 2818 array($this->getSurveyId(), $anonymize_id, $appr_id) 2819 ); 2820 } else { 2821 $result = $ilDB->queryF( 2822 "SELECT finished_id FROM svy_finished" . 2823 " WHERE survey_fi = %s AND user_fi = %s AND appr_id = %s", 2824 array('integer','integer','integer'), 2825 array($this->getSurveyId(), $user_id, $appr_id) 2826 ); 2827 } 2828 if ($result->numRows() == 0) { 2829 return false; 2830 } else { 2831 $row = $ilDB->fetchAssoc($result); 2832 return $row["finished_id"]; 2833 } 2834 } 2835 2836 /** 2837 * Returns the question id of the last active page a user visited in a survey 2838 * 2839 * @param integer $active_id The active id of the user 2840 * @return mixed Empty string if the user has not worked through a page, question id of the last page otherwise 2841 * @access public 2842 */ 2843 public function getLastActivePage($active_id) 2844 { 2845 $ilDB = $this->db; 2846 $result = $ilDB->queryF( 2847 "SELECT lastpage FROM svy_finished WHERE finished_id = %s", 2848 array('integer'), 2849 array($active_id) 2850 ); 2851 if ($result->numRows() == 0) { 2852 return ""; 2853 } else { 2854 $row = $ilDB->fetchAssoc($result); 2855 return ($row["lastpage"]) ? $row["lastpage"] : ''; 2856 } 2857 } 2858 2859 /** 2860 * Checks if a constraint is valid 2861 * 2862 * @param array $constraint_data The database row containing the constraint data 2863 * @param array $working_data The user input of the related question 2864 * @return boolean true if the constraint is valid, otherwise false 2865 * @access public 2866 */ 2867 public function checkConstraint($constraint_data, $working_data) 2868 { 2869 if (!is_array($working_data) || count($working_data) == 0) { 2870 return 0; 2871 } 2872 2873 if ((count($working_data) == 1) and (strcmp($working_data[0]["value"], "") == 0)) { 2874 return 0; 2875 } 2876 2877 $found = false; 2878 foreach ($working_data as $data) { 2879 switch ($constraint_data["short"]) { 2880 case "<": 2881 if ($data["value"] < $constraint_data["value"]) { 2882 $found = true; 2883 } 2884 break; 2885 2886 case "<=": 2887 if ($data["value"] <= $constraint_data["value"]) { 2888 $found = true; 2889 } 2890 break; 2891 2892 case "=": 2893 if ($data["value"] == $constraint_data["value"]) { 2894 $found = true; 2895 } 2896 break; 2897 2898 case "<>": 2899 if ($data["value"] <> $constraint_data["value"]) { 2900 $found = true; 2901 } 2902 break; 2903 2904 case ">=": 2905 if ($data["value"] >= $constraint_data["value"]) { 2906 $found = true; 2907 } 2908 break; 2909 2910 case ">": 2911 if ($data["value"] > $constraint_data["value"]) { 2912 $found = true; 2913 } 2914 break; 2915 } 2916 if ($found) { 2917 break; 2918 } 2919 } 2920 2921 return (int) $found; 2922 } 2923 2924 public static function _hasDatasets($survey_id) 2925 { 2926 global $DIC; 2927 2928 $ilDB = $DIC->database(); 2929 2930 $result = $ilDB->queryF( 2931 "SELECT finished_id FROM svy_finished WHERE survey_fi = %s", 2932 array('integer'), 2933 array($survey_id) 2934 ); 2935 return ($result->numRows()) ? true : false; 2936 } 2937 2938 /** 2939 * Get the finished id's of all survey participants 2940 * 2941 * @return array An array containing finished_id's of all survey participants 2942 * @access public 2943 */ 2944 public function &getSurveyFinishedIds() 2945 { 2946 $ilDB = $this->db; 2947 $ilLog = $this->log; 2948 2949 $users = array(); 2950 $result = $ilDB->queryF( 2951 "SELECT * FROM svy_finished WHERE survey_fi = %s", 2952 array('integer'), 2953 array($this->getSurveyId()) 2954 ); 2955 if ($result->numRows()) { 2956 while ($row = $ilDB->fetchAssoc($result)) { 2957 array_push($users, $row["finished_id"]); 2958 } 2959 } 2960 return $users; 2961 } 2962 2963 /** 2964 * Calculates the evaluation data for the user specific results 2965 * 2966 * @return array An array containing the user specific results 2967 * @access public 2968 */ 2969 public function getUserSpecificResults($finished_ids) 2970 { 2971 $evaluation = array(); 2972 2973 foreach (array_keys($this->getSurveyQuestions()) as $question_id) { 2974 // get question instance 2975 $question_type = SurveyQuestion::_getQuestionType($question_id); 2976 SurveyQuestion::_includeClass($question_type); 2977 $question = new $question_type(); 2978 $question->loadFromDb($question_id); 2979 2980 $q_eval = SurveyQuestion::_instanciateQuestionEvaluation($question_id, $finished_ids); 2981 $q_res = $q_eval->getResults(); 2982 2983 $data = array(); 2984 foreach ($finished_ids as $user_id) { 2985 $data[$user_id] = $q_eval->parseUserSpecificResults($q_res, $user_id); 2986 } 2987 2988 $evaluation[$question_id] = $data; 2989 } 2990 2991 return $evaluation; 2992 } 2993 2994 /** 2995 * Returns the user information from an active_id (survey_finished.finished_id) 2996 * 2997 * @param integer $active_id The active id of the user 2998 * @return array An array containing the user data 2999 * @access public 3000 */ 3001 public function getUserDataFromActiveId($active_id, $force_non_anonymous = false) 3002 { 3003 $ilDB = $this->db; 3004 3005 $surveySetting = new ilSetting("survey"); 3006 $use_anonymous_id = $surveySetting->get("use_anonymous_id"); 3007 $result = $ilDB->queryF( 3008 "SELECT * FROM svy_finished WHERE finished_id = %s", 3009 array('integer'), 3010 array($active_id) 3011 ); 3012 $row = array(); 3013 $foundrows = $result->numRows(); 3014 if ($foundrows) { 3015 $row = $ilDB->fetchAssoc($result); 3016 } 3017 $name = ($use_anonymous_id) ? $row["anonymous_id"] : $this->lng->txt("anonymous"); 3018 $userdata = array( 3019 "fullname" => $name, 3020 "sortname" => $name, 3021 "firstname" => "", 3022 "lastname" => "", 3023 "login" => "", 3024 "gender" => "", 3025 "active_id" => "$active_id" 3026 ); 3027 if ($foundrows) { 3028 if (($row["user_fi"] > 0) && 3029 (($row["user_fi"] != ANONYMOUS_USER_ID && 3030 !$this->hasAnonymizedResults() && 3031 !$this->get360Mode()) || // 360° uses ANONYMIZE_CODE_ALL which is wrong - see ilObjSurveyGUI::afterSave() 3032 (bool) $force_non_anonymous)) { 3033 if (strlen(ilObjUser::_lookupLogin($row["user_fi"])) == 0) { 3034 $userdata["fullname"] = $userdata["sortname"] = $this->lng->txt("deleted_user"); 3035 } else { 3036 $user = new ilObjUser($row["user_fi"]); 3037 $userdata['usr_id'] = $row['user_fi']; 3038 $userdata["fullname"] = $user->getFullname(); 3039 $gender = $user->getGender(); 3040 if (strlen($gender) == 1) { 3041 $gender = $this->lng->txt("gender_$gender"); 3042 } 3043 $userdata["gender"] = $gender; 3044 $userdata["firstname"] = $user->getFirstname(); 3045 $userdata["lastname"] = $user->getLastname(); 3046 $userdata["sortname"] = $user->getLastname() . ", " . $user->getFirstname(); 3047 $userdata["login"] = $user->getLogin(); 3048 } 3049 } 3050 } 3051 return $userdata; 3052 } 3053 3054 /** 3055 * Calculates the evaluation data for a given user or anonymous id 3056 * 3057 * @param array $questions An array containing all relevant information on the survey's questions 3058 * @param integer $user_id The database id of the user 3059 * @param string $anonymous_id The unique anonymous id for an anonymous survey 3060 * @return array An array containing the evaluation parameters for the user 3061 * @access public 3062 */ 3063 public function &getEvaluationByUser($questions, $active_id) 3064 { 3065 $ilDB = $this->db; 3066 3067 // collect all answers 3068 $answers = array(); 3069 $result = $ilDB->queryF( 3070 "SELECT * FROM svy_answer WHERE active_fi = %s", 3071 array('integer'), 3072 array($active_id) 3073 ); 3074 while ($row = $ilDB->fetchAssoc($result)) { 3075 if (!is_array($answers[$row["question_fi"]])) { 3076 $answers[$row["question_fi"]] = array(); 3077 } 3078 array_push($answers[$row["question_fi"]], $row); 3079 } 3080 $userdata = $this->getUserDataFromActiveId($active_id); 3081 $resultset = array( 3082 "name" => $userdata["fullname"], 3083 "firstname" => $userdata["firstname"], 3084 "lastname" => $userdata["lastname"], 3085 "login" => $userdata["login"], 3086 "gender" => $userdata["gender"], 3087 "answers" => array() 3088 ); 3089 foreach ($questions as $key => $question) { 3090 if (array_key_exists($key, $answers)) { 3091 $resultset["answers"][$key] = $answers[$key]; 3092 } else { 3093 $resultset["answers"][$key] = array(); 3094 } 3095 sort($resultset["answers"][$key]); 3096 } 3097 return $resultset; 3098 } 3099 3100 /** 3101 * Calculates the data for the output of the question browser 3102 * 3103 * @access public 3104 */ 3105 public function getQuestionsTable($arrFilter) 3106 { 3107 $ilUser = $this->user; 3108 $ilDB = $this->db; 3109 $where = ""; 3110 if (is_array($arrFilter)) { 3111 if (array_key_exists('title', $arrFilter) && strlen($arrFilter['title'])) { 3112 $where .= " AND " . $ilDB->like('svy_question.title', 'text', "%%" . $arrFilter['title'] . "%%"); 3113 } 3114 if (array_key_exists('description', $arrFilter) && strlen($arrFilter['description'])) { 3115 $where .= " AND " . $ilDB->like('svy_question.description', 'text', "%%" . $arrFilter['description'] . "%%"); 3116 } 3117 if (array_key_exists('author', $arrFilter) && strlen($arrFilter['author'])) { 3118 $where .= " AND " . $ilDB->like('svy_question.author', 'text', "%%" . $arrFilter['author'] . "%%"); 3119 } 3120 if (array_key_exists('type', $arrFilter) && strlen($arrFilter['type'])) { 3121 $where .= " AND svy_qtype.type_tag = " . $ilDB->quote($arrFilter['type'], 'text'); 3122 } 3123 if (array_key_exists('spl', $arrFilter) && strlen($arrFilter['spl'])) { 3124 $where .= " AND svy_question.obj_fi = " . $ilDB->quote($arrFilter['spl'], 'integer'); 3125 } 3126 } 3127 3128 $spls = &$this->getAvailableQuestionpools($use_obj_id = true, $could_be_offline = false, $showPath = false); 3129 $forbidden = ""; 3130 $forbidden = " AND " . $ilDB->in('svy_question.obj_fi', array_keys($spls), false, 'integer'); 3131 $forbidden .= " AND svy_question.complete = " . $ilDB->quote("1", 'text'); 3132 $existing = ""; 3133 $existing_questions = &$this->getExistingQuestions(); 3134 if (count($existing_questions)) { 3135 $existing = " AND " . $ilDB->in('svy_question.question_id', $existing_questions, true, 'integer'); 3136 } 3137 3138 $trans = ilObjSurveyQuestionPool::_getQuestionTypeTranslations(); 3139 3140 $query_result = $ilDB->query("SELECT svy_question.*, svy_qtype.type_tag, svy_qtype.plugin, object_reference.ref_id" . 3141 " FROM svy_question, svy_qtype, object_reference" . 3142 " WHERE svy_question.original_id IS NULL" . $forbidden . $existing . 3143 " AND svy_question.obj_fi = object_reference.obj_id AND svy_question.tstamp > 0" . 3144 " AND svy_question.questiontype_fi = svy_qtype.questiontype_id " . $where); 3145 3146 $rows = array(); 3147 if ($query_result->numRows()) { 3148 while ($row = $ilDB->fetchAssoc($query_result)) { 3149 if (array_key_exists('spl_txt', $arrFilter) && strlen($arrFilter['spl_txt'])) { 3150 if (!stristr($spls[$row["obj_fi"]], $arrFilter['spl_txt'])) { 3151 continue; 3152 } 3153 } 3154 3155 $row['ttype'] = $trans[$row['type_tag']]; 3156 if ($row["plugin"]) { 3157 if ($this->isPluginActive($row["type_tag"])) { 3158 array_push($rows, $row); 3159 } 3160 } else { 3161 array_push($rows, $row); 3162 } 3163 } 3164 } 3165 return $rows; 3166 } 3167 3168 /** 3169 * Calculates the data for the output of the questionblock browser 3170 * 3171 * @access public 3172 */ 3173 public function getQuestionblocksTable($arrFilter) 3174 { 3175 $ilUser = $this->user; 3176 $ilDB = $this->db; 3177 3178 $where = ""; 3179 if (is_array($arrFilter)) { 3180 if (array_key_exists('title', $arrFilter) && strlen($arrFilter['title'])) { 3181 $where .= " AND " . $ilDB->like('svy_qblk.title', 'text', "%%" . $arrFilter['title'] . "%%"); 3182 } 3183 } 3184 3185 $query_result = $ilDB->query("SELECT svy_qblk.*, svy_svy.obj_fi FROM svy_qblk , svy_qblk_qst, svy_svy WHERE " . 3186 "svy_qblk.questionblock_id = svy_qblk_qst.questionblock_fi AND svy_svy.survey_id = svy_qblk_qst.survey_fi " . 3187 "$where GROUP BY svy_qblk.questionblock_id, svy_qblk.title, svy_qblk.show_questiontext, svy_qblk.show_blocktitle, " . 3188 "svy_qblk.owner_fi, svy_qblk.tstamp, svy_svy.obj_fi"); 3189 $rows = array(); 3190 if ($query_result->numRows()) { 3191 $survey_ref_ids = ilUtil::_getObjectsByOperations("svy", "write"); 3192 $surveytitles = array(); 3193 foreach ($survey_ref_ids as $survey_ref_id) { 3194 $survey_id = ilObject::_lookupObjId($survey_ref_id); 3195 $surveytitles[$survey_id] = ilObject::_lookupTitle($survey_id); 3196 } 3197 while ($row = $ilDB->fetchAssoc($query_result)) { 3198 $questions_array = &$this->getQuestionblockQuestions($row["questionblock_id"]); 3199 $counter = 1; 3200 foreach ($questions_array as $key => $value) { 3201 $questions_array[$key] = "$counter. $value"; 3202 $counter++; 3203 } 3204 if (strlen($surveytitles[$row["obj_fi"]])) { // only questionpools which are not in trash 3205 $rows[$row["questionblock_id"]] = array( 3206 "questionblock_id" => $row["questionblock_id"], 3207 "title" => $row["title"], 3208 "svy" => $surveytitles[$row["obj_fi"]], 3209 "contains" => join(", ", $questions_array), 3210 "owner" => $row["owner_fi"] 3211 ); 3212 } 3213 } 3214 } 3215 return $rows; 3216 } 3217 3218 /** 3219 * Returns a QTI xml representation of the survey 3220 * 3221 * @return string The QTI xml representation of the survey 3222 * @access public 3223 */ 3224 public function toXML() 3225 { 3226 $a_xml_writer = new ilXmlWriter; 3227 // set xml header 3228 $a_xml_writer->xmlHeader(); 3229 $attrs = array( 3230 "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance", 3231 "xsi:noNamespaceSchemaLocation" => "http://www.ilias.de/download/xsd/ilias_survey_4_2.xsd" 3232 ); 3233 $a_xml_writer->xmlStartTag("surveyobject", $attrs); 3234 $attrs = array( 3235 "id" => $this->getSurveyId(), 3236 "title" => $this->getTitle() 3237 ); 3238 $a_xml_writer->xmlStartTag("survey", $attrs); 3239 3240 $a_xml_writer->xmlElement("description", null, $this->getDescription()); 3241 $a_xml_writer->xmlElement("author", null, $this->getAuthor()); 3242 $a_xml_writer->xmlStartTag("objectives"); 3243 $attrs = array( 3244 "label" => "introduction" 3245 ); 3246 $this->addMaterialTag($a_xml_writer, $this->getIntroduction(), true, true, $attrs); 3247 $attrs = array( 3248 "label" => "outro" 3249 ); 3250 $this->addMaterialTag($a_xml_writer, $this->getOutro(), true, true, $attrs); 3251 $a_xml_writer->xmlEndTag("objectives"); 3252 3253 if ($this->getAnonymize()) { 3254 $attribs = array("enabled" => "1"); 3255 } else { 3256 $attribs = array("enabled" => "0"); 3257 } 3258 $a_xml_writer->xmlElement("anonymisation", $attribs); 3259 $a_xml_writer->xmlStartTag("restrictions"); 3260 if ($this->getAnonymize() == 2) { 3261 $attribs = array("type" => "free"); 3262 } else { 3263 $attribs = array("type" => "restricted"); 3264 } 3265 $a_xml_writer->xmlElement("access", $attribs); 3266 if ($this->getStartDate()) { 3267 $attrs = array("type" => "date"); 3268 preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getStartDate(), $matches); 3269 $a_xml_writer->xmlElement("startingtime", $attrs, sprintf("%04d-%02d-%02dT%02d:%02d:00", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6])); 3270 } 3271 if ($this->getEndDate()) { 3272 $attrs = array("type" => "date"); 3273 preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->getEndDate(), $matches); 3274 $a_xml_writer->xmlElement("endingtime", $attrs, sprintf("%04d-%02d-%02dT%02d:%02d:00", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6])); 3275 } 3276 $a_xml_writer->xmlEndTag("restrictions"); 3277 3278 // constraints 3279 $pages = &$this->getSurveyPages(); 3280 $hasconstraints = false; 3281 foreach ($pages as $question_array) { 3282 foreach ($question_array as $question) { 3283 if (count($question["constraints"])) { 3284 $hasconstraints = true; 3285 } 3286 } 3287 } 3288 3289 if ($hasconstraints) { 3290 $a_xml_writer->xmlStartTag("constraints"); 3291 foreach ($pages as $question_array) { 3292 foreach ($question_array as $question) { 3293 if (count($question["constraints"])) { 3294 // found constraints 3295 foreach ($question["constraints"] as $constraint) { 3296 $attribs = array( 3297 "sourceref" => $question["question_id"], 3298 "destref" => $constraint["question"], 3299 "relation" => $constraint["short"], 3300 "value" => $constraint["value"], 3301 "conjunction" => $constraint["conjunction"] 3302 ); 3303 $a_xml_writer->xmlElement("constraint", $attribs); 3304 } 3305 } 3306 } 3307 } 3308 $a_xml_writer->xmlEndTag("constraints"); 3309 } 3310 3311 // add the rest of the preferences in qtimetadata tags, because there is no correspondent definition in QTI 3312 $a_xml_writer->xmlStartTag("metadata"); 3313 3314 $custom_properties = array(); 3315 $custom_properties["evaluation_access"] = $this->getEvaluationAccess(); 3316 $custom_properties["status"] = !$this->getOfflineStatus(); 3317 $custom_properties["display_question_titles"] = $this->getShowQuestionTitles(); 3318 $custom_properties["pool_usage"] = (int) $this->getPoolUsage(); 3319 3320 $custom_properties["own_results_view"] = (int) $this->hasViewOwnResults(); 3321 $custom_properties["own_results_mail"] = (int) $this->hasMailOwnResults(); 3322 $custom_properties["confirmation_mail"] = (int) $this->hasMailConfirmation(); 3323 3324 $custom_properties["anon_user_list"] = (int) $this->hasAnonymousUserList(); 3325 $custom_properties["mode"] = (int) $this->getMode(); 3326 $custom_properties["mode_360_self_eval"] = (int) $this->get360SelfEvaluation(); 3327 $custom_properties["mode_360_self_rate"] = (int) $this->get360SelfRaters(); 3328 $custom_properties["mode_360_self_appr"] = (int) $this->get360SelfAppraisee(); 3329 $custom_properties["mode_360_results"] = $this->get360Results(); 3330 $custom_properties["mode_skill_service"] = (int) $this->getSkillService(); 3331 $custom_properties["mode_self_eval_results"] = (int) $this->getSelfEvaluationResults(); 3332 3333 3334 // :TODO: skills? 3335 3336 // reminder/tutor notification are (currently?) not exportable 3337 3338 foreach ($custom_properties as $label => $value) { 3339 $a_xml_writer->xmlStartTag("metadatafield"); 3340 $a_xml_writer->xmlElement("fieldlabel", null, $label); 3341 $a_xml_writer->xmlElement("fieldentry", null, $value); 3342 $a_xml_writer->xmlEndTag("metadatafield"); 3343 } 3344 3345 $a_xml_writer->xmlStartTag("metadatafield"); 3346 $a_xml_writer->xmlElement("fieldlabel", null, "SCORM"); 3347 $md = new ilMD($this->getId(), 0, $this->getType()); 3348 $writer = new ilXmlWriter(); 3349 $md->toXml($writer); 3350 $metadata = $writer->xmlDumpMem(); 3351 $a_xml_writer->xmlElement("fieldentry", null, $metadata); 3352 $a_xml_writer->xmlEndTag("metadatafield"); 3353 3354 $a_xml_writer->xmlEndTag("metadata"); 3355 $a_xml_writer->xmlEndTag("survey"); 3356 3357 $attribs = array("id" => $this->getId()); 3358 $a_xml_writer->xmlStartTag("surveyquestions", $attribs); 3359 // add questionblock descriptions 3360 foreach ($pages as $question_array) { 3361 if (count($question_array) > 1) { 3362 $attribs = array("id" => $question_array[0]["question_id"]); 3363 $attribs = array("showQuestiontext" => $question_array[0]["questionblock_show_questiontext"], 3364 "showBlocktitle" => $question_array[0]["questionblock_show_blocktitle"]); 3365 $a_xml_writer->xmlStartTag("questionblock", $attribs); 3366 if (strlen($question_array[0]["questionblock_title"])) { 3367 $a_xml_writer->xmlElement("questionblocktitle", null, $question_array[0]["questionblock_title"]); 3368 } 3369 } 3370 foreach ($question_array as $question) { 3371 if (strlen($question["heading"])) { 3372 $a_xml_writer->xmlElement("textblock", null, $question["heading"]); 3373 } 3374 $questionObject = self::_instanciateQuestion($question["question_id"]); 3375 //questionObject contains all the fields from the database. (loadFromDb) 3376 //we don't need the value from svy_qst_oblig table, we already have the values from svy_question table. 3377 //if ($questionObject !== FALSE) $questionObject->insertXML($a_xml_writer, FALSE, $obligatory_states[$question["question_id"]]); 3378 if ($questionObject !== false) { 3379 $questionObject->insertXML($a_xml_writer, false); 3380 } 3381 } 3382 if (count($question_array) > 1) { 3383 $a_xml_writer->xmlEndTag("questionblock"); 3384 } 3385 } 3386 3387 $a_xml_writer->xmlEndTag("surveyquestions"); 3388 $a_xml_writer->xmlEndTag("surveyobject"); 3389 $xml = $a_xml_writer->xmlDumpMem(false); 3390 return $xml; 3391 } 3392 3393 /** 3394 * Creates an instance of a question with a given question id 3395 * 3396 * @param integer $question_id The question id 3397 * @return object The question instance 3398 * @access public 3399 */ 3400 public static function _instanciateQuestion($question_id) 3401 { 3402 if ($question_id < 1) { 3403 return false; 3404 } 3405 $question_type = SurveyQuestion::_getQuestionType($question_id); 3406 if (strlen($question_type) == 0) { 3407 return false; 3408 } 3409 SurveyQuestion::_includeClass($question_type); 3410 $question = new $question_type(); 3411 $question->loadFromDb($question_id); 3412 return $question; 3413 } 3414 3415 /** 3416 * Locates the import directory and the xml file in a directory with an unzipped import file 3417 * 3418 * @return array An associative array containing "dir" (import directory) and "xml" (xml file) 3419 * @access private 3420 */ 3421 public function locateImportFiles($a_dir) 3422 { 3423 if (!is_dir($a_dir) || is_int(strpos($a_dir, ".."))) { 3424 return; 3425 } 3426 $importDirectory = ""; 3427 $xmlFile = ""; 3428 3429 $current_dir = opendir($a_dir); 3430 $files = array(); 3431 while ($entryname = readdir($current_dir)) { 3432 $files[] = $entryname; 3433 } 3434 3435 foreach ($files as $file) { 3436 if (is_dir($a_dir . "/" . $file) and ($file != "." and $file != "..")) { 3437 // found directory created by zip 3438 $importDirectory = $a_dir . "/" . $file; 3439 } 3440 } 3441 closedir($current_dir); 3442 if (strlen($importDirectory)) { 3443 // find the xml file 3444 $current_dir = opendir($importDirectory); 3445 $files = array(); 3446 while ($entryname = readdir($current_dir)) { 3447 $files[] = $entryname; 3448 } 3449 foreach ($files as $file) { 3450 if (@is_file($importDirectory . "/" . $file) && 3451 ($file != "." && $file != "..") && 3452 (preg_match("/^[0-9]{10}__[0-9]+__(svy_)*[0-9]+\.[A-Za-z]{1,3}$/", $file) || 3453 preg_match("/^[0-9]{10}__[0-9]+__(survey__)*[0-9]+\.[A-Za-z]{1,3}$/", $file))) { 3454 // found xml file 3455 $xmlFile = $importDirectory . "/" . $file; 3456 } 3457 } 3458 } 3459 return array("dir" => $importDirectory, "xml" => $xmlFile); 3460 } 3461 3462 /** 3463 * Imports a survey from XML into the ILIAS database 3464 * @param $file_info 3465 * @param $svy_qpl_id 3466 * @return string 3467 * @throws ilFileUtilsException 3468 * @throws ilInvalidSurveyImportFileException 3469 */ 3470 public function importObject($file_info, $svy_qpl_id) 3471 { 3472 if ($svy_qpl_id < 1) { 3473 $svy_qpl_id = -1; 3474 } 3475 // check if file was uploaded 3476 $source = $file_info["tmp_name"]; 3477 $error = ""; 3478 if (($source == 'none') || (!$source) || $file_info["error"] > UPLOAD_ERR_OK) { 3479 $error = $this->lng->txt("import_no_file_selected"); 3480 } 3481 // check correct file type 3482 $isXml = false; 3483 $isZip = false; 3484 if ((strcmp($file_info["type"], "text/xml") == 0) || (strcmp($file_info["type"], "application/xml") == 0)) { 3485 $this->log->debug("isXML"); 3486 $isXml = true; 3487 } 3488 // too many different mime-types, so we use the suffix 3489 $suffix = pathinfo($file_info["name"]); 3490 if (strcmp(strtolower($suffix["extension"]), "zip") == 0) { 3491 $this->log->debug("isZip"); 3492 $isZip = true; 3493 } 3494 if (!$isXml && !$isZip) { 3495 $error = $this->lng->txt("import_wrong_file_type"); 3496 $this->log->debug("Survey: Import error. Filetype was \"" . $file_info["type"] . "\""); 3497 } 3498 if (strlen($error) == 0) { 3499 // import file as a survey 3500 $import_dir = $this->getImportDirectory(); 3501 $import_subdir = ""; 3502 $importfile = ""; 3503 if ($isZip) { 3504 $importfile = $import_dir . "/" . $file_info["name"]; 3505 ilUtil::moveUploadedFile($source, $file_info["name"], $importfile); 3506 ilUtil::unzip($importfile); 3507 $found = $this->locateImportFiles($import_dir); 3508 if (!((strlen($found["dir"]) > 0) && (strlen($found["xml"]) > 0))) { 3509 $error = $this->lng->txt("wrong_import_file_structure"); 3510 return $error; 3511 } 3512 $importfile = $found["xml"]; 3513 $import_subdir = $found["dir"]; 3514 } else { 3515 $importfile = tempnam($import_dir, "survey_import"); 3516 ilUtil::moveUploadedFile($source, $file_info["name"], $importfile); 3517 } 3518 3519 $this->log->debug("Import file = $importfile"); 3520 $this->log->debug("Import subdir = $import_subdir"); 3521 3522 $fh = fopen($importfile, "r"); 3523 if (!$fh) { 3524 $error = $this->lng->txt("import_error_opening_file"); 3525 return $error; 3526 } 3527 $xml = fread($fh, filesize($importfile)); 3528 $result = fclose($fh); 3529 if (!$result) { 3530 $error = $this->lng->txt("import_error_closing_file"); 3531 return $error; 3532 } 3533 3534 unset($_SESSION["import_mob_xhtml"]); 3535 if (strpos($xml, "questestinterop")) { 3536 throw new ilInvalidSurveyImportFileException("Unsupported survey version (< 3.8) found."); 3537 } else { 3538 $this->log->debug("survey id = " . $this->getId()); 3539 $this->log->debug("question pool id = " . $svy_qpl_id); 3540 3541 $imp = new ilImport(); 3542 $config = $imp->getConfig("Modules/Survey"); 3543 $config->setQuestionPoolID($svy_qpl_id); 3544 $imp->getMapping()->addMapping("Modules/Survey", "svy", 0, $this->getId()); 3545 $imp->importFromDirectory($import_subdir, "svy", "Modules/Survey"); 3546 $this->log->debug("config(Modules/survey)->getQuestionPoolId =" . $config->getQuestionPoolID()); 3547 return ""; 3548 3549 //old code 3550 $import = new SurveyImportParser($svy_qpl_id, "", true); 3551 $import->setSurveyObject($this); 3552 $import->setXMLContent($xml); 3553 $import->startParsing(); 3554 } 3555 3556 if (is_array($_SESSION["import_mob_xhtml"])) { 3557 foreach ($_SESSION["import_mob_xhtml"] as $mob) { 3558 $importfile = $import_subdir . "/" . $mob["uri"]; 3559 if (file_exists($importfile)) { 3560 if (!$mob["type"]) { 3561 $mob["type"] = "svy:html"; 3562 } 3563 3564 $media_object = ilObjMediaObject::_saveTempFileAsMediaObject(basename($importfile), $importfile, false); 3565 3566 // survey mob 3567 if ($mob["type"] == "svy:html") { 3568 ilObjMediaObject::_saveUsage($media_object->getId(), "svy:html", $this->getId()); 3569 $this->setIntroduction(str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $this->getIntroduction())); 3570 $this->setOutro(str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $this->getOutro())); 3571 } 3572 // question mob 3573 elseif ($import->questions[$mob["id"]]) { 3574 $new_qid = $import->questions[$mob["id"]]; 3575 ilObjMediaObject::_saveUsage($media_object->getId(), $mob["type"], $new_qid); 3576 $new_question = SurveyQuestion::_instanciateQuestion($new_qid); 3577 $qtext = $new_question->getQuestiontext(); 3578 $qtext = ilRTE::_replaceMediaObjectImageSrc($qtext, 0); 3579 $qtext = str_replace("src=\"" . $mob["mob"] . "\"", "src=\"" . "il_" . IL_INST_ID . "_mob_" . $media_object->getId() . "\"", $qtext); 3580 $qtext = ilRTE::_replaceMediaObjectImageSrc($qtext, 1); 3581 $new_question->setQuestiontext($qtext); 3582 $new_question->saveToDb(); 3583 3584 // also fix existing original in pool 3585 if ($new_question->getOriginalId()) { 3586 $pool_question = SurveyQuestion::_instanciateQuestion($new_question->getOriginalId()); 3587 $pool_question->setQuestiontext($qtext); 3588 $pool_question->saveToDb(); 3589 } 3590 } 3591 } else { 3592 $ilLog = $this->log; 3593 $ilLog->write("Error: Could not open XHTML mob file for test introduction during test import. File $importfile does not exist!"); 3594 } 3595 } 3596 $this->setIntroduction(ilRTE::_replaceMediaObjectImageSrc($this->getIntroduction(), 1)); 3597 $this->setOutro(ilRTE::_replaceMediaObjectImageSrc($this->getOutro(), 1)); 3598 $this->saveToDb(); 3599 } 3600 3601 // delete import directory 3602 ilUtil::delDir($this->getImportDirectory()); 3603 } 3604 return $error; 3605 } 3606 3607 /** 3608 * Clone object 3609 * 3610 * @access public 3611 * @param int ref_id of target container 3612 * @param int copy id 3613 * @return object new svy object 3614 */ 3615 public function cloneObject($a_target_id, $a_copy_id = 0, $a_omit_tree = false) 3616 { 3617 $ilDB = $this->db; 3618 3619 $this->loadFromDb(); 3620 3621 //survey mode 3622 $svy_type = $this->getMode(); 3623 3624 // Copy settings 3625 $newObj = parent::cloneObject($a_target_id, $a_copy_id, $a_omit_tree); 3626 $this->cloneMetaData($newObj); 3627 $newObj->updateMetaData(); 3628 3629 $newObj->setAuthor($this->getAuthor()); 3630 $newObj->setIntroduction($this->getIntroduction()); 3631 $newObj->setOutro($this->getOutro()); 3632 $newObj->setEvaluationAccess($this->getEvaluationAccess()); 3633 $newObj->setStartDate($this->getStartDate()); 3634 $newObj->setEndDate($this->getEndDate()); 3635 $newObj->setAnonymize($this->getAnonymize()); 3636 $newObj->setShowQuestionTitles($this->getShowQuestionTitles()); 3637 $newObj->setTemplate($this->getTemplate()); 3638 $newObj->setPoolUsage($this->getPoolUsage()); 3639 $newObj->setViewOwnResults($this->hasViewOwnResults()); 3640 $newObj->setMailOwnResults($this->hasMailOwnResults()); 3641 $newObj->setMailConfirmation($this->hasMailConfirmation()); 3642 $newObj->setAnonymousUserList($this->hasAnonymousUserList()); 3643 3644 // #12661 3645 if ($this->get360Mode()) { 3646 $newObj->setMode(ilObjSurvey::MODE_360); 3647 $newObj->set360SelfEvaluation($this->get360SelfEvaluation()); 3648 $newObj->set360SelfAppraisee($this->get360SelfAppraisee()); 3649 $newObj->set360SelfRaters($this->get360SelfRaters()); 3650 $newObj->set360Results($this->get360Results()); 3651 $newObj->setSkillService($this->getSkillService()); 3652 } 3653 //svy mode self eval: skills + view results 3654 if ($svy_type == ilObjSurvey::MODE_SELF_EVAL) { 3655 $newObj->setMode(ilObjSurvey::MODE_SELF_EVAL); 3656 $newObj->setSkillService($this->getSkillService()); 3657 $newObj->setSelfEvaluationResults($this->getSelfEvaluationResults()); 3658 } 3659 3660 // reminder/notification 3661 $newObj->setReminderStatus($this->getReminderStatus()); 3662 $newObj->setReminderStart($this->getReminderStart()); 3663 $newObj->setReminderEnd($this->getReminderEnd()); 3664 $newObj->setReminderFrequency($this->getReminderFrequency()); 3665 $newObj->setReminderTarget($this->getReminderTarget()); 3666 $newObj->setReminderTemplate($this->getReminderTemplate()); 3667 // reminder_last_sent must not be copied! 3668 $newObj->setTutorNotificationStatus($this->getTutorNotificationStatus()); 3669 $newObj->setTutorNotificationRecipients($this->getTutorNotificationRecipients()); 3670 $newObj->setTutorNotificationTarget($this->getTutorNotificationTarget()); 3671 $newObj->setTutorResultsStatus($this->getTutorResultsStatus()); 3672 $newObj->setTutorResultsRecipients($this->getTutorResultsRecipients()); 3673 3674 $newObj->setMailNotification($this->getMailNotification()); 3675 $newObj->setMailAddresses($this->getMailAddresses()); 3676 $newObj->setMailParticipantData($this->getMailParticipantData()); 3677 3678 $question_pointer = array(); 3679 // clone the questions 3680 $mapping = array(); 3681 3682 foreach ($this->questions as $key => $question_id) { 3683 /** @var $question SurveyQuestion */ 3684 $question = self::_instanciateQuestion($question_id); 3685 if ($question) { // #10824 3686 $question->id = -1; 3687 $original_id = SurveyQuestion::_getOriginalId($question_id, false); 3688 $question->setObjId($newObj->getId()); 3689 $question->saveToDb($original_id); 3690 $newObj->questions[$key] = $question->getId(); 3691 $question_pointer[$question_id] = $question->getId(); 3692 $mapping[$question_id] = $question->getId(); 3693 } 3694 } 3695 3696 //copy online status if object is not the root copy object 3697 $cp_options = ilCopyWizardOptions::_getInstance($a_copy_id); 3698 3699 if (!$cp_options->isRootNode($this->getRefId())) { 3700 $newObj->setOfflineStatus($this->getOfflineStatus()); 3701 } 3702 3703 $newObj->saveToDb(); 3704 $newObj->cloneTextblocks($mapping); 3705 3706 // #14929 3707 if (($svy_type == ilObjSurvey::MODE_360 || $svy_type == ilObjSurvey::MODE_SELF_EVAL) && 3708 $this->getSkillService()) { 3709 $src_skills = new ilSurveySkill($this); 3710 $tgt_skills = new ilSurveySkill($newObj); 3711 3712 foreach ($mapping as $src_qst_id => $tgt_qst_id) { 3713 $qst_skill = $src_skills->getSkillForQuestion($src_qst_id); 3714 if ($qst_skill) { 3715 $tgt_skills->addQuestionSkillAssignment($tgt_qst_id, $qst_skill["base_skill_id"], $qst_skill["tref_id"]); 3716 } 3717 } 3718 } 3719 3720 // clone the questionblocks 3721 $questionblocks = array(); 3722 $questionblock_questions = array(); 3723 $result = $ilDB->queryF( 3724 "SELECT * FROM svy_qblk_qst WHERE survey_fi = %s", 3725 array('integer'), 3726 array($this->getSurveyId()) 3727 ); 3728 if ($result->numRows() > 0) { 3729 while ($row = $ilDB->fetchAssoc($result)) { 3730 array_push($questionblock_questions, $row); 3731 $questionblocks[$row["questionblock_fi"]] = $row["questionblock_fi"]; 3732 } 3733 } 3734 // create new questionblocks 3735 foreach ($questionblocks as $key => $value) { 3736 $questionblock = self::_getQuestionblock($key); 3737 $questionblock_id = self::_addQuestionblock($questionblock["title"], $questionblock["owner_fi"], $questionblock["show_questiontext"], $questionblock["show_blocktitle"]); 3738 $questionblocks[$key] = $questionblock_id; 3739 } 3740 // create new questionblock questions 3741 foreach ($questionblock_questions as $key => $value) { 3742 if ($questionblocks[$value["questionblock_fi"]] && 3743 $question_pointer[$value["question_fi"]]) { 3744 $next_id = $ilDB->nextId('svy_qblk_qst'); 3745 $affectedRows = $ilDB->manipulateF( 3746 "INSERT INTO svy_qblk_qst (qblk_qst_id, survey_fi, questionblock_fi, question_fi) " . 3747 "VALUES (%s, %s, %s, %s)", 3748 array('integer','integer','integer','integer'), 3749 array($next_id, $newObj->getSurveyId(), $questionblocks[$value["questionblock_fi"]], $question_pointer[$value["question_fi"]]) 3750 ); 3751 } 3752 } 3753 3754 // clone the constraints 3755 $constraints = self::_getConstraints($this->getSurveyId()); 3756 $newConstraints = array(); 3757 foreach ($constraints as $key => $constraint) { 3758 if ($question_pointer[$constraint["for_question"]] && 3759 $question_pointer[$constraint["question"]]) { 3760 if (!array_key_exists($constraint['id'], $newConstraints)) { 3761 $constraint_id = $newObj->addConstraint($question_pointer[$constraint["question"]], $constraint["relation_id"], $constraint["value"], $constraint['conjunction']); 3762 $newConstraints[$constraint['id']] = $constraint_id; 3763 } 3764 $newObj->addConstraintToQuestion($question_pointer[$constraint["for_question"]], $newConstraints[$constraint['id']]); 3765 } 3766 } 3767 3768 // #16210 - clone LP settings 3769 $obj_settings = new ilLPObjSettings($this->getId()); 3770 $obj_settings->cloneSettings($newObj->getId()); 3771 unset($obj_settings); 3772 3773 return $newObj; 3774 } 3775 3776 public function getTextblock($question_id) 3777 { 3778 $ilDB = $this->db; 3779 $result = $ilDB->queryF( 3780 "SELECT * FROM svy_svy_qst WHERE question_fi = %s", 3781 array('integer'), 3782 array($question_id) 3783 ); 3784 if ($result->numRows()) { 3785 $row = $ilDB->fetchAssoc($result); 3786 return $row["heading"]; 3787 } else { 3788 return ""; 3789 } 3790 } 3791 3792 /** 3793 * Clones the textblocks of survey questions 3794 * 3795 * @access public 3796 */ 3797 public function cloneTextblocks($mapping) 3798 { 3799 foreach ($mapping as $original_id => $new_id) { 3800 $textblock = $this->getTextblock($original_id); 3801 $this->saveHeading(ilUtil::stripSlashes($textblock, true, ilObjAdvancedEditing::_getUsedHTMLTagsAsString("survey")), $new_id); 3802 } 3803 } 3804 3805 /** 3806 * creates data directory for export files 3807 * (data_dir/svy_data/svy_<id>/export, depending on data 3808 * directory that is set in ILIAS setup/ini) 3809 * 3810 * @throws ilSurveyException 3811 */ 3812 public function createExportDirectory() 3813 { 3814 $svy_data_dir = ilUtil::getDataDir() . "/svy_data"; 3815 ilUtil::makeDir($svy_data_dir); 3816 if (!is_writable($svy_data_dir)) { 3817 throw new ilSurveyException("Survey Data Directory (" . $svy_data_dir . ") not writeable."); 3818 } 3819 3820 // create learning module directory (data_dir/lm_data/lm_<id>) 3821 $svy_dir = $svy_data_dir . "/svy_" . $this->getId(); 3822 ilUtil::makeDir($svy_dir); 3823 if (!@is_dir($svy_dir)) { 3824 throw new ilSurveyException("Creation of Survey Directory failed."); 3825 } 3826 // create Export subdirectory (data_dir/lm_data/lm_<id>/Export) 3827 $export_dir = $svy_dir . "/export"; 3828 ilUtil::makeDir($export_dir); 3829 if (!@is_dir($export_dir)) { 3830 throw new ilSurveyException("Creation of Export Directory failed."); 3831 } 3832 } 3833 3834 /** 3835 * get export directory of survey 3836 */ 3837 public function getExportDirectory() 3838 { 3839 $export_dir = ilUtil::getDataDir() . "/svy_data" . "/svy_" . $this->getId() . "/export"; 3840 3841 return $export_dir; 3842 } 3843 3844 /** 3845 * creates data directory for import files 3846 * (data_dir/svy_data/svy_<id>/import, depending on data 3847 * directory that is set in ILIAS setup/ini) 3848 * 3849 * @throws ilSurveyException 3850 */ 3851 public function createImportDirectory() 3852 { 3853 $svy_data_dir = ilUtil::getDataDir() . "/svy_data"; 3854 ilUtil::makeDir($svy_data_dir); 3855 3856 if (!is_writable($svy_data_dir)) { 3857 throw new ilSurveyException("Survey Data Directory (" . $svy_data_dir . ") not writeable."); 3858 } 3859 3860 // create test directory (data_dir/svy_data/svy_<id>) 3861 $svy_dir = $svy_data_dir . "/svy_" . $this->getId(); 3862 ilUtil::makeDir($svy_dir); 3863 if (!@is_dir($svy_dir)) { 3864 throw new ilSurveyException("Creation of Survey Directory failed."); 3865 } 3866 3867 // create import subdirectory (data_dir/svy_data/svy_<id>/import) 3868 $import_dir = $svy_dir . "/import"; 3869 ilUtil::makeDir($import_dir); 3870 if (!@is_dir($import_dir)) { 3871 throw new ilSurveyException("Creation of Import Directory failed."); 3872 } 3873 } 3874 3875 /** 3876 * get import directory of survey 3877 */ 3878 public function getImportDirectory() 3879 { 3880 $import_dir = ilUtil::getDataDir() . "/svy_data" . 3881 "/svy_" . $this->getId() . "/import"; 3882 if (!is_dir($import_dir)) { 3883 ilUtil::makeDirParents($import_dir); 3884 } 3885 if (@is_dir($import_dir)) { 3886 return $import_dir; 3887 } else { 3888 return false; 3889 } 3890 } 3891 3892 public function saveHeading($heading = "", $insertbefore) 3893 { 3894 $ilDB = $this->db; 3895 if ($heading) { 3896 $affectedRows = $ilDB->manipulateF( 3897 "UPDATE svy_svy_qst SET heading=%s WHERE survey_fi=%s AND question_fi=%s", 3898 array('text','integer','integer'), 3899 array($heading, $this->getSurveyId(), $insertbefore) 3900 ); 3901 } else { 3902 $affectedRows = $ilDB->manipulateF( 3903 "UPDATE svy_svy_qst SET heading=%s WHERE survey_fi=%s AND question_fi=%s", 3904 array('text','integer','integer'), 3905 array(null, $this->getSurveyId(), $insertbefore) 3906 ); 3907 } 3908 } 3909 3910 public function isAnonymousKey($key) 3911 { 3912 $ilDB = $this->db; 3913 3914 $result = $ilDB->queryF( 3915 "SELECT anonymous_id FROM svy_anonymous WHERE survey_key = %s AND survey_fi = %s", 3916 array('text','integer'), 3917 array($key, $this->getSurveyId()) 3918 ); 3919 return ($result->numRows() == 1) ? true : false; 3920 } 3921 3922 public function bindSurveyCodeToUser($user_id, $code) 3923 { 3924 $ilDB = $this->db; 3925 3926 if ($user_id == ANONYMOUS_USER_ID) { 3927 return; 3928 } 3929 3930 if ($this->checkSurveyCode($code)) { 3931 $ilDB->manipulate("UPDATE svy_anonymous" . 3932 " SET user_key = " . $ilDB->quote(md5($user_id), "text") . 3933 " WHERE survey_key = " . $ilDB->quote($code, "text")); 3934 } 3935 } 3936 3937 public function isAnonymizedParticipant($key) 3938 { 3939 $ilDB = $this->db; 3940 3941 $result = $ilDB->queryF( 3942 "SELECT finished_id FROM svy_finished WHERE anonymous_id = %s AND survey_fi = %s", 3943 array('text','integer'), 3944 array($key, $this->getSurveyId()) 3945 ); 3946 return ($result->numRows() == 1) ? true : false; 3947 } 3948 3949 public function checkSurveyCode($code) 3950 { 3951 if ($this->isAnonymousKey($code)) { 3952 if ($this->isSurveyStarted("", $code) == 1) { 3953 return false; 3954 } else { 3955 return true; 3956 } 3957 } else { 3958 return false; 3959 } 3960 } 3961 3962 /** 3963 * Returns a list of survey codes for file export 3964 * 3965 * @param array $a_array An array of all survey codes that should be exported 3966 * @return string A comma separated list of survey codes an URLs for file export 3967 * @access public 3968 */ 3969 public function getSurveyCodesForExport(array $a_codes = null, array $a_ids = null) 3970 { 3971 $ilDB = $this->db; 3972 $ilUser = $this->user; 3973 $lng = $this->lng; 3974 3975 $sql = "SELECT svy_anonymous.*, svy_finished.state" . 3976 " FROM svy_anonymous" . 3977 " LEFT JOIN svy_finished ON (svy_anonymous.survey_key = svy_finished.anonymous_id)" . 3978 " WHERE svy_anonymous.survey_fi = " . $ilDB->quote($this->getSurveyId(), "integer") . 3979 " AND svy_anonymous.user_key IS NULL"; 3980 3981 if ($a_codes) { 3982 $sql .= " AND " . $ilDB->in("svy_anonymous.survey_key", $a_codes, "", "text"); 3983 } elseif ($a_ids) { 3984 $sql .= " AND " . $ilDB->in("svy_anonymous.anonymous_id", $a_ids, "", "text"); 3985 } 3986 3987 $export = array(); 3988 3989 // #14905 3990 $titles = array(); 3991 $titles[] = '"' . $lng->txt("survey_code") . '"'; 3992 $titles[] = '"' . $lng->txt("email") . '"'; 3993 $titles[] = '"' . $lng->txt("lastname") . '"'; 3994 $titles[] = '"' . $lng->txt("firstname") . '"'; 3995 $titles[] = '"' . $lng->txt("create_date") . '"'; 3996 $titles[] = '"' . $lng->txt("used") . '"'; 3997 $titles[] = '"' . $lng->txt("mail_sent_short") . '"'; 3998 $titles[] = '"' . $lng->txt("survey_code_url") . '"'; 3999 $export[] = implode(";", $titles); 4000 4001 $result = $ilDB->query($sql); 4002 $default_lang = $ilUser->getPref("survey_code_language"); 4003 while ($row = $ilDB->fetchAssoc($result)) { 4004 $item = array(); 4005 $item[] = $row["survey_key"]; 4006 4007 if ($row["externaldata"]) { 4008 $ext = unserialize($row["externaldata"]); 4009 $item[] = $ext["email"]; 4010 $item[] = $ext["lastname"]; 4011 $item[] = $ext["firstname"]; 4012 } else { 4013 $item[] = ""; 4014 $item[] = ""; 4015 $item[] = ""; 4016 } 4017 4018 // No relative (today, tomorrow...) dates in export. 4019 $date = new ilDateTime($row['tstamp'], IL_CAL_UNIX); 4020 $item[] = $date->get(IL_CAL_DATETIME); 4021 4022 $item[] = ($this->isSurveyCodeUsed($row["survey_key"])) ? 1 : 0; 4023 $item[] = ($row["sent"]) ? 1 : 0; 4024 4025 $params = array("accesscode" => $row["survey_key"]); 4026 if ($default_lang) { 4027 $params["lang"] = $default_lang; 4028 } 4029 $item[] = ilLink::_getLink($this->getRefId(), "svy", $params); 4030 4031 $export[] = '"' . implode('";"', $item) . '"'; 4032 } 4033 return implode("\n", $export); 4034 } 4035 4036 /** 4037 * Fetches the data for the survey codes table 4038 * 4039 * @param string $lang Language for the survey code URL 4040 * @return array The requested data 4041 * @access public 4042 */ 4043 public function getSurveyCodesTableData(array $ids = null, $lang = null) 4044 { 4045 $ilDB = $this->db; 4046 4047 $codes = array(); 4048 4049 $sql = "SELECT svy_anonymous.*, svy_finished.state" . 4050 " FROM svy_anonymous" . 4051 " LEFT JOIN svy_finished ON (svy_anonymous.survey_key = svy_finished.anonymous_id)" . 4052 " WHERE svy_anonymous.survey_fi = " . $ilDB->quote($this->getSurveyId(), "integer") /*. 4053 " AND svy_anonymous.user_key IS NULL" */; // #15860 4054 4055 if ($ids) { 4056 $sql .= " AND " . $ilDB->in("svy_anonymous.anonymous_id", $ids, "", "integer"); 4057 } 4058 4059 $sql .= " ORDER BY tstamp, survey_key ASC"; 4060 $result = $ilDB->query($sql); 4061 if ($result->numRows() > 0) { 4062 while ($row = $ilDB->fetchAssoc($result)) { 4063 $href = ""; 4064 $used = false; 4065 if ($this->isSurveyCodeUsed($row["survey_key"])) { 4066 $used = true; 4067 } else { 4068 $params = array("accesscode" => $row["survey_key"]); 4069 if ($lang) { 4070 $params["lang"] = $lang; 4071 } 4072 $href = ilLink::_getLink($this->getRefId(), "svy", $params); 4073 } 4074 4075 4076 $item = array( 4077 'id' => $row["anonymous_id"], 4078 'code' => $row["survey_key"], 4079 'date' => $row["tstamp"], 4080 'used' => $used, 4081 'sent' => $row['sent'], 4082 'href' => $href, 4083 'email' => '', 4084 'last_name' => '', 4085 'first_name' => '' 4086 ); 4087 4088 if ($row["externaldata"]) { 4089 $ext = unserialize($row["externaldata"]); 4090 $item['email'] = $ext['email']; 4091 $item['last_name'] = $ext['lastname']; 4092 $item['first_name'] = $ext['firstname']; 4093 } 4094 4095 array_push($codes, $item); 4096 } 4097 } 4098 return $codes; 4099 } 4100 4101 public function isSurveyCodeUsed($code) 4102 { 4103 $ilDB = $this->db; 4104 $result = $ilDB->queryF( 4105 "SELECT finished_id FROM svy_finished WHERE survey_fi = %s AND anonymous_id = %s", 4106 array('integer','text'), 4107 array($this->getSurveyId(), $code) 4108 ); 4109 return ($result->numRows() > 0) ? true : false; 4110 } 4111 4112 public function isSurveyCodeUnique($code) 4113 { 4114 $ilDB = $this->db; 4115 $result = $ilDB->queryF( 4116 "SELECT anonymous_id FROM svy_anonymous WHERE survey_fi = %s AND survey_key = %s", 4117 array('integer','text'), 4118 array($this->getSurveyId(), $code) 4119 ); 4120 return ($result->numRows() > 0) ? false : true; 4121 } 4122 4123 public function createSurveyCodes($nrOfCodes) 4124 { 4125 $ilDB = $this->db; 4126 4127 $res = array(); 4128 4129 for ($i = 0; $i < $nrOfCodes; $i++) { 4130 $next_id = $ilDB->nextId('svy_anonymous'); 4131 $ilDB->manipulateF( 4132 "INSERT INTO svy_anonymous (anonymous_id, survey_key, survey_fi, tstamp) " . 4133 "VALUES (%s, %s, %s, %s)", 4134 array('integer','text','integer','integer'), 4135 array($next_id, $this->createNewAccessCode(), $this->getSurveyId(), time()) 4136 ); 4137 $res[] = $next_id; 4138 } 4139 4140 return $res; 4141 } 4142 4143 public function importSurveyCode($a_anonymize_key, $a_created, $a_data) 4144 { 4145 $ilDB = $this->db; 4146 4147 $next_id = $ilDB->nextId('svy_anonymous'); 4148 $ilDB->manipulateF( 4149 "INSERT INTO svy_anonymous (anonymous_id, survey_key, survey_fi, externaldata, tstamp) " . 4150 "VALUES (%s, %s, %s, %s, %s)", 4151 array('integer','text','integer','text','integer'), 4152 array($next_id, $a_anonymize_key, $this->getSurveyId(), serialize($a_data), $a_created) 4153 ); 4154 } 4155 4156 public function createSurveyCodesForExternalData($data) 4157 { 4158 $ilDB = $this->db; 4159 4160 $ids = array(); 4161 foreach ($data as $dataset) { 4162 $anonymize_key = $this->createNewAccessCode(); 4163 $next_id = $ilDB->nextId('svy_anonymous'); 4164 $affectedRows = $ilDB->manipulateF( 4165 "INSERT INTO svy_anonymous (anonymous_id, survey_key, survey_fi, externaldata, tstamp) " . 4166 "VALUES (%s, %s, %s, %s, %s)", 4167 array('integer','text','integer','text','integer'), 4168 array($next_id, $anonymize_key, $this->getSurveyId(), serialize($dataset), time()) 4169 ); 4170 $ids[] = $next_id; 4171 } 4172 return $ids; 4173 } 4174 4175 public function sendCodes($not_sent, $subject, $message, $lang) 4176 { 4177 global $DIC; 4178 /* 4179 * 0 = all 4180 * 1 = not sent 4181 * 2 = finished 4182 * 3 = not finished 4183 */ 4184 $check_finished = ($not_sent > 1); 4185 4186 4187 $mail = new ilMail(ANONYMOUS_USER_ID); 4188 $recipients = $this->getExternalCodeRecipients($check_finished); 4189 foreach ($recipients as $data) { 4190 if ($data['email'] && $data['code']) { 4191 $do_send = false; 4192 switch ((int) $not_sent) { 4193 case 1: 4194 $do_send = !(bool) $data['sent']; 4195 break; 4196 4197 case 2: 4198 $do_send = $data['finished']; 4199 break; 4200 4201 case 3: 4202 $do_send = !$data['finished']; 4203 break; 4204 4205 default: 4206 $do_send = true; 4207 break; 4208 } 4209 if ($do_send) { 4210 // build text 4211 $messagetext = $message; 4212 $url = ilLink::_getLink( 4213 $this->getRefId(), 4214 "svy", 4215 array( 4216 "accesscode" => $data["code"], 4217 "lang" => $lang 4218 ) 4219 ); 4220 $messagetext = str_replace('[url]', $url, $messagetext); 4221 foreach ($data as $key => $value) { 4222 $messagetext = str_replace('[' . $key . ']', $value, $messagetext); 4223 } 4224 4225 // send mail 4226 $mail->enqueue( 4227 $data['email'], // to 4228 "", // cc 4229 "", // bcc 4230 $subject, // subject 4231 $messagetext, // message 4232 array() // attachments 4233 ); 4234 } 4235 } 4236 } 4237 4238 $ilDB = $this->db; 4239 $ilDB->manipulateF( 4240 "UPDATE svy_anonymous SET sent = %s WHERE survey_fi = %s AND externaldata IS NOT NULL", 4241 array('integer','integer'), 4242 array(1, $this->getSurveyId()) 4243 ); 4244 } 4245 4246 public function getExternalCodeRecipients($a_check_finished = false) 4247 { 4248 $ilDB = $this->db; 4249 $result = $ilDB->queryF( 4250 "SELECT survey_key code, externaldata, sent FROM svy_anonymous WHERE survey_fi = %s", 4251 array('integer'), 4252 array($this->getSurveyId()) 4253 ); 4254 $res = array(); 4255 while ($row = $ilDB->fetchAssoc($result)) { 4256 if (!$row['externaldata']) { 4257 continue; 4258 } 4259 4260 $externaldata = unserialize($row['externaldata']); 4261 if (!$externaldata['email']) { 4262 continue; 4263 } 4264 4265 $externaldata['code'] = $row['code']; 4266 $externaldata['sent'] = $row['sent']; 4267 4268 if ($a_check_finished) { 4269 #23294 4270 //$externaldata['finished'] = $this->isSurveyCodeUsed($row['code']); 4271 $externaldata['finished'] = $this->isSurveyFinishedByCode($row['code']); 4272 } 4273 4274 array_push($res, $externaldata); 4275 } 4276 return $res; 4277 } 4278 4279 /** 4280 * Get if survey is finished for an specific anonymous user code. 4281 * @param $a_code anonymous user code 4282 * @return bool 4283 */ 4284 public function isSurveyFinishedByCode($a_code) 4285 { 4286 $result = $this->db->queryF( 4287 "SELECT state FROM svy_finished WHERE survey_fi = %s AND anonymous_id = %s", 4288 array('integer','text'), 4289 array($this->getSurveyId(), $a_code) 4290 ); 4291 4292 $row = $this->db->fetchAssoc($result); 4293 4294 return $row['state']; 4295 } 4296 4297 /** 4298 * Deletes a given survey access code 4299 * 4300 * @param string $survey_code The survey code that should be deleted 4301 */ 4302 public function deleteSurveyCode($survey_code) 4303 { 4304 $ilDB = $this->db; 4305 4306 if (strlen($survey_code) > 0) { 4307 $affectedRows = $ilDB->manipulateF( 4308 "DELETE FROM svy_anonymous WHERE survey_fi = %s AND survey_key = %s", 4309 array('integer', 'text'), 4310 array($this->getSurveyId(), $survey_code) 4311 ); 4312 } 4313 } 4314 4315 /** 4316 * Returns a survey access code that was saved for a registered user 4317 * 4318 * @param int $user_id The database id of the user 4319 * @return string The survey access code of the user 4320 */ 4321 public function getUserAccessCode($user_id) 4322 { 4323 $ilDB = $this->db; 4324 $access_code = ""; 4325 $result = $ilDB->queryF( 4326 "SELECT survey_key FROM svy_anonymous WHERE survey_fi = %s AND user_key = %s", 4327 array('integer','text'), 4328 array($this->getSurveyId(), md5($user_id)) 4329 ); 4330 if ($result->numRows()) { 4331 $row = $ilDB->fetchAssoc($result); 4332 $access_code = $row["survey_key"]; 4333 } 4334 return $access_code; 4335 } 4336 4337 /** 4338 * Saves a survey access code for a registered user to the database 4339 * 4340 * @param int $user_id The database id of the user 4341 * @param string $access_code The survey access code 4342 */ 4343 public function saveUserAccessCode($user_id, $access_code) 4344 { 4345 $ilDB = $this->db; 4346 4347 // not really sure what to do about ANONYMOUS_USER_ID 4348 4349 $next_id = $ilDB->nextId('svy_anonymous'); 4350 $affectedRows = $ilDB->manipulateF( 4351 "INSERT INTO svy_anonymous (anonymous_id, survey_key, survey_fi, user_key, tstamp) " . 4352 "VALUES (%s, %s, %s, %s, %s)", 4353 array('integer','text', 'integer', 'text', 'integer'), 4354 array($next_id, $access_code, $this->getSurveyId(), md5($user_id), time()) 4355 ); 4356 } 4357 4358 /** 4359 * Returns a new, unused survey access code 4360 * 4361 * @return string A new survey access code 4362 */ 4363 public function createNewAccessCode() 4364 { 4365 // create a 5 character code 4366 $codestring = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; 4367 mt_srand(); 4368 $code = ""; 4369 for ($i = 1; $i <= 5; $i++) { 4370 $index = mt_rand(0, strlen($codestring) - 1); 4371 $code .= substr($codestring, $index, 1); 4372 } 4373 // verify it against the database 4374 while (!$this->isSurveyCodeUnique($code)) { 4375 $code = $this->createNewAccessCode(); 4376 } 4377 return $code; 4378 } 4379 4380 public function getLastAccess($finished_id) 4381 { 4382 $ilDB = $this->db; 4383 4384 $result = $ilDB->queryF( 4385 "SELECT tstamp FROM svy_answer WHERE active_fi = %s ORDER BY tstamp DESC", 4386 array('integer'), 4387 array($finished_id) 4388 ); 4389 if ($result->numRows()) { 4390 $row = $ilDB->fetchAssoc($result); 4391 return $row["tstamp"]; 4392 } else { 4393 $result = $ilDB->queryF( 4394 "SELECT tstamp FROM svy_finished WHERE finished_id = %s", 4395 array('integer'), 4396 array($finished_id) 4397 ); 4398 if ($result->numRows()) { 4399 $row = $ilDB->fetchAssoc($result); 4400 return $row["tstamp"]; 4401 } 4402 } 4403 return ""; 4404 } 4405 4406 /** 4407 * Prepares a string for a text area output in surveys 4408 * 4409 * @param string $txt_output String which should be prepared for output 4410 * @access public 4411 */ 4412 public function prepareTextareaOutput($txt_output) 4413 { 4414 return ilUtil::prepareTextareaOutput($txt_output, $prepare_for_latex_output); 4415 } 4416 4417 /** 4418 * Checks if a given string contains HTML or not 4419 * 4420 * @param string $a_text Text which should be checked 4421 * @return boolean 4422 * @access public 4423 */ 4424 public function isHTML($a_text) 4425 { 4426 if (preg_match("/<[^>]*?>/", $a_text)) { 4427 return true; 4428 } else { 4429 return false; 4430 } 4431 } 4432 4433 /** 4434 * Creates an XML material tag from a plain text or xhtml text 4435 * 4436 * @param object $a_xml_writer Reference to the ILIAS XML writer 4437 * @param string $a_material plain text or html text containing the material 4438 * @return string XML material tag 4439 * @access public 4440 */ 4441 public function addMaterialTag(&$a_xml_writer, $a_material, $close_material_tag = true, $add_mobs = true, $attribs = null) 4442 { 4443 $a_xml_writer->xmlStartTag("material", $attribs); 4444 $attrs = array( 4445 "type" => "text/plain" 4446 ); 4447 if ($this->isHTML($a_material)) { 4448 $attrs["type"] = "text/xhtml"; 4449 } 4450 $mattext = ilRTE::_replaceMediaObjectImageSrc($a_material, 0); 4451 $a_xml_writer->xmlElement("mattext", $attrs, $mattext); 4452 4453 if ($add_mobs) { 4454 $mobs = ilObjMediaObject::_getMobsOfObject("svy:html", $this->getId()); 4455 foreach ($mobs as $mob) { 4456 $mob_id = "il_" . IL_INST_ID . "_mob_" . $mob; 4457 if (strpos($mattext, $mob_id) !== false) { 4458 $mob_obj = new ilObjMediaObject($mob); 4459 $imgattrs = array( 4460 "label" => $mob_id, 4461 "uri" => "objects/" . "il_" . IL_INST_ID . "_mob_" . $mob . "/" . $mob_obj->getTitle(), 4462 "type" => "svy:html", 4463 "id" => $this->getId() 4464 ); 4465 $a_xml_writer->xmlElement("matimage", $imgattrs, null); 4466 } 4467 } 4468 } 4469 if ($close_material_tag) { 4470 $a_xml_writer->xmlEndTag("material"); 4471 } 4472 } 4473 4474 /** 4475 * Checks if the survey code can be exported with the survey evaluation. In some cases this may be 4476 * necessary but usually you should prevent it because people who sent the survey codes could connect 4477 * real people with the survey code in the evaluation and undermine the anonymity 4478 * 4479 * @return boolean TRUE if the survey is anonymized and the survey code may be shown in the export file 4480 * @author Helmut Schottmüller 4481 **/ 4482 public function canExportSurveyCode() 4483 { 4484 if ($this->getAnonymize() != self::ANONYMIZE_OFF) { 4485 if ($this->surveyCodeSecurity == false) { 4486 return true; 4487 } 4488 } 4489 return false; 4490 } 4491 4492 /** 4493 * Convert a print output to XSL-FO 4494 * 4495 * @param string $print_output The print output 4496 * @return string XSL-FO code 4497 * @access public 4498 */ 4499 public function processPrintoutput2FO($print_output) 4500 { 4501 if (extension_loaded("tidy")) { 4502 $config = array( 4503 "indent" => false, 4504 "output-xml" => true, 4505 "numeric-entities" => true 4506 ); 4507 $tidy = new tidy(); 4508 $tidy->parseString($print_output, $config, 'utf8'); 4509 $tidy->cleanRepair(); 4510 $print_output = tidy_get_output($tidy); 4511 $print_output = preg_replace("/^.*?(<html)/", "\\1", $print_output); 4512 } else { 4513 $print_output = str_replace(" ", " ", $print_output); 4514 $print_output = str_replace("⊗", "X", $print_output); 4515 4516 // #17680 - metric questions use   in print view 4517 $print_output = str_replace(">", "~|gt|~", $print_output); // see #21550 4518 $print_output = str_replace("<", "~|lt|~", $print_output); 4519 $print_output = str_replace(" ", "~|nbsp|~", $print_output); 4520 $print_output = preg_replace('/&(?!amp)/', '&', $print_output); 4521 $print_output = str_replace("~|nbsp|~", " ", $print_output); 4522 $print_output = str_replace("~|gt|~", ">", $print_output); 4523 $print_output = str_replace("~|lt|~", "<", $print_output); 4524 } 4525 $xsl = file_get_contents("./Modules/Survey/xml/question2fo.xsl"); 4526 4527 // additional font support 4528 $xsl = str_replace( 4529 'font-family="Helvetica, unifont"', 4530 'font-family="' . $GLOBALS['ilSetting']->get('rpc_pdf_font', 'Helvetica, unifont') . '"', 4531 $xsl 4532 ); 4533 $args = array( '/_xml' => $print_output, '/_xsl' => $xsl ); 4534 $xh = xslt_create(); 4535 $params = array(); 4536 try { 4537 $output = xslt_process($xh, "arg:/_xml", "arg:/_xsl", null, $args, $params); 4538 } catch (Exception $e) { 4539 $this->log->error("Print XSLT failed:"); 4540 $this->log->error("Content: " . $print_output); 4541 $this->log->error("Xsl: " . $xsl); 4542 throw ($e); 4543 } 4544 xslt_error($xh); 4545 xslt_free($xh); 4546 4547 return $output; 4548 } 4549 4550 /** 4551 * Delivers a PDF file from a XSL-FO string 4552 * 4553 * @param string $fo The XSL-FO string 4554 * @access public 4555 */ 4556 public function deliverPDFfromFO($fo) 4557 { 4558 $ilLog = $this->log; 4559 4560 $fo_file = ilUtil::ilTempnam() . ".fo"; 4561 $fp = fopen($fo_file, "w"); 4562 fwrite($fp, $fo); 4563 fclose($fp); 4564 4565 try { 4566 $pdf_base64 = ilRpcClientFactory::factory('RPCTransformationHandler')->ilFO2PDF($fo); 4567 ilUtil::deliverData($pdf_base64->scalar, ilUtil::getASCIIFilename($this->getTitle()) . ".pdf", "application/pdf"); 4568 return true; 4569 } catch (Exception $e) { 4570 $ilLog->write(__METHOD__ . ': ' . $e->getMessage()); 4571 return false; 4572 } 4573 } 4574 4575 /** 4576 * Checks whether or not a question plugin with a given name is active 4577 * 4578 * @param string $a_pname The plugin name 4579 * @access public 4580 */ 4581 public function isPluginActive($a_pname) 4582 { 4583 $ilPluginAdmin = $this->plugin_admin; 4584 if ($ilPluginAdmin->isActive(IL_COMP_MODULE, "SurveyQuestionPool", "svyq", $a_pname)) { 4585 return true; 4586 } else { 4587 return false; 4588 } 4589 } 4590 4591 /** 4592 * Sets the survey id 4593 * 4594 * @param integer $survey_id The survey id 4595 */ 4596 public function setSurveyId($survey_id) 4597 { 4598 $this->survey_id = $survey_id; 4599 } 4600 4601 /** 4602 * Returns a data of all users specified by id list 4603 * 4604 * @param $ids array of user id's 4605 * @return array The user data "usr_id, login, lastname, firstname, clientip" of the users with id as key 4606 */ 4607 public function &getUserData($ids) 4608 { 4609 $ilDB = $this->db; 4610 4611 if (!is_array($ids) || count($ids) == 0) { 4612 return array(); 4613 } 4614 4615 $result = $ilDB->query("SELECT usr_id, login, lastname, firstname FROM usr_data WHERE " . $ilDB->in('usr_id', $ids, false, 'integer') . " ORDER BY login"); 4616 $result_array = array(); 4617 while ($row = $ilDB->fetchAssoc($result)) { 4618 $result_array[$row["usr_id"]] = $row; 4619 } 4620 return $result_array; 4621 } 4622 4623 public function getMailNotification() 4624 { 4625 return $this->mailnotification; 4626 } 4627 4628 public function setMailNotification($a_notification) 4629 { 4630 $this->mailnotification = ($a_notification) ? true : false; 4631 } 4632 4633 public function getMailAddresses() 4634 { 4635 return $this->mailaddresses; 4636 } 4637 4638 public function setMailAddresses($a_addresses) 4639 { 4640 $this->mailaddresses = $a_addresses; 4641 } 4642 4643 public function getMailParticipantData() 4644 { 4645 return $this->mailparticipantdata; 4646 } 4647 4648 public function setMailParticipantData($a_data) 4649 { 4650 $this->mailparticipantdata = $a_data; 4651 } 4652 4653 public function setStartTime($finished_id, $first_question) 4654 { 4655 $ilDB = $this->db; 4656 $time = time(); 4657 //primary for table svy_times 4658 $id = $ilDB->nextId('svy_times'); 4659 $_SESSION['svy_entered_page'] = $time; 4660 $affectedRows = $ilDB->manipulateF( 4661 "INSERT INTO svy_times (id, finished_fi, entered_page, left_page, first_question) VALUES (%s, %s, %s, %s,%s)", 4662 array('integer','integer', 'integer', 'integer', 'integer'), 4663 array($id, $finished_id, $time, null, $first_question) 4664 ); 4665 } 4666 4667 public function setEndTime($finished_id) 4668 { 4669 $ilDB = $this->db; 4670 $time = time(); 4671 $affectedRows = $ilDB->manipulateF( 4672 "UPDATE svy_times SET left_page = %s WHERE finished_fi = %s AND entered_page = %s", 4673 array('integer', 'integer', 'integer'), 4674 array($time, $finished_id, $_SESSION['svy_entered_page']) 4675 ); 4676 unset($_SESSION['svy_entered_page']); 4677 } 4678 4679 public function getWorkingtimeForParticipant($finished_id) 4680 { 4681 $ilDB = $this->db; 4682 4683 $result = $ilDB->queryF( 4684 "SELECT * FROM svy_times WHERE finished_fi = %s", 4685 array('integer'), 4686 array($finished_id) 4687 ); 4688 $total = 0; 4689 while ($row = $ilDB->fetchAssoc($result)) { 4690 if ($row['left_page'] > 0 && $row['entered_page'] > 0) { 4691 $total += $row['left_page'] - $row['entered_page']; 4692 } 4693 } 4694 return $total; 4695 } 4696 4697 public function setTemplate($template_id) 4698 { 4699 $this->template_id = (int) $template_id; 4700 } 4701 4702 public function getTemplate() 4703 { 4704 return $this->template_id; 4705 } 4706 4707 public function updateOrder(array $a_order) 4708 { 4709 if (sizeof($this->questions) == sizeof($a_order)) { 4710 $this->questions = array_flip($a_order); 4711 $this->saveQuestionsToDB(); 4712 } 4713 } 4714 4715 public function getPoolUsage() 4716 { 4717 return $this->pool_usage; 4718 } 4719 4720 public function setPoolUsage($a_value) 4721 { 4722 $this->pool_usage = (bool) $a_value; 4723 } 4724 4725 /** 4726 * Get current pool status 4727 * 4728 * @return bool 4729 */ 4730 public function isPoolActive() 4731 { 4732 $use_pool = (bool) $this->getPoolUsage(); 4733 $template_settings = $this->getTemplate(); 4734 if ($template_settings) { 4735 $template_settings = new ilSettingsTemplate($template_settings); 4736 $template_settings = $template_settings->getSettings(); 4737 $template_settings = $template_settings["use_pool"]; 4738 if ($template_settings && $template_settings["hide"]) { 4739 $use_pool = (bool) $template_settings["value"]; 4740 } 4741 } 4742 return $use_pool; 4743 } 4744 4745 /** 4746 * Apply settings template 4747 * 4748 * @param int $template_id 4749 */ 4750 public function applySettingsTemplate($template_id) 4751 { 4752 if (!$template_id) { 4753 return; 4754 } 4755 4756 $template = new ilSettingsTemplate($template_id); 4757 $template_settings = $template->getSettings(); 4758 //ilUtil::dumpVar($template_settings); exit; 4759 if ($template_settings) { 4760 if ($template_settings["show_question_titles"] !== null) { 4761 if ($template_settings["show_question_titles"]["value"]) { 4762 $this->setShowQuestionTitles(true); 4763 } else { 4764 $this->setShowQuestionTitles(false); 4765 } 4766 } 4767 4768 if ($template_settings["use_pool"] !== null) { 4769 if ($template_settings["use_pool"]["value"]) { 4770 $this->setPoolUsage(true); 4771 } else { 4772 $this->setPoolUsage(false); 4773 } 4774 } 4775 4776 4777 /* see #0021719 4778 if($template_settings["anonymization_options"]["value"]) 4779 { 4780 $anon_map = array('personalized' => self::ANONYMIZE_OFF, 4781 'anonymize_with_code' => self::ANONYMIZE_ON, 4782 'anonymize_without_code' => self::ANONYMIZE_FREEACCESS); 4783 $this->setAnonymize($anon_map[$template_settings["anonymization_options"]["value"]]); 4784 }*/ 4785 4786 // see #0021719 and ilObjectSurveyGUI::savePropertiesObject 4787 $this->setEvaluationAccess($template_settings["evaluation_access"]["value"]); 4788 $codes = (bool) $template_settings["acc_codes"]["value"]; 4789 $anon = (bool) $template_settings["anonymization_options"]["value"]; 4790 if (!$anon) { 4791 if (!$codes) { 4792 $this->setAnonymize(ilObjSurvey::ANONYMIZE_OFF); 4793 } else { 4794 $this->setAnonymize(ilObjSurvey::ANONYMIZE_CODE_ALL); 4795 } 4796 } else { 4797 if ($codes) { 4798 $this->setAnonymize(ilObjSurvey::ANONYMIZE_ON); 4799 } else { 4800 $this->setAnonymize(ilObjSurvey::ANONYMIZE_FREEACCESS); 4801 } 4802 4803 $this->setAnonymousUserList($_POST["anon_list"]); 4804 } 4805 4806 4807 4808 /* other settings: not needed here 4809 * - enabled_end_date 4810 * - enabled_start_date 4811 * - rte_switch 4812 */ 4813 } 4814 4815 $this->setTemplate($template_id); 4816 $this->saveToDb(); 4817 } 4818 4819 public function updateCode($a_id, $a_email, $a_last_name, $a_first_name, $a_sent) 4820 { 4821 $ilDB = $this->db; 4822 4823 $a_email = trim($a_email); 4824 4825 // :TODO: 4826 if (($a_email && !ilUtil::is_email($a_email)) || $a_email == "") { 4827 return false; 4828 } 4829 4830 $data = array("email" => $a_email, 4831 "lastname" => trim($a_last_name), 4832 "firstname" => trim($a_first_name)); 4833 4834 $fields = array( 4835 "externaldata" => array("text", serialize($data)), 4836 "sent" => array("integer", $a_sent) 4837 ); 4838 4839 $ilDB->update( 4840 "svy_anonymous", 4841 $fields, 4842 array("anonymous_id" => array("integer", $a_id)) 4843 ); 4844 4845 return true; 4846 } 4847 4848 4849 // 4850 // 360° 4851 // 4852 4853 public function get360Mode() 4854 { 4855 if ($this->getMode() == ilObjSurvey::MODE_360) { 4856 return true; 4857 } 4858 return false; 4859 } 4860 4861 public function set360SelfEvaluation($a_value) 4862 { 4863 $this->mode_360_self_eval = (bool) $a_value; 4864 } 4865 4866 public function get360SelfEvaluation() 4867 { 4868 return (bool) $this->mode_360_self_eval; 4869 } 4870 4871 public function set360SelfAppraisee($a_value) 4872 { 4873 $this->mode_360_self_appr = (bool) $a_value; 4874 } 4875 4876 public function get360SelfAppraisee() 4877 { 4878 return (bool) $this->mode_360_self_appr; 4879 } 4880 4881 public function set360SelfRaters($a_value) 4882 { 4883 $this->mode_360_self_rate = (bool) $a_value; 4884 } 4885 4886 public function get360SelfRaters() 4887 { 4888 return (bool) $this->mode_360_self_rate; 4889 } 4890 4891 public function set360Results($a_value) 4892 { 4893 $this->mode_360_results = (int) $a_value; 4894 } 4895 4896 public function get360Results() 4897 { 4898 return (int) $this->mode_360_results; 4899 } 4900 4901 public function addAppraisee($a_user_id) 4902 { 4903 global $DIC; 4904 4905 $ilDB = $DIC->database(); 4906 $access = $DIC->access(); 4907 4908 if (!$this->isAppraisee($a_user_id) && 4909 $a_user_id != ANONYMOUS_USER_ID) { 4910 $fields = array( 4911 "obj_id" => array("integer", $this->getSurveyId()), 4912 "user_id" => array("integer", $a_user_id) 4913 ); 4914 $ilDB->insert("svy_360_appr", $fields); 4915 4916 // send notification and add to desktop 4917 if ($access->checkAccessOfUser($a_user_id, "read", "", $this->getRefId())) { 4918 $this->sendAppraiseeNotification($a_user_id); 4919 } 4920 } 4921 } 4922 4923 /** 4924 * Send appraisee notification 4925 * 4926 * @param int $a_user_id user id 4927 */ 4928 public function sendAppraiseeNotification($a_user_id) 4929 { 4930 $ntf = new ilSystemNotification(); 4931 $ntf->setLangModules(array("svy", "survey")); 4932 $ntf->setRefId($this->getRefId()); 4933 $ntf->setGotoLangId('url'); 4934 4935 // user specific language 4936 $lng = $ntf->getUserLanguage($a_user_id); 4937 4938 $ntf->setIntroductionLangId("svy_user_added_360_appraisee_mail"); 4939 $subject = str_replace("%1", $this->getTitle(), $lng->txt("svy_user_added_360_appraisee")); 4940 4941 // #10044 4942 $mail = new ilMail(ANONYMOUS_USER_ID); 4943 $mail->enqueue( 4944 ilObjUser::_lookupLogin($a_user_id), 4945 null, 4946 null, 4947 $subject, 4948 $ntf->composeAndGetMessage($a_user_id, null, "read", true), 4949 [] 4950 ); 4951 } 4952 4953 /** 4954 * Send appraisee notification 4955 * 4956 * @param int $a_user_id user id 4957 */ 4958 public function sendAppraiseeCloseNotification($a_user_id) 4959 { 4960 $ntf = new ilSystemNotification(); 4961 $ntf->setLangModules(array("svy", "survey")); 4962 $ntf->setRefId($this->getRefId()); 4963 $ntf->setGotoLangId('url'); 4964 4965 // user specific language 4966 $lng = $ntf->getUserLanguage($a_user_id); 4967 4968 $ntf->setIntroductionLangId("svy_user_added_360_appraisee_close_mail"); 4969 $subject = str_replace("%1", $this->getTitle(), $lng->txt("svy_user_added_360_appraisee")); 4970 4971 // #10044 4972 $mail = new ilMail(ANONYMOUS_USER_ID); 4973 $mail->enqueue( 4974 ilObjUser::_lookupLogin($a_user_id), 4975 null, 4976 null, 4977 $subject, 4978 $ntf->composeAndGetMessage($a_user_id, null, "read", true), 4979 [] 4980 ); 4981 } 4982 4983 /** 4984 * Send rater notification 4985 * 4986 * @param int $a_user_id user id 4987 */ 4988 public function sendRaterNotification($a_user_id, $a_appraisee_id) 4989 { 4990 $ntf = new ilSystemNotification(); 4991 $ntf->setLangModules(array("svy", "survey")); 4992 $ntf->setRefId($this->getRefId()); 4993 $ntf->setGotoLangId('url'); 4994 4995 // user specific language 4996 $lng = $ntf->getUserLanguage($a_user_id); 4997 4998 $ntf->setIntroductionLangId("svy_user_added_360_rater_mail"); 4999 $subject = str_replace("%1", $this->getTitle(), $lng->txt("svy_user_added_360_rater")); 5000 $ntf->addAdditionalInfo("survey_360_appraisee", ilUserUtil::getNamePresentation($a_appraisee_id, false, false, "", true)); 5001 5002 // #10044 5003 $mail = new ilMail(ANONYMOUS_USER_ID); 5004 $mail->enqueue( 5005 ilObjUser::_lookupLogin($a_user_id), 5006 null, 5007 null, 5008 $subject, 5009 $ntf->composeAndGetMessage($a_user_id, null, "read", true), 5010 [] 5011 ); 5012 } 5013 5014 public function isAppraisee($a_user_id) 5015 { 5016 $ilDB = $this->db; 5017 5018 $set = $ilDB->query("SELECT user_id" . 5019 " FROM svy_360_appr" . 5020 " WHERE obj_id = " . $ilDB->quote($this->getSurveyId(), "integer") . 5021 " AND user_id = " . $ilDB->quote($a_user_id, "integer")); 5022 return (bool) $ilDB->numRows($set); 5023 } 5024 5025 public function isAppraiseeClosed($a_user_id) 5026 { 5027 $ilDB = $this->db; 5028 5029 $set = $ilDB->query("SELECT has_closed" . 5030 " FROM svy_360_appr" . 5031 " WHERE obj_id = " . $ilDB->quote($this->getSurveyId(), "integer") . 5032 " AND user_id = " . $ilDB->quote($a_user_id, "integer")); 5033 $row = $ilDB->fetchAssoc($set); 5034 return $row["has_closed"]; 5035 } 5036 5037 public function deleteAppraisee($a_user_id) 5038 { 5039 $ilDB = $this->db; 5040 5041 $ilDB->manipulate("DELETE FROM svy_360_appr" . 5042 " WHERE obj_id = " . $ilDB->quote($this->getSurveyId(), "integer") . 5043 " AND user_id = " . $ilDB->quote($a_user_id, "integer")); 5044 5045 $set = $ilDB->query("SELECT user_id" . 5046 " FROM svy_360_rater" . 5047 " WHERE obj_id = " . $ilDB->quote($this->getSurveyId(), "integer") . 5048 " AND appr_id = " . $ilDB->quote($a_user_id, "integer")); 5049 while ($row = $ilDB->fetchAssoc($set)) { 5050 $this->deleteRater($a_user_id, $row["user_id"]); 5051 } 5052 // appraisee will not be part of raters table 5053 if ($this->get360SelfEvaluation()) { 5054 $this->deleteRater($a_user_id, $a_user_id); 5055 } 5056 } 5057 5058 public function getAppraiseesData() 5059 { 5060 $ilDB = $this->db; 5061 5062 $res = array(); 5063 5064 $set = $ilDB->query("SELECT * FROM svy_360_appr" . 5065 " WHERE obj_id = " . $ilDB->quote($this->getSurveyId(), "integer")); 5066 while ($row = $ilDB->fetchAssoc($set)) { 5067 $name = ilObjUser::_lookupName($row["user_id"]); 5068 $name["email"] = ilObjUser::_lookupEmail($row["user_id"]); 5069 $name["name"] = $name["lastname"] . ", " . $name["firstname"]; 5070 $res[$row["user_id"]] = $name; 5071 5072 $finished = 0; 5073 $raters = $this->getRatersData($row["user_id"]); 5074 foreach ($raters as $rater) { 5075 if ($rater["finished"]) { 5076 $finished++; 5077 } 5078 } 5079 $res[$row["user_id"]]["finished"] = $finished . "/" . sizeof($raters); 5080 $res[$row["user_id"]]["closed"] = $row["has_closed"]; 5081 } 5082 5083 return $res; 5084 } 5085 5086 public function addRater($a_appraisee_id, $a_user_id, $a_anonymous_id = 0) 5087 { 5088 global $DIC; 5089 5090 $ilDB = $DIC->database(); 5091 $access = $DIC->access(); 5092 5093 if ($this->isAppraisee($a_appraisee_id) && 5094 !$this->isRater($a_appraisee_id, $a_user_id, $a_anonymous_id)) { 5095 $fields = array( 5096 "obj_id" => array("integer", $this->getSurveyId()), 5097 "appr_id" => array("integer", $a_appraisee_id), 5098 "user_id" => array("integer", $a_user_id), 5099 "anonymous_id" => array("integer", $a_anonymous_id) 5100 ); 5101 $ilDB->insert("svy_360_rater", $fields); 5102 5103 // send notification and add to desktop 5104 if ($access->checkAccessOfUser($a_user_id, "read", "", $this->getRefId())) { 5105 $this->sendRaterNotification($a_user_id, $a_appraisee_id); 5106 } 5107 } 5108 } 5109 5110 public function isRater($a_appraisee_id, $a_user_id, $a_anonymous_id = 0) 5111 { 5112 $ilDB = $this->db; 5113 5114 // user is rater if already appraisee and active self-evaluation 5115 if ($this->isAppraisee($a_user_id) && 5116 $this->get360SelfEvaluation() && 5117 (!$a_appraisee_id || $a_appraisee_id == $a_user_id)) { 5118 return true; 5119 } 5120 5121 // :TODO: should we get rid of code as well? 5122 5123 $sql = "SELECT user_id" . 5124 " FROM svy_360_rater" . 5125 " WHERE obj_id = " . $ilDB->quote($this->getSurveyId(), "integer") . 5126 " AND user_id = " . $ilDB->quote($a_user_id, "integer") . 5127 " AND anonymous_id = " . $ilDB->quote($a_anonymous_id, "integer"); 5128 if ($a_appraisee_id) { 5129 $sql .= " AND appr_id = " . $ilDB->quote($a_appraisee_id, "integer"); 5130 } 5131 $set = $ilDB->query($sql); 5132 return (bool) $ilDB->numRows($set); 5133 } 5134 5135 public function deleteRater($a_appraisee_id, $a_user_id, $a_anonymous_id = 0) 5136 { 5137 $ilDB = $this->db; 5138 5139 $finished_id = $this->getFinishedIdForAppraiseeIdAndRaterId($a_appraisee_id, $a_user_id); 5140 if ($finished_id) { 5141 $this->removeSelectedSurveyResults(array($finished_id)); 5142 } 5143 5144 $ilDB->manipulate("DELETE FROM svy_360_rater" . 5145 " WHERE obj_id = " . $ilDB->quote($this->getSurveyId(), "integer") . 5146 " AND appr_id = " . $ilDB->quote($a_appraisee_id, "integer") . 5147 " AND user_id = " . $ilDB->quote($a_user_id, "integer") . 5148 " AND anonymous_id = " . $ilDB->quote($a_anonymous_id, "integer")); 5149 } 5150 5151 public function getRatersData($a_appraisee_id) 5152 { 5153 $ilDB = $this->db; 5154 5155 $res = $anonymous_ids = array(); 5156 5157 $set = $ilDB->query("SELECT * FROM svy_360_rater" . 5158 " WHERE obj_id = " . $ilDB->quote($this->getSurveyId(), "integer") . 5159 " AND appr_id = " . $ilDB->quote($a_appraisee_id, "integer")); 5160 while ($row = $ilDB->fetchAssoc($set)) { 5161 if ($row["anonymous_id"]) { 5162 $res["a" . $row["anonymous_id"]] = array( 5163 "lastname" => "unknown code " . $row["anonymous_id"], 5164 "sent" => $row["mail_sent"], 5165 "finished" => null 5166 ); 5167 $anonymous_ids[] = $row["anonymous_id"]; 5168 } else { 5169 $name = ilObjUser::_lookupName($row["user_id"]); 5170 $name["name"] = $name["lastname"] . ", " . $name["firstname"]; 5171 $name["user_id"] = "u" . $name["user_id"]; 5172 $name["email"] = ilObjUser::_lookupEmail($row["user_id"]); 5173 $name["sent"] = $row["mail_sent"]; 5174 $name["finished"] = (bool) $this->is360SurveyStarted($a_appraisee_id, $row["user_id"]); 5175 $res["u" . $row["user_id"]] = $name; 5176 } 5177 } 5178 5179 if (sizeof($anonymous_ids)) { 5180 $data = $this->getSurveyCodesTableData($anonymous_ids); 5181 foreach ($data as $item) { 5182 if (isset($res["a" . $item["id"]])) { 5183 $res["a" . $item["id"]] = array( 5184 "user_id" => "a" . $item["id"], 5185 "lastname" => $item["last_name"], 5186 "firstname" => $item["first_name"], 5187 "name" => $item["last_name"] . ", " . $item["first_name"], 5188 "login" => "", 5189 "email" => $item["email"], 5190 "code" => $item["code"], 5191 "href" => $item["href"], 5192 "sent" => $res["a" . $item["id"]]["sent"], 5193 "finished" => (bool) $this->is360SurveyStarted($a_appraisee_id, null, $item["code"]) 5194 ); 5195 } 5196 } 5197 } 5198 5199 return $res; 5200 } 5201 5202 public function getAppraiseesToRate($a_user_id, $a_anonymous_id = null) 5203 { 5204 $ilDB = $this->db; 5205 5206 $res = array(); 5207 5208 $sql = "SELECT appr_id FROM svy_360_rater" . 5209 " WHERE obj_id = " . $ilDB->quote($this->getSurveyId(), "integer"); 5210 5211 if ($a_user_id) { 5212 $sql .= " AND user_id = " . $ilDB->quote($a_user_id, "integer"); 5213 } else { 5214 $sql .= " AND anonymous_id = " . $ilDB->quote($a_anonymous_id, "integer"); 5215 } 5216 5217 $set = $ilDB->query($sql); 5218 while ($row = $ilDB->fetchAssoc($set)) { 5219 $res[] = $row["appr_id"]; 5220 } 5221 5222 // user may evaluate himself if already appraisee 5223 if ($this->get360SelfEvaluation() && 5224 $this->isAppraisee($a_user_id) && 5225 !in_array($a_user_id, $res)) { 5226 $res[] = $a_user_id; 5227 } 5228 5229 return $res; 5230 } 5231 5232 public function getAnonymousIdByCode($a_code) 5233 { 5234 $ilDB = $this->db; 5235 5236 $set = $ilDB->query("SELECT anonymous_id FROM svy_anonymous" . 5237 " WHERE survey_fi = " . $ilDB->quote($this->getSurveyId(), "integer") . 5238 " AND survey_key = " . $ilDB->quote($a_code, "text")); 5239 $res = $ilDB->fetchAssoc($set); 5240 return $res["anonymous_id"]; 5241 } 5242 5243 public function is360SurveyStarted($appr_id, $user_id, $anonymous_code = null) 5244 { 5245 $ilDB = $this->db; 5246 5247 $sql = "SELECT * FROM svy_finished" . 5248 " WHERE survey_fi =" . $ilDB->quote($this->getSurveyId(), "integer") . 5249 " AND appr_id = " . $ilDB->quote($appr_id, "integer"); 5250 if ($user_id) { 5251 $sql .= " AND user_fi = " . $ilDB->quote($user_id, "integer"); 5252 } else { 5253 $sql .= " AND anonymous_id = " . $ilDB->quote($anonymous_code, "text"); 5254 } 5255 $result = $ilDB->query($sql); 5256 if ($result->numRows() == 0) { 5257 return false; 5258 } else { 5259 $row = $ilDB->fetchAssoc($result); 5260 return (int) $row["state"]; 5261 } 5262 } 5263 5264 public function getUserSurveyExecutionStatus($a_code = null) 5265 { 5266 $ilUser = $this->user; 5267 $ilDB = $this->db; 5268 5269 $user_id = $ilUser->getId(); 5270 5271 // code is obligatory? 5272 if (!$this->isAccessibleWithoutCode()) { 5273 if (!$a_code) { 5274 // registered raters do not need code 5275 if ($this->get360Mode() && 5276 $user_id != ANONYMOUS_USER_ID && 5277 $this->isRater(0, $user_id)) { 5278 // auto-generate code 5279 $a_code = $this->createNewAccessCode(); 5280 $this->saveUserAccessCode($user_id, $a_code); 5281 } else { 5282 return null; 5283 } 5284 } 5285 } elseif ($user_id == ANONYMOUS_USER_ID || 5286 $this->getAnonymize() == self::ANONYMIZE_FREEACCESS) { 5287 if (!$a_code) { 5288 // auto-generate code 5289 $a_code = $this->createNewAccessCode(); 5290 $this->saveUserAccessCode($user_id, $a_code); 5291 } 5292 } else { 5293 $a_code = null; 5294 } 5295 5296 $res = array(); 5297 5298 $sql = "SELECT * FROM svy_finished" . 5299 " WHERE survey_fi = " . $ilDB->quote($this->getSurveyId(), "integer"); 5300 // if proper user id is given, use it or current code 5301 if ($user_id != ANONYMOUS_USER_ID) { 5302 $sql .= " AND (user_fi = " . $ilDB->quote($user_id, "integer") . 5303 " OR anonymous_id = " . $ilDB->quote($a_code, "text") . ")"; 5304 } 5305 // use anonymous code to find finished id(s) 5306 else { 5307 $sql .= " AND anonymous_id = " . $ilDB->quote($a_code, "text"); 5308 } 5309 $set = $ilDB->query($sql); 5310 while ($row = $ilDB->fetchAssoc($set)) { 5311 $res[$row["finished_id"]] = array("appr_id" => $row["appr_id"], 5312 "user_id" => $row["user_fi"], 5313 "code" => $row["anonymous_id"], 5314 "finished" => (bool) $row["state"]); 5315 } 5316 5317 return array("code" => $a_code, "runs" => $res); 5318 } 5319 5320 public function findCodeForUser($a_user_id) 5321 { 5322 $ilDB = $this->db; 5323 5324 if ($a_user_id != ANONYMOUS_USER_ID) { 5325 $set = $ilDB->query("SELECT sf.anonymous_id FROM svy_finished sf" . 5326 " WHERE sf.survey_fi = " . $ilDB->quote($this->getSurveyId(), "integer") . 5327 " AND sf.user_fi = " . $ilDB->quote($a_user_id, "integer")); 5328 $a_code = $ilDB->fetchAssoc($set); 5329 return $a_code["anonymous_id"]; 5330 } 5331 } 5332 5333 public function isUnusedCode($a_code, $a_user_id) 5334 { 5335 $ilDB = $this->db; 5336 5337 $set = $ilDB->query("SELECT user_fi FROM svy_finished" . 5338 " WHERE survey_fi = " . $ilDB->quote($this->getSurveyId(), "integer") . 5339 " AND anonymous_id = " . $ilDB->quote($a_code, "text")); 5340 $user_id = $ilDB->fetchAssoc($set); 5341 $user_id = $user_id["user_fi"]; 5342 5343 if ($user_id && ($user_id != $a_user_id || $user_id == ANONYMOUS_USER_ID)) { 5344 return false; 5345 } 5346 return true; 5347 } 5348 5349 public function getFinishedIdsForAppraiseeId($a_appr_id, $a_exclude_appraisee = false) 5350 { 5351 $ilDB = $this->db; 5352 5353 $res = array(); 5354 5355 $set = $ilDB->query("SELECT finished_id, user_fi FROM svy_finished" . 5356 " WHERE survey_fi = " . $ilDB->quote($this->getSurveyId(), "integer") . 5357 " AND appr_id = " . $ilDB->quote($a_appr_id, "integer")); 5358 while ($row = $ilDB->fetchAssoc($set)) { 5359 if ($a_exclude_appraisee && $row["user_fi"] == $a_appr_id) { 5360 continue; 5361 } 5362 $res[] = $row["finished_id"]; 5363 } 5364 5365 return $res; 5366 } 5367 5368 /** 5369 * Get finished id for an appraisee and a rater 5370 * 5371 * @param int $a_appraisee_id appraisee id 5372 * @param int $a_rater_id rater id 5373 * @return int finished id 5374 */ 5375 public function getFinishedIdForAppraiseeIdAndRaterId($a_appr_id, $a_rat_id) 5376 { 5377 $ilDB = $this->db; 5378 5379 $set = $ilDB->query("SELECT finished_id, user_fi FROM svy_finished" . 5380 " WHERE survey_fi = " . $ilDB->quote($this->getSurveyId(), "integer") . 5381 " AND appr_id = " . $ilDB->quote($a_appr_id, "integer") . 5382 " AND user_fi = " . $ilDB->quote($a_rat_id, "integer")); 5383 $row = $ilDB->fetchAssoc($set); 5384 return $row["finished_id"]; 5385 } 5386 5387 5388 // 360° using competence/skill service 5389 5390 /** 5391 * Set skill service 5392 * 5393 * @param bool $a_val activate skill service 5394 */ 5395 public function setSkillService($a_val) 5396 { 5397 $this->mode_skill_service = $a_val; 5398 } 5399 5400 /** 5401 * Get skill service 5402 * 5403 * @return bool activate skill service 5404 */ 5405 public function getSkillService() 5406 { 5407 return $this->mode_skill_service; 5408 } 5409 5410 public function set360RaterSent($a_appraisee_id, $a_user_id, $a_anonymous_id, $a_tstamp = null) 5411 { 5412 $ilDB = $this->db; 5413 5414 if (!$a_tstamp) { 5415 $a_tstamp = time(); 5416 } 5417 5418 $ilDB->manipulate("UPDATE svy_360_rater" . 5419 " SET mail_sent = " . $ilDB->quote($a_tstamp, "integer") . 5420 " WHERE obj_id = " . $ilDB->quote($this->getSurveyId(), "integer") . 5421 " AND appr_id = " . $ilDB->quote($a_appraisee_id, "integer") . 5422 " AND user_id = " . $ilDB->quote($a_user_id, "integer") . 5423 " AND anonymous_id = " . $ilDB->quote($a_anonymous_id, "integer")); 5424 } 5425 5426 public function closeAppraisee($a_user_id) 5427 { 5428 global $DIC; 5429 5430 $ilDB = $DIC->database(); 5431 $user = $DIC->user(); 5432 5433 // close the appraisee 5434 $ilDB->manipulate("UPDATE svy_360_appr" . 5435 " SET has_closed = " . $ilDB->quote(time(), "integer") . 5436 " WHERE obj_id = " . $ilDB->quote($this->getSurveyId(), "integer") . 5437 " AND user_id = " . $ilDB->quote($a_user_id, "integer")); 5438 5439 // write competences 5440 $skmg_set = new ilSkillManagementSettings(); 5441 if ($this->getSkillService() && $skmg_set->isActivated()) { 5442 $sskill = new ilSurveySkill($this); 5443 $sskill->writeAndAddAppraiseeSkills($a_user_id); 5444 } 5445 5446 // send notification 5447 if ($user->getId() != $a_user_id) { 5448 $this->sendAppraiseeCloseNotification($a_user_id); 5449 } 5450 } 5451 5452 public function openAllAppraisees() 5453 { 5454 $ilDB = $this->db; 5455 5456 $ilDB->manipulate("UPDATE svy_360_appr" . 5457 " SET has_closed = " . $ilDB->quote(null, "integer") . 5458 " WHERE obj_id = " . $ilDB->quote($this->getSurveyId(), "integer")); 5459 } 5460 5461 public static function validateExternalRaterCode($a_ref_id, $a_code) 5462 { 5463 if (!isset($_SESSION["360_extrtr"][$a_ref_id])) { 5464 $svy = new self($a_ref_id); 5465 $svy->loadFromDB(); 5466 5467 if ($svy->canStartSurvey(null, true) && 5468 $svy->get360Mode() && 5469 $svy->isAnonymousKey($a_code)) { 5470 $anonymous_id = $svy->getAnonymousIdByCode($a_code); 5471 if ($anonymous_id) { 5472 if (sizeof($svy->getAppraiseesToRate(null, $anonymous_id))) { 5473 $_SESSION["360_extrtr"][$a_ref_id] = true; 5474 return true; 5475 } 5476 } 5477 } 5478 5479 $_SESSION["360_extrtr"][$a_ref_id] = false; 5480 return false; 5481 } 5482 5483 return $_SESSION["360_extrtr"][$a_ref_id]; 5484 } 5485 5486 5487 // 5488 // reminder/notification 5489 // 5490 5491 public function getReminderStatus() 5492 { 5493 return (bool) $this->reminder_status; 5494 } 5495 5496 public function setReminderStatus($a_value) 5497 { 5498 $this->reminder_status = (bool) $a_value; 5499 } 5500 5501 public function getReminderStart() 5502 { 5503 return $this->reminder_start; 5504 } 5505 5506 public function setReminderStart(ilDate $a_value = null) 5507 { 5508 $this->reminder_start = $a_value; 5509 } 5510 5511 public function getReminderEnd() 5512 { 5513 return $this->reminder_end; 5514 } 5515 5516 public function setReminderEnd(ilDate $a_value = null) 5517 { 5518 $this->reminder_end = $a_value; 5519 } 5520 5521 public function getReminderFrequency() 5522 { 5523 return $this->reminder_frequency; 5524 } 5525 5526 public function setReminderFrequency($a_value) 5527 { 5528 $this->reminder_frequency = (int) $a_value; 5529 } 5530 5531 public function getReminderTarget() 5532 { 5533 return $this->reminder_target; 5534 } 5535 5536 public function setReminderTarget($a_value) 5537 { 5538 $this->reminder_target = (int) $a_value; 5539 } 5540 5541 public function getReminderLastSent() 5542 { 5543 return $this->reminder_last_sent; 5544 } 5545 5546 public function setReminderLastSent($a_value) 5547 { 5548 $this->reminder_last_sent = $a_value; 5549 } 5550 5551 /** 5552 * @param bool $selectDefault 5553 * @return mixed 5554 */ 5555 public function getReminderTemplate($selectDefault = false) 5556 { 5557 if ($selectDefault) { 5558 $defaultTemplateId = 0; 5559 $this->getReminderMailTemplates($defaultTemplateId); 5560 5561 if ($defaultTemplateId > 0) { 5562 return $defaultTemplateId; 5563 } 5564 } 5565 5566 return $this->reminder_tmpl; 5567 } 5568 5569 public function setReminderTemplate($a_value) 5570 { 5571 $this->reminder_tmpl = $a_value; 5572 } 5573 5574 public function getTutorNotificationStatus() 5575 { 5576 return (bool) $this->tutor_ntf_status; 5577 } 5578 5579 public function setTutorNotificationStatus($a_value) 5580 { 5581 $this->tutor_ntf_status = (bool) $a_value; 5582 } 5583 5584 public function getTutorNotificationRecipients() 5585 { 5586 return $this->tutor_ntf_recipients; 5587 } 5588 5589 public function setTutorNotificationRecipients(array $a_value) 5590 { 5591 $this->tutor_ntf_recipients = $a_value; 5592 } 5593 5594 public function getTutorNotificationTarget() 5595 { 5596 return $this->tutor_ntf_target; 5597 } 5598 5599 public function setTutorNotificationTarget($a_value) 5600 { 5601 $this->tutor_ntf_target = (int) $a_value; 5602 } 5603 5604 public function getTutorResultsStatus() 5605 { 5606 return (bool) $this->tutor_res_status; 5607 } 5608 5609 public function setTutorResultsStatus($a_value) 5610 { 5611 $this->tutor_res_status = (bool) $a_value; 5612 } 5613 5614 public function getTutorResultsRecipients() 5615 { 5616 return $this->tutor_res_recipients; 5617 } 5618 5619 public function setTutorResultsRecipients(array $a_value) 5620 { 5621 $this->tutor_res_recipients = $a_value; 5622 } 5623 5624 protected function checkTutorNotification() 5625 { 5626 $ilDB = $this->db; 5627 5628 if ($this->getTutorNotificationStatus()) { 5629 $user_ids = $this->getNotificationTargetUserIds(($this->getTutorNotificationTarget() == self::NOTIFICATION_INVITED_USERS)); 5630 if ($user_ids) { 5631 $set = $ilDB->query("SELECT COUNT(*) numall FROM svy_finished" . 5632 " WHERE survey_fi = " . $ilDB->quote($this->getSurveyId(), "integer") . 5633 " AND state = " . $ilDB->quote(1, "integer") . 5634 " AND " . $ilDB->in("user_fi", $user_ids, "", "integer")); 5635 $row = $ilDB->fetchAssoc($set); 5636 if ($row["numall"] == sizeof($user_ids)) { 5637 $this->sendTutorNotification(); 5638 } 5639 } 5640 } 5641 } 5642 5643 /** 5644 * Send 360 reminders 5645 * 5646 * @param 5647 * @return 5648 */ 5649 public function sent360Reminders() 5650 { 5651 global $DIC; 5652 5653 $access = $DIC->access(); 5654 5655 // collect all open ratings 5656 $rater_ids = array(); 5657 foreach ($this->getAppraiseesData() as $app) { 5658 $this->log->debug("Handle appraisee " . $app['user_id']); 5659 5660 if (!$this->isAppraiseeClosed($app['user_id'])) { 5661 $this->log->debug("Check self evaluation, self: " . $this->get360SelfAppraisee() . ", target: " . $this->getReminderTarget()); 5662 5663 // self evaluation? 5664 if ($this->get360SelfEvaluation() && 5665 in_array($this->getReminderTarget(), array(ilObjSurvey::NOTIFICATION_APPRAISEES, ilObjSurvey::NOTIFICATION_APPRAISEES_AND_RATERS))) { 5666 $this->log->debug("...1"); 5667 // did user already finished self evaluation? 5668 if (!$this->is360SurveyStarted($app['user_id'], $app['user_id'])) { 5669 $this->log->debug("...2"); 5670 if (!is_array($rater_ids[$app['user_id']])) { 5671 $rater_ids[$app['user_id']] = array(); 5672 } 5673 if (!in_array($app["user_id"], $rater_ids[$app['user_id']])) { 5674 $rater_ids[$app['user_id']][] = $app["user_id"]; 5675 } 5676 } 5677 } 5678 5679 $this->log->debug("Check raters."); 5680 5681 // should raters be notified? 5682 if (in_array($this->getReminderTarget(), array(ilObjSurvey::NOTIFICATION_RATERS, ilObjSurvey::NOTIFICATION_APPRAISEES_AND_RATERS))) { 5683 foreach ($this->getRatersData($app['user_id']) as $rater) { 5684 // is rater not anonymous and did not rate yet? 5685 if (!$rater["anonymous_id"] && !$rater["finished"]) { 5686 if (!is_array($rater_ids[$rater["user_id"]])) { 5687 $rater_ids[$rater["user_id"]] = array(); 5688 } 5689 if (!in_array($app["user_id"], $rater_ids[$rater["user_id"]])) { 5690 $rater_ids[$rater["user_id"]][] = $app["user_id"]; 5691 } 5692 } 5693 } 5694 } 5695 } 5696 } 5697 5698 $this->log->debug("Found raters:" . count($rater_ids)); 5699 5700 foreach ($rater_ids as $id => $app) { 5701 if ($access->checkAccessOfUser($id, "read", "", $this->getRefId())) { 5702 $this->send360ReminderToUser($id, $app); 5703 } 5704 } 5705 } 5706 5707 /** 5708 * Send rater notification 5709 * 5710 * @param int $a_user_id user id 5711 */ 5712 public function send360ReminderToUser($a_user_id, $a_appraisee_ids) 5713 { 5714 $this->log->debug("Send mail to:" . $a_user_id); 5715 5716 $ntf = new ilSystemNotification(); 5717 $ntf->setLangModules(array("svy", "survey")); 5718 $ntf->setRefId($this->getRefId()); 5719 $ntf->setGotoLangId('url'); 5720 5721 // user specific language 5722 $lng = $ntf->getUserLanguage($a_user_id); 5723 5724 $ntf->setIntroductionLangId("svy_user_added_360_rater_reminder_mail"); 5725 $subject = str_replace("%1", $this->getTitle(), $lng->txt("svy_user_added_360_rater")); 5726 5727 foreach ($a_appraisee_ids as $appraisee_id) { 5728 $ntf->addAdditionalInfo("survey_360_appraisee", ilUserUtil::getNamePresentation($appraisee_id, false, false, "", true)); 5729 } 5730 5731 // #10044 5732 $mail = new ilMail(ANONYMOUS_USER_ID); 5733 $mail->enqueue( 5734 ilObjUser::_lookupLogin($a_user_id), 5735 null, 5736 null, 5737 $subject, 5738 $ntf->composeAndGetMessage($a_user_id, null, "read", true), 5739 [] 5740 ); 5741 } 5742 5743 5744 public function getNotificationTargetUserIds($a_use_invited) 5745 { 5746 $tree = $this->tree; 5747 5748 if ((bool) $a_use_invited) { 5749 $user_ids = $this->invitation_manager->getAllForSurvey($this->getSurveyId()); 5750 } else { 5751 $parent_grp_ref_id = $tree->checkForParentType($this->getRefId(), "grp"); 5752 if ($parent_grp_ref_id) { 5753 $part = new ilGroupParticipants(ilObject::_lookupObjId($parent_grp_ref_id)); 5754 $user_ids = $part->getMembers(); 5755 } else { 5756 $parent_crs_ref_id = $tree->checkForParentType($this->getRefId(), "crs"); 5757 if ($parent_crs_ref_id) { 5758 $part = new ilCourseParticipants(ilObject::_lookupObjId($parent_crs_ref_id)); 5759 $user_ids = $part->getMembers(); 5760 } 5761 } 5762 } 5763 return $user_ids; 5764 } 5765 5766 protected function sendTutorNotification() 5767 { 5768 $link = ilLink::_getStaticLink($this->getRefId(), "svy"); 5769 5770 foreach ($this->getTutorNotificationRecipients() as $user_id) { 5771 // use language of recipient to compose message 5772 $ulng = ilLanguageFactory::_getLanguageOfUser($user_id); 5773 $ulng->loadLanguageModule('survey'); 5774 5775 $subject = sprintf($ulng->txt('survey_notification_tutor_subject'), $this->getTitle()); 5776 $message = sprintf($ulng->txt('survey_notification_tutor_salutation'), ilObjUser::_lookupFullname($user_id)) . "\n\n"; 5777 5778 $message .= $ulng->txt('survey_notification_tutor_body') . ":\n\n"; 5779 $message .= $ulng->txt('obj_svy') . ": " . $this->getTitle() . "\n"; 5780 $message .= "\n" . $ulng->txt('survey_notification_tutor_link') . ": " . $link; 5781 5782 $mail_obj = new ilMail(ANONYMOUS_USER_ID); 5783 $mail_obj->appendInstallationSignature(true); 5784 $mail_obj->enqueue( 5785 ilObjUser::_lookupLogin($user_id), 5786 "", 5787 "", 5788 $subject, 5789 $message, 5790 array() 5791 ); 5792 } 5793 } 5794 5795 public function checkReminder() 5796 { 5797 $ilDB = $this->db; 5798 $ilAccess = $this->access; 5799 5800 $now = time(); 5801 $now_with_format = date("YmdHis", $now); 5802 $today = date("Y-m-d"); 5803 5804 $this->log->debug("Check status and dates."); 5805 5806 // object settings / participation period 5807 if ( 5808 $this->getOfflineStatus() || 5809 !$this->getReminderStatus() || 5810 ($this->getStartDate() && $now_with_format < $this->getStartDate()) || 5811 ($this->getEndDate() && $now_with_format > $this->getEndDate())) { 5812 return false; 5813 } 5814 5815 // reminder period 5816 $start = $this->getReminderStart(); 5817 if ($start) { 5818 $start = $start->get(IL_CAL_DATE); 5819 } 5820 $end = $this->getReminderEnd(); 5821 if ($end) { 5822 $end = $end->get(IL_CAL_DATE); 5823 } 5824 if ($today < $start || 5825 ($end && $today > $end)) { 5826 return false; 5827 } 5828 5829 $this->log->debug("Check access period."); 5830 5831 // object access period 5832 $item_data = ilObjectActivation::getItem($this->getRefId()); 5833 if ($item_data["timing_type"] == ilObjectActivation::TIMINGS_ACTIVATION && 5834 ($now < $item_data["timing_start"] || 5835 $now > $item_data["timing_end"])) { 5836 return false; 5837 } 5838 5839 $this->log->debug("Check frequency."); 5840 5841 // check frequency 5842 $cut = new ilDate($today, IL_CAL_DATE); 5843 $cut->increment(IL_CAL_DAY, $this->getReminderFrequency() * -1); 5844 if (!$this->getReminderLastSent() || 5845 $cut->get(IL_CAL_DATE) >= substr($this->getReminderLastSent(), 0, 10)) { 5846 $missing_ids = array(); 5847 5848 if (!$this->get360Mode()) { 5849 $this->log->debug("Entering survey mode."); 5850 5851 // #16871 5852 $user_ids = $this->getNotificationTargetUserIds(($this->getReminderTarget() == self::NOTIFICATION_INVITED_USERS)); 5853 if ($user_ids) { 5854 // gather participants who already finished 5855 $finished_ids = array(); 5856 $set = $ilDB->query("SELECT user_fi FROM svy_finished" . 5857 " WHERE survey_fi = " . $ilDB->quote($this->getSurveyId(), "integer") . 5858 " AND state = " . $ilDB->quote(1, "text") . 5859 " AND " . $ilDB->in("user_fi", $user_ids, "", "integer")); 5860 while ($row = $ilDB->fetchAssoc($set)) { 5861 $finished_ids[] = $row["user_fi"]; 5862 } 5863 5864 // some users missing out? 5865 $missing_ids = array_diff($user_ids, $finished_ids); 5866 if ($missing_ids) { 5867 foreach ($missing_ids as $idx => $user_id) { 5868 // should be able to participate 5869 if (!$ilAccess->checkAccessOfUser($user_id, "read", "", $this->getRefId(), "svy", $this->getId())) { 5870 unset($missing_ids[$idx]); 5871 } 5872 } 5873 } 5874 if ($missing_ids) { 5875 $this->sentReminder($missing_ids); 5876 } 5877 } 5878 } else { 5879 $this->log->debug("Entering 360 mode."); 5880 5881 $this->sent360Reminders(); 5882 } 5883 5884 5885 $this->setReminderLastSent($today); 5886 $this->saveToDb(); 5887 5888 return sizeof($missing_ids); 5889 } 5890 5891 return false; 5892 } 5893 5894 protected function sentReminder(array $a_recipient_ids) 5895 { 5896 global $DIC; 5897 5898 // use mail template 5899 if ($this->getReminderTemplate() && 5900 array_key_exists($this->getReminderTemplate(), $this->getReminderMailTemplates())) { 5901 /** @var \ilMailTemplateService $templateService */ 5902 $templateService = $DIC['mail.texttemplates.service']; 5903 $tmpl = $templateService->loadTemplateForId((int) $this->getReminderTemplate()); 5904 5905 $tmpl_params = array( 5906 "ref_id" => $this->getRefId(), 5907 "ts" => time() 5908 ); 5909 } else { 5910 $tmpl = null; 5911 $link = ilLink::_getStaticLink($this->getRefId(), "svy"); 5912 } 5913 5914 foreach ($a_recipient_ids as $user_id) { 5915 if ($tmpl) { 5916 $subject = $tmpl->getSubject(); 5917 $message = $this->sentReminderPlaceholders($tmpl->getMessage(), $user_id, $tmpl_params); 5918 } 5919 // use lng 5920 else { 5921 // use language of recipient to compose message 5922 $ulng = ilLanguageFactory::_getLanguageOfUser($user_id); 5923 $ulng->loadLanguageModule('survey'); 5924 5925 $subject = sprintf($ulng->txt('survey_reminder_subject'), $this->getTitle()); 5926 $message = sprintf($ulng->txt('survey_reminder_salutation'), ilObjUser::_lookupFullname($user_id)) . "\n\n"; 5927 5928 $message .= $ulng->txt('survey_reminder_body') . ":\n\n"; 5929 $message .= $ulng->txt('obj_svy') . ": " . $this->getTitle() . "\n"; 5930 $message .= "\n" . $ulng->txt('survey_reminder_link') . ": " . $link; 5931 } 5932 5933 $mail_obj = new ilMail(ANONYMOUS_USER_ID); 5934 $mail_obj->appendInstallationSignature(true); 5935 $mail_obj->enqueue( 5936 ilObjUser::_lookupLogin($user_id), 5937 "", 5938 "", 5939 $subject, 5940 $message, 5941 array() 5942 ); 5943 } 5944 } 5945 5946 public function setActivationStartDate($starting_time = null) 5947 { 5948 $this->activation_starting_time = $starting_time; 5949 } 5950 5951 public function setActivationEndDate($ending_time = null) 5952 { 5953 $this->activation_ending_time = $ending_time; 5954 } 5955 5956 public function getActivationStartDate() 5957 { 5958 return (strlen($this->activation_starting_time)) ? $this->activation_starting_time : null; 5959 } 5960 5961 public function getActivationEndDate() 5962 { 5963 return (strlen($this->activation_ending_time)) ? $this->activation_ending_time : null; 5964 } 5965 5966 public function setViewOwnResults($a_value) 5967 { 5968 $this->view_own_results = (bool) $a_value; 5969 } 5970 5971 public function hasViewOwnResults() 5972 { 5973 return $this->view_own_results; 5974 } 5975 5976 public function setMailOwnResults($a_value) 5977 { 5978 $this->mail_own_results = (bool) $a_value; 5979 } 5980 5981 public function hasMailOwnResults() 5982 { 5983 return $this->mail_own_results; 5984 } 5985 5986 public function setMailConfirmation($a_value) 5987 { 5988 $this->mail_confirmation = (bool) $a_value; 5989 } 5990 5991 public function hasMailConfirmation() 5992 { 5993 return $this->mail_confirmation; 5994 } 5995 5996 public function setAnonymousUserList($a_value) 5997 { 5998 $this->anon_user_list = (bool) $a_value; 5999 } 6000 6001 public function hasAnonymousUserList() 6002 { 6003 return $this->anon_user_list; 6004 } 6005 6006 public static function getSurveySkippedValue() 6007 { 6008 global $DIC; 6009 6010 $lng = $DIC->language(); 6011 6012 // #13541 6013 6014 $surveySetting = new ilSetting("survey"); 6015 if (!$surveySetting->get("skipped_is_custom", false)) { 6016 return $lng->txt("skipped"); 6017 } else { 6018 return $surveySetting->get("skipped_custom_value", ""); 6019 } 6020 } 6021 6022 /** 6023 * @param int $defaultTemplateId 6024 * @return array 6025 */ 6026 public function getReminderMailTemplates(&$defaultTemplateId = null) 6027 { 6028 global $DIC; 6029 6030 $res = array(); 6031 6032 /** @var \ilMailTemplateService $templateService */ 6033 $templateService = $DIC['mail.texttemplates.service']; 6034 foreach ($templateService->loadTemplatesForContextId((string) ilSurveyMailTemplateReminderContext::ID) as $tmpl) { 6035 $res[$tmpl->getTplId()] = $tmpl->getTitle(); 6036 if (null !== $defaultTemplateId && $tmpl->isDefault()) { 6037 $defaultTemplateId = $tmpl->getTplId(); 6038 } 6039 } 6040 6041 return $res; 6042 } 6043 6044 protected function sentReminderPlaceholders($a_message, $a_user_id, array $a_context_params) 6045 { 6046 // see ilMail::replacePlaceholders() 6047 try { 6048 $context = \ilMailTemplateContextService::getTemplateContextById(ilSurveyMailTemplateReminderContext::ID); 6049 6050 $user = new \ilObjUser($a_user_id); 6051 6052 $processor = new \ilMailTemplatePlaceholderResolver($context, $a_message); 6053 $a_message = $processor->resolve($user, $a_context_params); 6054 } catch (\Exception $e) { 6055 ilLoggerFactory::getLogger('mail')->error(__METHOD__ . ' has been called with invalid context.'); 6056 } 6057 6058 return $a_message; 6059 } 6060 6061 public function setMode($a_value) 6062 { 6063 $this->mode = $a_value; 6064 } 6065 6066 public function getMode() 6067 { 6068 return $this->mode; 6069 } 6070 6071 public function setSelfEvaluationResults($a_value) 6072 { 6073 $this->mode_self_eval_results = $a_value; 6074 } 6075 6076 public function getSelfEvaluationResults() 6077 { 6078 return $this->mode_self_eval_results; 6079 } 6080 6081 public static function getSurveysWithTutorResults() 6082 { 6083 global $ilDB; 6084 6085 $res = array(); 6086 6087 $log = ilLoggerFactory::getLogger("svy"); 6088 6089 6090 $q = "SELECT obj_fi FROM svy_svy" . 6091 " WHERE tutor_res_cron IS NULL" . 6092 " AND tutor_res_status = " . $ilDB->quote(1, "integer") . 6093 " AND enddate < " . $ilDB->quote(date("Ymd000000"), "text"); 6094 6095 if (DEVMODE) { 6096 $q = "SELECT obj_fi FROM svy_svy" . 6097 " WHERE tutor_res_status = " . $ilDB->quote(1, "integer") . 6098 " AND enddate < " . $ilDB->quote(date("Ymd000000"), "text"); 6099 } 6100 6101 $set = $ilDB->query($q); 6102 6103 $log->debug($q); 6104 6105 while ($row = $ilDB->fetchAssoc($set)) { 6106 $res[] = $row["obj_fi"]; 6107 } 6108 6109 return $res; 6110 } 6111 6112 public function sendTutorResults() 6113 { 6114 global $ilCtrl, $ilDB; 6115 6116 $log = ilLoggerFactory::getLogger("svy"); 6117 6118 include_once "./Services/Mail/classes/class.ilMail.php"; 6119 include_once "./Services/User/classes/class.ilObjUser.php"; 6120 include_once "./Services/Language/classes/class.ilLanguageFactory.php"; 6121 include_once "./Services/User/classes/class.ilUserUtil.php"; 6122 6123 include_once "./Services/Link/classes/class.ilLink.php"; 6124 $link = ilLink::_getStaticLink($this->getRefId(), "svy"); 6125 6126 // somehow needed in cron-calls 6127 //$ilCtrl->setTargetScript("ilias.php"); 6128 //$ilCtrl->initBaseClass("ilobjsurveygui"); 6129 6130 // yeah, I know... 6131 $old_ref_id = $_GET["ref_id"]; 6132 $old_base_class = $_GET["baseClass"]; 6133 $_GET["ref_id"] = $this->getRefId(); 6134 $ilCtrl->setTargetScript("ilias.php"); 6135 $_GET["baseClass"] = "ilObjSurveyGUI"; 6136 6137 $ilCtrl->setParameterByClass("ilSurveyEvaluationGUI", "ref_id", $this->getRefId()); 6138 6139 try { 6140 $gui = new ilSurveyEvaluationGUI($this); 6141 $html = $gui->evaluation(1, true, true); 6142 } catch (Exception $exception) { 6143 $_GET["ref_id"] = $old_ref_id; 6144 $_GET["baseClass"] = $old_base_class; 6145 throw $exception; 6146 } 6147 $_GET["ref_id"] = $old_ref_id; 6148 $_GET["baseClass"] = $old_base_class; 6149 6150 $html = preg_replace("/\?dummy\=[0-9]+/", "", $html); 6151 $html = preg_replace("/\?vers\=[0-9A-Za-z\-]+/", "", $html); 6152 $html = str_replace('.css$Id$', ".css", $html); 6153 $html = preg_replace("/src=\"\\.\\//ims", "src=\"" . ILIAS_HTTP_PATH . "/", $html); 6154 $html = preg_replace("/href=\"\\.\\//ims", "href=\"" . ILIAS_HTTP_PATH . "/", $html); 6155 6156 $pdf_factory = new ilHtmlToPdfTransformerFactory(); 6157 $pdf = $pdf_factory->deliverPDFFromHTMLString($html, "survey.pdf", ilHtmlToPdfTransformerFactory::PDF_OUTPUT_FILE, "Survey", "Results"); 6158 6159 /* 6160 $log->debug("calling phantom for ref_id: " . $this->getRefId()); 6161 6162 $pdf = $gui->callPdfGeneration($url, "pdf", true, true); 6163 6164 $log->debug("phantom called : " . $pdf);*/ 6165 6166 if (!$pdf || 6167 !file_exists($pdf)) { 6168 return false; 6169 } 6170 6171 // prepare mail attachment 6172 require_once 'Services/Mail/classes/class.ilFileDataMail.php'; 6173 $att = "survey_" . $this->getRefId() . ".pdf"; 6174 $mail_data = new ilFileDataMail(ANONYMOUS_USER_ID); 6175 $mail_data->copyAttachmentFile($pdf, $att); 6176 6177 foreach ($this->getTutorResultsRecipients() as $user_id) { 6178 // use language of recipient to compose message 6179 $ulng = ilLanguageFactory::_getLanguageOfUser($user_id); 6180 $ulng->loadLanguageModule('survey'); 6181 6182 $subject = sprintf($ulng->txt('survey_results_tutor_subject'), $this->getTitle()); 6183 $message = sprintf($ulng->txt('survey_notification_tutor_salutation'), ilObjUser::_lookupFullname($user_id)) . "\n\n"; 6184 6185 $message .= $ulng->txt('survey_results_tutor_body') . ":\n\n"; 6186 $message .= $ulng->txt('obj_svy') . ": " . $this->getTitle() . "\n"; 6187 $message .= "\n" . $ulng->txt('survey_notification_tutor_link') . ": " . $link; 6188 6189 $mail_obj = new ilMail(ANONYMOUS_USER_ID); 6190 $mail_obj->appendInstallationSignature(true); 6191 $log->debug("send mail to user id: " . $user_id . ",login: " . ilObjUser::_lookupLogin($user_id)); 6192 $mail_obj->enqueue( 6193 ilObjUser::_lookupLogin($user_id), 6194 "", 6195 "", 6196 $subject, 6197 $message, 6198 array($att) 6199 ); 6200 } 6201 6202 $ilDB->manipulate("UPDATE svy_svy" . 6203 " SET tutor_res_cron = " . $ilDB->quote(1, "integer") . 6204 " WHERE survey_id = " . $ilDB->quote($this->getSurveyId(), "integer")); 6205 6206 return true; 6207 } 6208} // END class.ilObjSurvey 6209