1<?php 2 /* 3 +----------------------------------------------------------------------------+ 4 | ILIAS open source | 5 +----------------------------------------------------------------------------+ 6 | Copyright (c) 1998-2001 ILIAS open source, University of Cologne | 7 | | 8 | This program is free software; you can redistribute it and/or | 9 | modify it under the terms of the GNU General Public License | 10 | as published by the Free Software Foundation; either version 2 | 11 | of the License, or (at your option) any later version. | 12 | | 13 | This program is distributed in the hope that it will be useful, | 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 16 | GNU General Public License for more details. | 17 | | 18 | You should have received a copy of the GNU General Public License | 19 | along with this program; if not, write to the Free Software | 20 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 21 +----------------------------------------------------------------------------+ 22*/ 23 24/** 25* Basic class for all survey question types 26* 27* The SurveyQuestion class defines and encapsulates basic methods and attributes 28* for survey question types to be used for all parent classes. 29* 30* @author Helmut Schottmüller <helmut.schottmueller@mac.com> 31* @version $Id$ 32* @ingroup ModulesSurveyQuestionPool 33*/ 34class SurveyQuestion 35{ 36 /** 37 * @var ilObjUser 38 */ 39 protected $user; 40 41 /** 42 * @var ilDB 43 */ 44 protected $db; 45 46 /** 47 * A unique question id 48 * 49 * @var integer 50 */ 51 public $id; 52 53 /** 54 * A title string to describe the question 55 * 56 * @var string 57 */ 58 public $title; 59 /** 60 * A description string to describe the question more detailed as the title 61 * 62 * @var string 63 */ 64 public $description; 65 /** 66 * A unique positive numerical ID which identifies the owner/creator of the question. 67 * This can be a primary key from a database table for example. 68 * 69 * @var integer 70 */ 71 public $owner; 72 73 /** 74 * A text representation of the authors name. The name of the author must 75 * not necessary be the name of the owner. 76 * 77 * @var string 78 */ 79 public $author; 80 81 /** 82 * Contains uris name and uris to additional materials 83 * 84 * @var array 85 */ 86 public $materials; 87 88 /** 89 * The database id of a survey in which the question is contained 90 * 91 * @var integer 92 */ 93 public $survey_id; 94 95 /** 96 * Object id of the container object 97 * 98 * @var double 99 */ 100 public $obj_id; 101 102 /** 103 * Questiontext string 104 * 105 * @var string 106 */ 107 public $questiontext; 108 109 /** 110 * Contains the obligatory state of the question 111 * 112 * @var boolean 113 */ 114 public $obligatory; 115 116 /** 117 * The reference to the Language class 118 * 119 * @var object 120 */ 121 public $lng; 122 123 /** 124 * The orientation of the question output (0 = vertical, 1 = horizontal) 125 * 126 * @var integer 127 */ 128 public $orientation; 129 130 public $material; 131 public $complete; 132 133 /** 134 * An array containing the cumulated results of the question for a given survey 135 */ 136 protected $cumulated; 137 138 /** 139 * data array containing the question data 140 */ 141 private $arrData; 142 143 /** 144 * @var ilLogger 145 */ 146 protected $log; 147 148 /** 149 * SurveyQuestion constructor 150 * The constructor takes possible arguments an creates an instance of the SurveyQuestion object. 151 * 152 * @param string $title A title string to describe the question 153 * @param string $description A description string to describe the question 154 * @param string $author A string containing the name of the questions author 155 * @param integer $owner A numerical ID to identify the owner/creator 156 * @access public 157 */ 158 public function __construct($title = "", $description = "", $author = "", $questiontext = "", $owner = -1) 159 { 160 global $DIC; 161 162 $this->user = $DIC->user(); 163 $this->db = $DIC->database(); 164 $lng = $DIC->language(); 165 $ilUser = $DIC->user(); 166 167 $this->lng = $lng; 168 $this->complete = 0; 169 $this->title = $title; 170 $this->description = $description; 171 $this->questiontext = $questiontext; 172 $this->author = $author; 173 $this->cumulated = array(); 174 if (!$this->author) { 175 $this->author = $ilUser->fullname; 176 } 177 $this->owner = $owner; 178 if ($this->owner == -1) { 179 $this->owner = $ilUser->getId(); 180 } 181 $this->id = -1; 182 $this->survey_id = -1; 183 $this->obligatory = 1; 184 $this->orientation = 0; 185 $this->materials = array(); 186 $this->material = array(); 187 $this->arrData = array(); 188 189 $this->log = ilLoggerFactory::getLogger('svy'); 190 } 191 192 /** 193 * Sets the complete state of the question 194 * 195 * @param integer $a_complete 1 if complete, 0 otherwise 196 * @access public 197 */ 198 public function setComplete($a_complete) 199 { 200 $this->complete = ($a_complete) ? 1 : 0; 201 } 202 203 /** 204 * Returns 1, if a question is complete for use 205 * 206 * @return integer 1, if the question is complete for use, otherwise 0 207 * @access public 208 */ 209 public function isComplete() 210 { 211 return 0; 212 } 213 214 /** 215 * Returns TRUE if the question title exists in the database 216 * 217 * @param string $title The title of the question 218 * @param string $questionpool_reference The reference id of a container question pool 219 * @return boolean The result of the title check 220 * @access public 221 */ 222 public function questionTitleExists($title, $questionpool_object = "") 223 { 224 $ilDB = $this->db; 225 226 $refwhere = ""; 227 if (strcmp($questionpool_object, "") != 0) { 228 $refwhere = sprintf( 229 " AND obj_fi = %s", 230 $ilDB->quote($questionpool_object, 'integer') 231 ); 232 } 233 $result = $ilDB->queryF( 234 "SELECT question_id FROM svy_question WHERE title = %s$refwhere", 235 array('text'), 236 array($title) 237 ); 238 return ($result->numRows() > 0) ? true : false; 239 } 240 241 /** 242 * Sets the title string of the SurveyQuestion object 243 * 244 * @param string $title A title string to describe the question 245 * @access public 246 * @see $title 247 */ 248 public function setTitle($title = "") 249 { 250 $this->title = $title; 251 } 252 253 /** 254 * Sets the obligatory state of the question 255 * 256 * @param integer $obligatory 1, if the question is obligatory, otherwise 0 257 * @access public 258 * @see $obligatory 259 */ 260 public function setObligatory($obligatory = 1) 261 { 262 $this->obligatory = ($obligatory) ? 1 : 0; 263 } 264 265 /** 266 * Sets the orientation of the question output 267 * 268 * @param integer $orientation 0 = vertical, 1 = horizontal 269 * @access public 270 * @see $orientation 271 */ 272 public function setOrientation($orientation = 0) 273 { 274 $this->orientation = ($orientation) ? $orientation : 0; 275 } 276 277 /** 278 * Sets the id of the SurveyQuestion object 279 * 280 * @param integer $id A unique integer value 281 * @access public 282 * @see $id 283 */ 284 public function setId($id = -1) 285 { 286 $this->id = $id; 287 } 288 289 /** 290 * Sets the survey id of the SurveyQuestion object 291 * 292 * @param integer $id A unique integer value 293 * @access public 294 * @see $survey_id 295 */ 296 public function setSurveyId($id = -1) 297 { 298 $this->survey_id = $id; 299 } 300 301 /** 302 * Sets the description string of the SurveyQuestion object 303 * 304 * @param string $description A description string to describe the question 305 * @access public 306 * @see $description 307 */ 308 public function setDescription($description = "") 309 { 310 $this->description = $description; 311 } 312 313 /** 314 * Sets the materials uri 315 * 316 * @param string $materials_file An uri to additional materials 317 * @param string $materials_name An uri name to additional materials 318 * @access public 319 * @see $materials 320 */ 321 public function addMaterials($materials_file, $materials_name = "") 322 { 323 if (empty($materials_name)) { 324 $materials_name = $materials_file; 325 } 326 if ((!empty($materials_name)) && (!array_key_exists($materials_name, $this->materials))) { 327 $this->materials[$materials_name] = $materials_file; 328 } 329 } 330 331 /** 332 * Sets and uploads the materials uri 333 * 334 * @param string $materials_filename, string $materials_tempfilename, string $materials 335 * @access public 336 * @see $materials 337 */ 338 public function setMaterialsfile($materials_filename, $materials_tempfilename = "", $materials_name = "") 339 { 340 if (!empty($materials_filename)) { 341 $materialspath = $this->getMaterialsPath(); 342 if (!file_exists($materialspath)) { 343 ilUtil::makeDirParents($materialspath); 344 } 345 if (ilUtil::moveUploadedFile( 346 $materials_tempfilename, 347 $materials_filename, 348 $materialspath . $materials_filename 349 )) { 350 print "image not uploaded!!!! "; 351 } else { 352 $this->addMaterials($materials_filename, $materials_name); 353 } 354 } 355 } 356 357 /** 358 * Deletes a materials uri with a given name. 359 * 360 * @param string $index A materials_name of the materials uri 361 * @access public 362 * @see $materials 363 */ 364 public function deleteMaterial($materials_name = "") 365 { 366 foreach ($this->materials as $key => $value) { 367 if (strcmp($key, $materials_name) == 0) { 368 if (file_exists($this->getMaterialsPath() . $value)) { 369 unlink($this->getMaterialsPath() . $value); 370 } 371 unset($this->materials[$key]); 372 } 373 } 374 } 375 376 /** 377 * Deletes all materials uris 378 * 379 * @access public 380 * @see $materials 381 */ 382 public function flushMaterials() 383 { 384 $this->materials = array(); 385 } 386 387 /** 388 * Sets the authors name of the SurveyQuestion object 389 * 390 * @param string $author A string containing the name of the questions author 391 * @access public 392 * @see $author 393 */ 394 public function setAuthor($author = "") 395 { 396 $ilUser = $this->user; 397 398 if (!$author) { 399 $author = $ilUser->fullname; 400 } 401 $this->author = $author; 402 } 403 404 /** 405 * Sets the questiontext of the SurveyQuestion object 406 * 407 * @param string $questiontext A string containing the questiontext 408 * @access public 409 * @see $questiontext 410 */ 411 public function setQuestiontext($questiontext = "") 412 { 413 $this->questiontext = $questiontext; 414 } 415 416 /** 417 * Sets the creator/owner ID of the SurveyQuestion object 418 * 419 * @param integer $owner A numerical ID to identify the owner/creator 420 * @access public 421 * @see $owner 422 */ 423 public function setOwner($owner = "") 424 { 425 $this->owner = $owner; 426 } 427 428 /** 429 * Gets the title string of the SurveyQuestion object 430 * 431 * @return string The title string to describe the question 432 * @access public 433 * @see $title 434 */ 435 public function getTitle() 436 { 437 return $this->title; 438 } 439 440 public function getLabel() 441 { 442 return $this->label; 443 } 444 445 /** 446 * Gets the id of the SurveyQuestion object 447 * 448 * @return integer The id of the SurveyQuestion object 449 * @access public 450 * @see $id 451 */ 452 public function getId() 453 { 454 return $this->id; 455 } 456 457 /** 458 * Gets the obligatory state of the question 459 * 460 * @return integer 1, if the question is obligatory, otherwise 0 461 * @see $obligatory 462 */ 463 public function getObligatory($survey_id = "") 464 { 465 return ($this->obligatory) ? 1 : 0; 466 } 467 468 /** 469 * Gets the survey id of the SurveyQuestion object 470 * 471 * @return integer The survey id of the SurveyQuestion object 472 * @access public 473 * @see $survey_id 474 */ 475 public function getSurveyId() 476 { 477 return $this->survey_id; 478 } 479 480 /** 481 * Gets the orientation of the question output 482 * 483 * @return integer 0 = vertical, 1 = horizontal 484 * @access public 485 * @see $orientation 486 */ 487 public function getOrientation() 488 { 489 switch ($this->orientation) { 490 case 0: 491 case 1: 492 case 2: 493 break; 494 default: 495 $this->orientation = 0; 496 break; 497 } 498 return $this->orientation; 499 } 500 501 502 /** 503 * Gets the description string of the SurveyQuestion object 504 * 505 * @return string The description string to describe the question 506 * @access public 507 * @see $description 508 */ 509 public function getDescription() 510 { 511 return (strlen($this->description)) ? $this->description : null; 512 } 513 514 /** 515 * Gets the authors name of the SurveyQuestion object 516 * 517 * @return string The string containing the name of the questions author 518 * @access public 519 * @see $author 520 */ 521 public function getAuthor() 522 { 523 return (strlen($this->author)) ? $this->author : null; 524 } 525 526 /** 527 * Gets the creator/owner ID of the SurveyQuestion object 528 * 529 * @return integer The numerical ID to identify the owner/creator 530 * @access public 531 * @see $owner 532 */ 533 public function getOwner() 534 { 535 return $this->owner; 536 } 537 538 /** 539 * Gets the questiontext of the SurveyQuestion object 540 * 541 * @return string The questiontext of the question object 542 * @access public 543 * @see $questiontext 544 */ 545 public function getQuestiontext() 546 { 547 return (strlen($this->questiontext)) ? $this->questiontext : null; 548 } 549 550 /** 551 * Get the reference id of the container object 552 * 553 * @return integer The reference id of the container object 554 * @access public 555 * @see $obj_id 556 */ 557 public function getObjId() 558 { 559 return $this->obj_id; 560 } 561 562 /** 563 * Set the reference id of the container object 564 * 565 * @param integer $obj_id The reference id of the container object 566 * @access public 567 * @see $obj_id 568 */ 569 public function setObjId($obj_id = 0) 570 { 571 $this->obj_id = $obj_id; 572 } 573 574 /** 575 * Duplicates a survey question 576 * 577 * @access public 578 */ 579 public function duplicate($for_survey = true, $title = "", $author = "", $owner = "", $a_survey_id = 0) 580 { 581 if ($this->getId() <= 0) { 582 // The question has not been saved. It cannot be duplicated 583 return; 584 } 585 // duplicate the question in database 586 $clone = $this; 587 $original_id = $this->getId(); 588 $clone->setId(-1); 589 if ($a_survey_id > 0) { 590 $clone->setObjId($a_survey_id); 591 } 592 if ($title) { 593 $clone->setTitle($title); 594 } 595 if ($author) { 596 $clone->setAuthor($author); 597 } 598 if ($owner) { 599 $clone->setOwner($owner); 600 } 601 if ($for_survey) { 602 $clone->saveToDb($original_id); 603 } else { 604 $clone->saveToDb(); 605 } 606 // duplicate the materials 607 $clone->duplicateMaterials($original_id); 608 // copy XHTML media objects 609 $clone->copyXHTMLMediaObjectsOfQuestion($original_id); 610 return $clone->getId(); 611 } 612 613 /** 614 * Copies an assOrderingQuestion object 615 * 616 * @access public 617 */ 618 public function copyObject($target_questionpool, $title = "") 619 { 620 if ($this->getId() <= 0) { 621 // The question has not been saved. It cannot be copied 622 return; 623 } 624 $clone = $this; 625 $original_id = self::_getOriginalId($this->getId(), false); 626 $clone->setId(-1); 627 $source_questionpool = $this->getObjId(); 628 $clone->setObjId($target_questionpool); 629 if ($title) { 630 $clone->setTitle($title); 631 } 632 633 $clone->saveToDb(); 634 635 // duplicate the materials 636 $clone->duplicateMaterials($original_id); 637 // copy XHTML media objects 638 $clone->copyXHTMLMediaObjectsOfQuestion($original_id); 639 return $clone->getId(); 640 } 641 642 /** 643 * Increases the media object usage counter when a question is duplicated 644 * 645 * @param integer $a_q_id The question id of the original question 646 * @access public 647 */ 648 public function copyXHTMLMediaObjectsOfQuestion($a_q_id) 649 { 650 include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php"); 651 $mobs = ilObjMediaObject::_getMobsOfObject("spl:html", $a_q_id); 652 foreach ($mobs as $mob) { 653 ilObjMediaObject::_saveUsage($mob, "spl:html", $this->getId()); 654 } 655 } 656 657 /** 658 * Loads a SurveyQuestion object from the database 659 * 660 * @param integer $question_id A unique key which defines the question in the database 661 * @access public 662 */ 663 public function loadFromDb($question_id) 664 { 665 $ilDB = $this->db; 666 667 $result = $ilDB->queryF( 668 "SELECT * FROM svy_material WHERE question_fi = %s", 669 array('integer'), 670 array($this->getId()) 671 ); 672 $this->material = array(); 673 if ($result->numRows()) { 674 include_once "./Modules/SurveyQuestionPool/classes/class.ilSurveyMaterial.php"; 675 while ($row = $ilDB->fetchAssoc($result)) { 676 $mat = new ilSurveyMaterial(); 677 $mat->type = $row['material_type']; 678 $mat->internal_link = $row['internal_link']; 679 $mat->title = $row['material_title']; 680 $mat->import_id = $row['import_id']; 681 $mat->text_material = $row['text_material']; 682 $mat->external_link = $row['external_link']; 683 $mat->file_material = $row['file_material']; 684 array_push($this->material, $mat); 685 } 686 } 687 } 688 689 /** 690 * Checks whether the question is complete or not 691 * 692 * @return boolean TRUE if the question is complete, FALSE otherwise 693 * @access public 694 */ 695 public static function _isComplete($question_id) 696 { 697 global $DIC; 698 699 $ilDB = $DIC->database(); 700 701 $result = $ilDB->queryF( 702 "SELECT complete FROM svy_question WHERE question_id = %s", 703 array('integer'), 704 array($question_id) 705 ); 706 if ($result->numRows()) { 707 $row = $ilDB->fetchAssoc($result); 708 if ($row["complete"] == 1) { 709 return true; 710 } 711 } 712 return false; 713 } 714 715 /** 716 * Saves the complete flag to the database 717 * 718 * @access public 719 */ 720 public function saveCompletionStatus($original_id = "") 721 { 722 $ilDB = $this->db; 723 724 $question_id = $this->getId(); 725 if (strlen($original_id)) { 726 $question_id = $original_id; 727 } 728 729 if ($this->getId() > 0) { 730 $this->log->debug("UPDATE svy_question question_id=" . $question_id); 731 732 // update existing dataset 733 $affectedRows = $ilDB->manipulateF( 734 "UPDATE svy_question SET complete = %s, tstamp = %s WHERE question_id = %s", 735 array('text', 'integer', 'integer'), 736 array($this->isComplete(), time(), $question_id) 737 ); 738 } 739 } 740 741 /** 742 * Saves a SurveyQuestion object to a database 743 * 744 * @param integer $original_id 745 * @access public 746 */ 747 public function saveToDb($original_id = "") 748 { 749 $ilDB = $this->db; 750 751 // cleanup RTE images which are not inserted into the question text 752 include_once("./Services/RTE/classes/class.ilRTE.php"); 753 ilRTE::_cleanupMediaObjectUsage($this->getQuestiontext(), "spl:html", $this->getId()); 754 $affectedRows = 0; 755 if ($this->getId() == -1) { 756 // Write new dataset 757 $next_id = $ilDB->nextId('svy_question'); 758 $affectedRows = $ilDB->insert("svy_question", array( 759 "question_id" => array("integer", $next_id), 760 "questiontype_fi" => array("integer", $this->getQuestionTypeID()), 761 "obj_fi" => array("integer", $this->getObjId()), 762 "owner_fi" => array("integer", $this->getOwner()), 763 "title" => array("text", $this->getTitle()), 764 "label" => array("text", (strlen($this->label)) ? $this->label : null), 765 "description" => array("text", $this->getDescription()), 766 "author" => array("text", $this->getAuthor()), 767 "questiontext" => array("clob", ilRTE::_replaceMediaObjectImageSrc($this->getQuestiontext(), 0)), 768 "obligatory" => array("text", $this->getObligatory()), 769 "complete" => array("text", $this->isComplete()), 770 "created" => array("integer", time()), 771 "original_id" => array("integer", ($original_id) ? $original_id : null), 772 "tstamp" => array("integer", time()) 773 )); 774 775 //$this->log->debug("INSERT: svy_question id=".$next_id." questiontype_fi=".$this->getQuestionTypeID()." obj_fi".$this->getObjId()." title=".$this->getTitle()." ..."); 776 777 $this->setId($next_id); 778 } else { 779 // update existing dataset 780 $affectedRows = $ilDB->update("svy_question", array( 781 "title" => array("text", $this->getTitle()), 782 "label" => array("text", (strlen($this->label)) ? $this->label : null), 783 "description" => array("text", $this->getDescription()), 784 "author" => array("text", $this->getAuthor()), 785 "questiontext" => array("clob", ilRTE::_replaceMediaObjectImageSrc($this->getQuestiontext(), 0)), 786 "obligatory" => array("text", $this->getObligatory()), 787 "complete" => array("text", $this->isComplete()), 788 "tstamp" => array("integer", time()) 789 ), array( 790 "question_id" => array("integer", $this->getId()) 791 )); 792 793 $this->log->debug("UPDATE svy_question id=" . $this->getId() . " SET: title=" . $this->getTitle() . " ..."); 794 } 795 796 return $affectedRows; 797 } 798 799 /** 800 * save material to db 801 */ 802 public function saveMaterial() 803 { 804 $ilDB = $this->db; 805 806 include_once "./Services/Link/classes/class.ilInternalLink.php"; 807 808 $this->log->debug("DELETE: svy_material question_fi=" . $this->getId()); 809 810 $affectedRows = $ilDB->manipulateF( 811 "DELETE FROM svy_material WHERE question_fi = %s", 812 array('integer'), 813 array($this->getId()) 814 ); 815 ilInternalLink::_deleteAllLinksOfSource("sqst", $this->getId()); 816 817 foreach ($this->material as $material) { 818 $next_id = $ilDB->nextId('svy_material'); 819 820 $this->log->debug("INSERT: svy_material question_fi=" . $this->getId()); 821 822 $affectedRows = $ilDB->manipulateF( 823 "INSERT INTO svy_material " . 824 "(material_id, question_fi, internal_link, import_id, material_title, tstamp," . 825 "text_material, external_link, file_material, material_type) " . 826 "VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)", 827 array('integer','integer','text','text','text','integer','text','text','text','integer'), 828 array( 829 $next_id, $this->getId(), $material->internal_link, $material->import_id, 830 $material->title, time(), $material->text_material, $material->external_link, 831 $material->file_material, $material->type) 832 ); 833 if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $material->internal_link, $matches)) { 834 ilInternalLink::_saveLink("sqst", $this->getId(), $matches[2], $matches[3], $matches[1]); 835 } 836 } 837 } 838 839 /** 840 * Creates a new question with a 0 timestamp when a new question is created 841 * This assures that an ID is given to the question if a file upload or something else occurs 842 * 843 * @return integer ID of the new question 844 */ 845 public function createNewQuestion() 846 { 847 $ilDB = $this->db; 848 849 $obj_id = $this->getObjId(); 850 if ($obj_id > 0) { 851 $next_id = $ilDB->nextId('svy_question'); 852 $affectedRows = $ilDB->manipulateF( 853 "INSERT INTO svy_question (question_id, questiontype_fi, " . 854 "obj_fi, owner_fi, title, description, author, questiontext, obligatory, complete, " . 855 "created, original_id, tstamp) VALUES " . 856 "(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)", 857 array('integer', 'integer', 'integer', 'integer', 'text', 'text', 'text', 'text', 858 'text', 'text', 'integer', 'integer', 'integer'), 859 array( 860 $next_id, 861 $this->getQuestionTypeID(), 862 $obj_id, 863 $this->getOwner(), 864 null, 865 null, 866 $this->getAuthor(), 867 null, 868 "1", 869 "0", 870 time(), 871 null, 872 0 873 ) 874 ); 875 $this->log->debug("INSERT INTO svy_question question_id= " . $next_id . " questiontype_fi= " . $this->getQuestionTypeID()); 876 877 $this->setId($next_id); 878 } 879 return $this->getId(); 880 } 881 882 /** 883 * Saves the learners input of the question to the database 884 * 885 * @access public 886 * @see $answers 887 */ 888 public function saveWorkingData($limit_to = LIMIT_NO_LIMIT) 889 { 890 } 891 892 /** 893 * Returns the image path for web accessable images of a question. 894 * The image path is under the CLIENT_WEB_DIR in assessment/REFERENCE_ID_OF_QUESTION_POOL/ID_OF_QUESTION/images 895 * 896 * @access public 897 */ 898 public function getImagePath() 899 { 900 return CLIENT_WEB_DIR . "/survey/$this->obj_id/$this->id/images/"; 901 } 902 903 /** 904 * Returns the materials path for web accessable materials of a question. 905 * The materials path is under the CLIENT_WEB_DIR in assessment/REFERENCE_ID_OF_QUESTION_POOL/ID_OF_QUESTION/materials 906 * 907 * @access public 908 */ 909 public function getMaterialsPath() 910 { 911 return CLIENT_WEB_DIR . "/survey/$this->obj_id/$this->id/materials/"; 912 } 913 914 /** 915 * Returns the web image path for web accessable images of a question. 916 * The image path is under the web accessable data dir in assessment/REFERENCE_ID_OF_QUESTION_POOL/ID_OF_QUESTION/images 917 * 918 * @access public 919 */ 920 public function getImagePathWeb() 921 { 922 $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/survey/$this->obj_id/$this->id/images/"; 923 return str_replace(ilUtil::removeTrailingPathSeparators(ILIAS_ABSOLUTE_PATH), ilUtil::removeTrailingPathSeparators(ILIAS_HTTP_PATH), $webdir); 924 } 925 926 /** 927 * Returns the web image path for web accessable images of a question. 928 * The image path is under the web accessable data dir in assessment/REFERENCE_ID_OF_QUESTION_POOL/ID_OF_QUESTION/images 929 * 930 * @access public 931 */ 932 public function getMaterialsPathWeb() 933 { 934 $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/survey/$this->obj_id/$this->id/materials/"; 935 return str_replace(ilUtil::removeTrailingPathSeparators(ILIAS_ABSOLUTE_PATH), ilUtil::removeTrailingPathSeparators(ILIAS_HTTP_PATH), $webdir); 936 } 937 938 /** 939 * Saves a category to the database 940 * 941 * @param string $categorytext The description of the category 942 * @result integer The database id of the category 943 * @access public 944 * @see $categories 945 */ 946 public function saveCategoryToDb($categorytext, $neutral = 0) 947 { 948 $ilUser = $this->user; 949 $ilDB = $this->db; 950 951 $result = $ilDB->queryF( 952 "SELECT title, category_id FROM svy_category WHERE title = %s AND neutral = %s AND owner_fi = %s", 953 array('text','text','integer'), 954 array($categorytext, $neutral, $ilUser->getId()) 955 ); 956 $insert = false; 957 $returnvalue = ""; 958 if ($result->numRows()) { 959 $insert = true; 960 while ($row = $ilDB->fetchAssoc($result)) { 961 if (strcmp($row["title"], $categorytext) == 0) { 962 $returnvalue = $row["category_id"]; 963 $insert = false; 964 } 965 } 966 } else { 967 $insert = true; 968 } 969 if ($insert) { 970 $next_id = $ilDB->nextId('svy_category'); 971 $affectedRows = $ilDB->manipulateF( 972 "INSERT INTO svy_category (category_id, title, neutral, owner_fi, tstamp) VALUES (%s, %s, %s, %s, %s)", 973 array('integer','text','text','integer','integer'), 974 array($next_id, $categorytext, $neutral, $ilUser->getId(), time()) 975 ); 976 977 $this->log->debug("INSERT INTO svy_category id=" . $next_id); 978 979 $returnvalue = $next_id; 980 } 981 return $returnvalue; 982 } 983 984 /** 985 * Deletes datasets from the additional question table in the database 986 * 987 * @param integer $question_id The question id which should be deleted in the additional question table 988 * @access public 989 */ 990 public function deleteAdditionalTableData($question_id) 991 { 992 $ilDB = $this->db; 993 994 $this->log->debug("DELETE FROM " . $this->getAdditionalTableName()); 995 996 $affectedRows = $ilDB->manipulateF( 997 "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s", 998 array('integer'), 999 array($question_id) 1000 ); 1001 } 1002 1003 /** 1004 * Deletes a question and all materials from the database 1005 * 1006 * @param integer $question_id The database id of the question 1007 * @access private 1008 */ 1009 public function delete($question_id) 1010 { 1011 $ilDB = $this->db; 1012 1013 if ($question_id < 1) { 1014 return; 1015 } 1016 1017 $result = $ilDB->queryF( 1018 "SELECT obj_fi FROM svy_question WHERE question_id = %s", 1019 array('integer'), 1020 array($question_id) 1021 ); 1022 if ($result->numRows() == 1) { 1023 $row = $ilDB->fetchAssoc($result); 1024 $obj_id = $row["obj_fi"]; 1025 } else { 1026 return; 1027 } 1028 1029 $affectedRows = $ilDB->manipulateF( 1030 "DELETE FROM svy_answer WHERE question_fi = %s", 1031 array('integer'), 1032 array($question_id) 1033 ); 1034 1035 $affectedRows = $ilDB->manipulateF( 1036 "DELETE FROM svy_constraint WHERE question_fi = %s", 1037 array('integer'), 1038 array($question_id) 1039 ); 1040 1041 $result = $ilDB->queryF( 1042 "SELECT constraint_fi FROM svy_qst_constraint WHERE question_fi = %s", 1043 array('integer'), 1044 array($question_id) 1045 ); 1046 while ($row = $ilDB->fetchObject($result)) { 1047 $affectedRows = $ilDB->manipulateF( 1048 "DELETE FROM svy_constraint WHERE constraint_id = %s", 1049 array('integer'), 1050 array($row->constraint_fi) 1051 ); 1052 } 1053 1054 $affectedRows = $ilDB->manipulateF( 1055 "DELETE FROM svy_qst_constraint WHERE question_fi = %s", 1056 array('integer'), 1057 array($question_id) 1058 ); 1059 $affectedRows = $ilDB->manipulateF( 1060 "DELETE FROM svy_qblk_qst WHERE question_fi = %s", 1061 array('integer'), 1062 array($question_id) 1063 ); 1064 $affectedRows = $ilDB->manipulateF( 1065 "DELETE FROM svy_svy_qst WHERE question_fi = %s", 1066 array('integer'), 1067 array($question_id) 1068 ); 1069 $affectedRows = $ilDB->manipulateF( 1070 "DELETE FROM svy_variable WHERE question_fi = %s", 1071 array('integer'), 1072 array($question_id) 1073 ); 1074 $affectedRows = $ilDB->manipulateF( 1075 "DELETE FROM svy_question WHERE question_id = %s", 1076 array('integer'), 1077 array($question_id) 1078 ); 1079 1080 $this->deleteAdditionalTableData($question_id); 1081 1082 $affectedRows = $ilDB->manipulateF( 1083 "DELETE FROM svy_material WHERE question_fi = %s", 1084 array('integer'), 1085 array($question_id) 1086 ); 1087 1088 $this->log->debug("SET OF DELETES svy_answer, svy_constraint, svy_qst_constraint, svy_qblk_qst, svy_qst_oblig, svy_svy_qst, svy_variable, svy_question, svy_material WHERE question_fi = " . $question_id); 1089 1090 include_once "./Services/Link/classes/class.ilInternalLink.php"; 1091 ilInternalLink::_deleteAllLinksOfSource("sqst", $question_id); 1092 1093 $directory = CLIENT_WEB_DIR . "/survey/" . $obj_id . "/$question_id"; 1094 if (preg_match("/\d+/", $obj_id) and preg_match("/\d+/", $question_id) and is_dir($directory)) { 1095 ilUtil::delDir($directory); 1096 } 1097 1098 include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php"); 1099 $mobs = ilObjMediaObject::_getMobsOfObject("spl:html", $question_id); 1100 // remaining usages are not in text anymore -> delete them 1101 // and media objects (note: delete method of ilObjMediaObject 1102 // checks whether object is used in another context; if yes, 1103 // the object is not deleted!) 1104 foreach ($mobs as $mob) { 1105 ilObjMediaObject::_removeUsage($mob, "spl:html", $question_id); 1106 $mob_obj = new ilObjMediaObject($mob); 1107 $mob_obj->delete(); 1108 } 1109 1110 include_once("./Modules/Survey/classes/class.ilSurveySkill.php"); 1111 ilSurveySkill::handleQuestionDeletion($question_id, $obj_id); 1112 1113 $this->log->debug("UPDATE svy_question"); 1114 1115 // #12772 - untie question copies from pool question 1116 $ilDB->manipulate("UPDATE svy_question" . 1117 " SET original_id = NULL" . 1118 " WHERE original_id = " . $ilDB->quote($question_id, "integer")); 1119 } 1120 1121 /** 1122 * Returns the question type of a question with a given id 1123 * 1124 * @param integer $question_id The database id of the question 1125 * @result string The question type string 1126 * @access private 1127 */ 1128 public static function _getQuestionType($question_id) 1129 { 1130 global $DIC; 1131 1132 $ilDB = $DIC->database(); 1133 1134 if ($question_id < 1) { 1135 return ""; 1136 } 1137 1138 $result = $ilDB->queryF( 1139 "SELECT type_tag FROM svy_question, svy_qtype WHERE svy_question.question_id = %s AND svy_question.questiontype_fi = svy_qtype.questiontype_id", 1140 array('integer'), 1141 array($question_id) 1142 ); 1143 if ($result->numRows() == 1) { 1144 $data = $ilDB->fetchAssoc($result); 1145 return $data["type_tag"]; 1146 } else { 1147 return ""; 1148 } 1149 } 1150 1151 /** 1152 * Returns the question title of a question with a given id 1153 * 1154 * @param integer $question_id The database id of the question 1155 * @result string The question title 1156 * @access private 1157 */ 1158 public static function _getTitle($question_id) 1159 { 1160 global $DIC; 1161 1162 $ilDB = $DIC->database(); 1163 1164 if ($question_id < 1) { 1165 return ""; 1166 } 1167 1168 $result = $ilDB->queryF( 1169 "SELECT title FROM svy_question WHERE svy_question.question_id = %s", 1170 array('integer'), 1171 array($question_id) 1172 ); 1173 if ($result->numRows() == 1) { 1174 $data = $ilDB->fetchAssoc($result); 1175 return $data["title"]; 1176 } else { 1177 return ""; 1178 } 1179 } 1180 1181 /** 1182 * Returns the original id of a question 1183 * 1184 * @param integer $question_id The database id of the question 1185 * @return integer The database id of the original question 1186 * @access public 1187 */ 1188 public static function _getOriginalId($question_id, $a_return_question_id_if_no_original = true) 1189 { 1190 global $DIC; 1191 1192 $ilDB = $DIC->database(); 1193 $result = $ilDB->queryF( 1194 "SELECT * FROM svy_question WHERE question_id = %s", 1195 array('integer'), 1196 array($question_id) 1197 ); 1198 if ($result->numRows() > 0) { 1199 $row = $ilDB->fetchAssoc($result); 1200 if ($row["original_id"] > 0) { 1201 return $row["original_id"]; 1202 } elseif ((bool) $a_return_question_id_if_no_original) { // #12419 1203 return $row["question_id"]; 1204 } 1205 } else { 1206 return ""; 1207 } 1208 } 1209 1210 public function syncWithOriginal() 1211 { 1212 $ilDB = $this->db; 1213 1214 if ($this->getOriginalId()) { 1215 $id = $this->getId(); 1216 $original = $this->getOriginalId(); 1217 1218 $this->setId($this->getOriginalId()); 1219 $this->setOriginalId(null); 1220 $this->saveToDb(); 1221 1222 $this->setId($id); 1223 $this->setOriginalId($original); 1224 1225 $this->log->debug("DELETE FROM svy_material WHERE question_fi = " . $this->getOriginalId()); 1226 1227 include_once "./Services/Link/classes/class.ilInternalLink.php"; 1228 $affectedRows = $ilDB->manipulateF( 1229 "DELETE FROM svy_material WHERE question_fi = %s", 1230 array('integer'), 1231 array($this->getOriginalId()) 1232 ); 1233 ilInternalLink::_deleteAllLinksOfSource("sqst", $this->original_id); 1234 if (strlen($this->material["internal_link"])) { 1235 $next_id = $ilDB->nextId('svy_material'); 1236 $affectedRows = $ilDB->manipulateF( 1237 "INSERT INTO svy_material (material_id, question_fi, internal_link, import_id, material_title, tstamp) VALUES (%s, %s, %s, %s, %s, %s)", 1238 array('integer', 'integer', 'text', 'text', 'text', 'integer'), 1239 array($next_id, $this->getOriginalId(), $this->material["internal_link"], $this->material["import_id"], $this->material["title"], time()) 1240 ); 1241 1242 $this->log->debug("INSERT svy_material material_id=" . $next_id . " question_fi=" . $this->getOriginalId()); 1243 1244 if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $this->material["internal_link"], $matches)) { 1245 ilInternalLink::_saveLink("sqst", $this->getOriginalId(), $matches[2], $matches[3], $matches[1]); 1246 } 1247 } 1248 } 1249 } 1250 1251 /** 1252 * Returns a phrase for a given database id 1253 * 1254 * @result String The title of the phrase 1255 * @access public 1256 */ 1257 public function getPhrase($phrase_id) 1258 { 1259 $ilDB = $this->db; 1260 1261 $result = $ilDB->queryF( 1262 "SELECT title FROM svy_phrase WHERE phrase_id = %s", 1263 array('integer'), 1264 array($phrase_id) 1265 ); 1266 if ($row = $ilDB->fetchAssoc($result)) { 1267 return $row["title"]; 1268 } 1269 return ""; 1270 } 1271 1272 /** 1273 * Returns true if the phrase title already exists for the current user 1274 * 1275 * @param string $title The title of the phrase 1276 * @result boolean True, if the title exists, otherwise False 1277 * @access public 1278 */ 1279 public function phraseExists($title) 1280 { 1281 $ilUser = $this->user; 1282 $ilDB = $this->db; 1283 1284 $result = $ilDB->queryF( 1285 "SELECT phrase_id FROM svy_phrase WHERE title = %s AND owner_fi = %s", 1286 array('text', 'integer'), 1287 array($title, $ilUser->getId()) 1288 ); 1289 return ($result->numRows() == 0) ? false : true; 1290 } 1291 1292 /** 1293 * Returns true if the question already exists in the database 1294 * 1295 * @param integer $question_id The database id of the question 1296 * @result boolean True, if the question exists, otherwise False 1297 * @access public 1298 */ 1299 public static function _questionExists($question_id) 1300 { 1301 global $DIC; 1302 1303 $ilDB = $DIC->database(); 1304 1305 if ($question_id < 1) { 1306 return false; 1307 } 1308 1309 $result = $ilDB->queryF( 1310 "SELECT question_id FROM svy_question WHERE question_id = %s", 1311 array('integer'), 1312 array($question_id) 1313 ); 1314 return ($result->numRows() == 1) ? true : false; 1315 } 1316 1317 public function addInternalLink($material_id, $title = "") 1318 { 1319 if (strlen($material_id)) { 1320 if (strcmp($material_title, "") == 0) { 1321 if (preg_match("/il__(\w+)_(\d+)/", $material_id, $matches)) { 1322 $type = $matches[1]; 1323 $target_id = $matches[2]; 1324 $material_title = $this->lng->txt("obj_$type") . ": "; 1325 switch ($type) { 1326 case "lm": 1327 include_once("./Modules/LearningModule/classes/class.ilObjContentObjectGUI.php"); 1328 $cont_obj_gui = new ilObjContentObjectGUI("", $target_id, true); 1329 $cont_obj = $cont_obj_gui->object; 1330 $material_title .= $cont_obj->getTitle(); 1331 break; 1332 case "pg": 1333 include_once("./Modules/LearningModule/classes/class.ilLMPageObject.php"); 1334 include_once("./Modules/LearningModule/classes/class.ilLMObject.php"); 1335 $lm_id = ilLMObject::_lookupContObjID($target_id); 1336 include_once("./Modules/LearningModule/classes/class.ilObjContentObjectGUI.php"); 1337 $cont_obj_gui = new ilObjContentObjectGUI("", $lm_id, false); 1338 $cont_obj = $cont_obj_gui->object; 1339 $pg_obj = new ilLMPageObject($cont_obj, $target_id); 1340 $material_title .= $pg_obj->getTitle(); 1341 break; 1342 case "st": 1343 include_once("./Modules/LearningModule/classes/class.ilStructureObject.php"); 1344 include_once("./Modules/LearningModule/classes/class.ilLMObject.php"); 1345 $lm_id = ilLMObject::_lookupContObjID($target_id); 1346 include_once("./Modules/LearningModule/classes/class.ilObjContentObjectGUI.php"); 1347 $cont_obj_gui = new ilObjContentObjectGUI("", $lm_id, false); 1348 $cont_obj = $cont_obj_gui->object; 1349 $st_obj = new ilStructureObject($cont_obj, $target_id); 1350 $material_title .= $st_obj->getTitle(); 1351 break; 1352 case "git": 1353 include_once "./Modules/Glossary/classes/class.ilGlossaryTerm.php"; 1354 $material_title = $this->lng->txt("glossary_term") . ": " . ilGlossaryTerm::_lookGlossaryTerm($target_id); 1355 break; 1356 case "mob": 1357 break; 1358 } 1359 } 1360 } 1361 include_once "./Modules/SurveyQuestionPool/classes/class.ilSurveyMaterial.php"; 1362 $mat = new ilSurveyMaterial(); 1363 $mat->type = 0; 1364 $mat->internal_link = $material_id; 1365 $mat->title = $material_title; 1366 $this->addMaterial($mat); 1367 $this->saveMaterial(); 1368 } 1369 } 1370 1371 /** 1372 * Deletes materials 1373 * 1374 * @param array $a_array Array with indexes of the materials to delete 1375 */ 1376 public function deleteMaterials($a_array) 1377 { 1378 foreach ($a_array as $idx) { 1379 unset($this->material[$idx]); 1380 } 1381 $this->material = array_values($this->material); 1382 $this->saveMaterial(); 1383 } 1384 1385 /** 1386 * Duplicates the materials of a question 1387 * 1388 * @param integer $question_id The database id of the original survey question 1389 * @access public 1390 */ 1391 public function duplicateMaterials($question_id) 1392 { 1393 foreach ($this->materials as $filename) { 1394 $materialspath = $this->getMaterialsPath(); 1395 $materialspath_original = preg_replace("/([^\d])$this->id([^\d])/", "\${1}$question_id\${2}", $materialspath); 1396 if (!file_exists($materialspath)) { 1397 ilUtil::makeDirParents($materialspath); 1398 } 1399 if (!copy($materialspath_original . $filename, $materialspath . $filename)) { 1400 print "material could not be duplicated!!!! "; 1401 } 1402 } 1403 } 1404 1405 public function addMaterial($obj_material) 1406 { 1407 array_push($this->material, $obj_material); 1408 } 1409 1410 /** 1411 * Sets a material link for the question 1412 * 1413 * @param string $material_id An internal link pointing to the material 1414 * @param boolean $is_import A boolean indication that the internal link was imported from another ILIAS installation 1415 * @access public 1416 */ 1417 public function setMaterial($material_id = "", $is_import = false, $material_title = "") 1418 { 1419 if (strcmp($material_id, "") != 0) { 1420 $import_id = ""; 1421 if ($is_import) { 1422 $import_id = $material_id; 1423 $material_id = self::_resolveInternalLink($import_id); 1424 } 1425 if (strcmp($material_title, "") == 0) { 1426 if (preg_match("/il__(\w+)_(\d+)/", $material_id, $matches)) { 1427 $type = $matches[1]; 1428 $target_id = $matches[2]; 1429 $material_title = $this->lng->txt("obj_$type") . ": "; 1430 switch ($type) { 1431 case "lm": 1432 include_once("./Modules/LearningModule/classes/class.ilObjContentObjectGUI.php"); 1433 $cont_obj_gui = new ilObjContentObjectGUI("", $target_id, true); 1434 $cont_obj = $cont_obj_gui->object; 1435 $material_title .= $cont_obj->getTitle(); 1436 break; 1437 case "pg": 1438 include_once("./Modules/LearningModule/classes/class.ilLMPageObject.php"); 1439 include_once("./Modules/LearningModule/classes/class.ilLMObject.php"); 1440 $lm_id = ilLMObject::_lookupContObjID($target_id); 1441 include_once("./Modules/LearningModule/classes/class.ilObjContentObjectGUI.php"); 1442 $cont_obj_gui = new ilObjContentObjectGUI("", $lm_id, false); 1443 $cont_obj = $cont_obj_gui->object; 1444 $pg_obj = new ilLMPageObject($cont_obj, $target_id); 1445 $material_title .= $pg_obj->getTitle(); 1446 break; 1447 case "st": 1448 include_once("./Modules/LearningModule/classes/class.ilStructureObject.php"); 1449 include_once("./Modules/LearningModule/classes/class.ilLMObject.php"); 1450 $lm_id = ilLMObject::_lookupContObjID($target_id); 1451 include_once("./Modules/LearningModule/classes/class.ilObjContentObjectGUI.php"); 1452 $cont_obj_gui = new ilObjContentObjectGUI("", $lm_id, false); 1453 $cont_obj = $cont_obj_gui->object; 1454 $st_obj = new ilStructureObject($cont_obj, $target_id); 1455 $material_title .= $st_obj->getTitle(); 1456 break; 1457 case "git": 1458 include_once "./Modules/Glossary/classes/class.ilGlossaryTerm.php"; 1459 $material_title = $this->lng->txt("glossary_term") . ": " . ilGlossaryTerm::_lookGlossaryTerm($target_id); 1460 break; 1461 case "mob": 1462 break; 1463 } 1464 } 1465 } 1466 $this->material = array( 1467 "internal_link" => $material_id, 1468 "import_id" => $import_id, 1469 "title" => $material_title 1470 ); 1471 } 1472 $this->saveMaterial(); 1473 } 1474 1475 public static function _resolveInternalLink($internal_link) 1476 { 1477 if (preg_match("/il_(\d+)_(\w+)_(\d+)/", $internal_link, $matches)) { 1478 include_once "./Services/Link/classes/class.ilInternalLink.php"; 1479 include_once "./Modules/LearningModule/classes/class.ilLMObject.php"; 1480 include_once "./Modules/Glossary/classes/class.ilGlossaryTerm.php"; 1481 switch ($matches[2]) { 1482 case "lm": 1483 $resolved_link = ilLMObject::_getIdForImportId($internal_link); 1484 break; 1485 case "pg": 1486 $resolved_link = ilInternalLink::_getIdForImportId("PageObject", $internal_link); 1487 break; 1488 case "st": 1489 $resolved_link = ilInternalLink::_getIdForImportId("StructureObject", $internal_link); 1490 break; 1491 case "git": 1492 $resolved_link = ilInternalLink::_getIdForImportId("GlossaryItem", $internal_link); 1493 break; 1494 case "mob": 1495 $resolved_link = ilInternalLink::_getIdForImportId("MediaObject", $internal_link); 1496 break; 1497 } 1498 if (strcmp($resolved_link, "") == 0) { 1499 $resolved_link = $internal_link; 1500 } 1501 } else { 1502 $resolved_link = $internal_link; 1503 } 1504 return $resolved_link; 1505 } 1506 1507 public static function _resolveIntLinks($question_id) 1508 { 1509 global $DIC; 1510 1511 $ilDB = $DIC->database(); 1512 $resolvedlinks = 0; 1513 $result = $ilDB->queryF( 1514 "SELECT * FROM svy_material WHERE question_fi = %s", 1515 array('integer'), 1516 array($question_id) 1517 ); 1518 if ($result->numRows()) { 1519 while ($row = $ilDB->fetchAssoc($result)) { 1520 $internal_link = $row["internal_link"]; 1521 include_once "./Modules/SurveyQuestionPool/classes/class.SurveyQuestion.php"; 1522 $resolved_link = self::_resolveInternalLink($internal_link); 1523 if (strcmp($internal_link, $resolved_link) != 0) { 1524 // internal link was resolved successfully 1525 $affectedRows = $ilDB->manipulateF( 1526 "UPDATE svy_material SET internal_link = %s, tstamp = %s WHERE material_id = %s", 1527 array('text', 'integer', 'integer'), 1528 array($resolved_link, time(), $row["material_id"]) 1529 ); 1530 $resolvedlinks++; 1531 } 1532 } 1533 } 1534 if ($resolvedlinks) { 1535 // there are resolved links -> reenter theses links to the database 1536 1537 // delete all internal links from the database 1538 include_once "./Services/Link/classes/class.ilInternalLink.php"; 1539 ilInternalLink::_deleteAllLinksOfSource("sqst", $question_id); 1540 1541 $result = $ilDB->queryF( 1542 "SELECT * FROM svy_material WHERE question_fi = %s", 1543 array('integer'), 1544 array($question_id) 1545 ); 1546 if ($result->numRows()) { 1547 while ($row = $ilDB->fetchAssoc($result)) { 1548 if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $row["internal_link"], $matches)) { 1549 ilInternalLink::_saveLink("sqst", $question_id, $matches[2], $matches[3], $matches[1]); 1550 } 1551 } 1552 } 1553 } 1554 } 1555 1556 public static function _getInternalLinkHref($target = "", $a_parent_ref_id = null) 1557 { 1558 global $DIC; 1559 1560 $ilDB = $DIC->database(); 1561 $linktypes = array( 1562 "lm" => "LearningModule", 1563 "pg" => "PageObject", 1564 "st" => "StructureObject", 1565 "git" => "GlossaryItem", 1566 "mob" => "MediaObject" 1567 ); 1568 $href = ""; 1569 if (preg_match("/il__(\w+)_(\d+)/", $target, $matches)) { 1570 $type = $matches[1]; 1571 $target_id = $matches[2]; 1572 switch ($linktypes[$matches[1]]) { 1573 case "LearningModule": 1574 $href = ilUtil::removeTrailingPathSeparators(ILIAS_HTTP_PATH) . "/goto.php?target=" . $type . "_" . $target_id; 1575 break; 1576 case "PageObject": 1577 case "StructureObject": 1578 $href = ilUtil::removeTrailingPathSeparators(ILIAS_HTTP_PATH) . "/goto.php?target=" . $type . "_" . $target_id; 1579 break; 1580 case "GlossaryItem": 1581 $href = ilUtil::removeTrailingPathSeparators(ILIAS_HTTP_PATH) . "/goto.php?target=" . $type . "_" . $target_id; 1582 break; 1583 case "MediaObject": 1584 $href = ilUtil::removeTrailingPathSeparators(ILIAS_HTTP_PATH) . "/ilias.php?baseClass=ilLMPresentationGUI&obj_type=" . $linktypes[$type] . "&cmd=media&ref_id=" . $a_parent_ref_id . "&mob_id=" . $target_id; 1585 break; 1586 } 1587 } 1588 return $href; 1589 } 1590 1591 /** 1592 * Returns true if the question is writeable by a certain user 1593 * 1594 * @param integer $question_id The database id of the question 1595 * @param integer $user_id The database id of the user 1596 * @result boolean True, if the question exists, otherwise False 1597 * @access public 1598 */ 1599 public static function _isWriteable($question_id, $user_id) 1600 { 1601 global $DIC; 1602 1603 $ilDB = $DIC->database(); 1604 1605 if (($question_id < 1) || ($user_id < 1)) { 1606 return false; 1607 } 1608 1609 $result = $ilDB->queryF( 1610 "SELECT obj_fi FROM svy_question WHERE question_id = %s", 1611 array('integer'), 1612 array($question_id) 1613 ); 1614 if ($result->numRows() == 1) { 1615 $row = $ilDB->fetchAssoc($result); 1616 $qpl_object_id = $row["obj_fi"]; 1617 include_once "./Modules/SurveyQuestionPool/classes/class.ilObjSurveyQuestionPool.php"; 1618 return ilObjSurveyQuestionPool::_isWriteable($qpl_object_id, $user_id); 1619 } else { 1620 return false; 1621 } 1622 } 1623 1624 /** 1625 * Returns the question type ID of the question 1626 * 1627 * @return integer The question type of the question 1628 * @access public 1629 */ 1630 public function getQuestionTypeID() 1631 { 1632 $ilDB = $this->db; 1633 $result = $ilDB->queryF( 1634 "SELECT questiontype_id FROM svy_qtype WHERE type_tag = %s", 1635 array('text'), 1636 array($this->getQuestionType()) 1637 ); 1638 if ($result->numRows() == 1) { 1639 $row = $ilDB->fetchAssoc($result); 1640 return $row["questiontype_id"]; 1641 } else { 1642 return 0; 1643 } 1644 } 1645 1646 /** 1647 * Returns the question type of the question 1648 * 1649 * @return integer The question type of the question 1650 * @access public 1651 */ 1652 public function getQuestionType() 1653 { 1654 return ""; 1655 } 1656 1657 /** 1658 * Include the php class file for a given question type 1659 * 1660 * @param string $question_type The type tag of the question type 1661 * @return integer 0 if the class should be included, 1 if the GUI class should be included 1662 * @access public 1663 */ 1664 public static function _includeClass($question_type, $gui = 0) 1665 { 1666 $type = $question_type; 1667 if ($gui == 1) { 1668 $type .= "GUI"; 1669 } elseif ($gui == 2) { 1670 $type .= "Evaluation"; 1671 } 1672 if (file_exists("./Modules/SurveyQuestionPool/classes/class." . $type . ".php")) { 1673 include_once "./Modules/SurveyQuestionPool/classes/class." . $type . ".php"; 1674 return true; 1675 } else { 1676 global $DIC; 1677 1678 $ilPluginAdmin = $DIC["ilPluginAdmin"]; 1679 $pl_names = $ilPluginAdmin->getActivePluginsForSlot(IL_COMP_MODULE, "SurveyQuestionPool", "svyq"); 1680 foreach ($pl_names as $pl_name) { 1681 $pl = ilPlugin::getPluginObject(IL_COMP_MODULE, "SurveyQuestionPool", "svyq", $pl_name); 1682 if (strcmp($pl->getQuestionType(), $question_type) == 0) { 1683 $pl->includeClass("class." . $type . ".php"); 1684 return true; 1685 } 1686 } 1687 } 1688 return false; 1689 } 1690 1691 /** 1692 * Return the translation for a given question type tag 1693 * 1694 * @param string $type_tag The type tag of the question type 1695 * @access public 1696 */ 1697 public static function _getQuestionTypeName($type_tag) 1698 { 1699 if (file_exists("./Modules/SurveyQuestionPool/classes/class." . $type_tag . ".php")) { 1700 global $DIC; 1701 1702 $lng = $DIC->language(); 1703 return $lng->txt($type_tag); 1704 } else { 1705 global $DIC; 1706 1707 $ilPluginAdmin = $DIC["ilPluginAdmin"]; 1708 $pl_names = $ilPluginAdmin->getActivePluginsForSlot(IL_COMP_MODULE, "SurveyQuestionPool", "svyq"); 1709 foreach ($pl_names as $pl_name) { 1710 $pl = ilPlugin::getPluginObject(IL_COMP_MODULE, "SurveyQuestionPool", "svyq", $pl_name); 1711 if (strcmp($pl->getQuestionType(), $type_tag) == 0) { 1712 return $pl->getQuestionTypeTranslation(); 1713 } 1714 } 1715 } 1716 return ""; 1717 } 1718 1719 1720 /** 1721 * Creates an instance of a question with a given question id 1722 * 1723 * @param integer $question_id The question id 1724 * @return object The question instance 1725 * @access public 1726 */ 1727 public static function _instanciateQuestion($question_id) 1728 { 1729 $question_type = self::_getQuestionType($question_id); 1730 if ($question_type) { 1731 self::_includeClass($question_type); 1732 $question = new $question_type(); 1733 $question->loadFromDb($question_id); 1734 return $question; 1735 } 1736 } 1737 1738 /** 1739 * Creates an instance of a question GUI with a given question id 1740 * 1741 * @param integer $question_id The question id 1742 * @return object The question GUI instance 1743 * @access public 1744 */ 1745 public static function _instanciateQuestionGUI($question_id) 1746 { 1747 $question_type = self::_getQuestionType($question_id); 1748 if ($question_type) { 1749 self::_includeClass($question_type, 1); 1750 $guitype = $question_type . "GUI"; 1751 $question = new $guitype($question_id); 1752 return $question; 1753 } 1754 } 1755 1756 /** 1757 * Creates an instance of a question evaluation with a given question id 1758 * 1759 * @param integer $question_id The question id 1760 * @return object The question evaluation instance 1761 * @access public 1762 */ 1763 public static function _instanciateQuestionEvaluation($question_id, array $a_finished_ids = null) 1764 { 1765 $question = self::_instanciateQuestion($question_id); 1766 if ($question) { 1767 $question_type = self::_getQuestionType($question_id); 1768 self::_includeClass($question_type, 2); 1769 $class = $question_type . "Evaluation"; 1770 $ev = new $class($question, $a_finished_ids); 1771 return $ev; 1772 } 1773 } 1774 1775 /** 1776 * Checks if a given string contains HTML or not 1777 * 1778 * @param string $a_text Text which should be checked 1779 * 1780 * @return boolean 1781 * @access public 1782 */ 1783 public function isHTML($a_text) 1784 { 1785 if (preg_match("/<[^>]*?>/", $a_text)) { 1786 return true; 1787 } else { 1788 return false; 1789 } 1790 } 1791 1792 /** 1793 * Reads an QTI material tag an creates a text string 1794 * 1795 * @param string $a_material QTI material tag 1796 * @return string text or xhtml string 1797 * @access public 1798 */ 1799 public function QTIMaterialToString($a_material) 1800 { 1801 $svy_log = ilLoggerFactory::getLogger("svy"); 1802 $svy_log->debug("material count: " . $a_material->getMaterialCount()); 1803 1804 $result = ""; 1805 for ($i = 0; $i < $a_material->getMaterialCount(); $i++) { 1806 $material = $a_material->getMaterial($i); 1807 if (strcmp($material["type"], "mattext") == 0) { 1808 $result .= $material["material"]->getContent(); 1809 } 1810 if (strcmp($material["type"], "matimage") == 0) { 1811 $matimage = $material["material"]; 1812 if (preg_match("/(il_([0-9]+)_mob_([0-9]+))/", $matimage->getLabel(), $matches)) { 1813 // import an mediaobject which was inserted using tiny mce 1814 if (!is_array($_SESSION["import_mob_xhtml"])) { 1815 $_SESSION["import_mob_xhtml"] = array(); 1816 } 1817 array_push($_SESSION["import_mob_xhtml"], array("mob" => $matimage->getLabel(), "uri" => $matimage->getUri())); 1818 } 1819 } 1820 } 1821 return $result; 1822 } 1823 1824 /** 1825 * Creates an XML material tag from a plain text or xhtml text 1826 * 1827 * @param object $a_xml_writer Reference to the ILIAS XML writer 1828 * @param string $a_material plain text or html text containing the material 1829 * @return string XML material tag 1830 * @access public 1831 */ 1832 public function addMaterialTag(&$a_xml_writer, $a_material, $close_material_tag = true, $add_mobs = true, $a_attrs = null) 1833 { 1834 include_once "./Services/RTE/classes/class.ilRTE.php"; 1835 include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php"); 1836 1837 $a_xml_writer->xmlStartTag("material"); 1838 $attrs = array( 1839 "type" => "text/plain" 1840 ); 1841 if ($this->isHTML($a_material)) { 1842 $attrs["type"] = "text/xhtml"; 1843 } 1844 if (is_array($a_attrs)) { 1845 $attrs = array_merge($attrs, $a_attrs); 1846 } 1847 $a_xml_writer->xmlElement("mattext", $attrs, ilRTE::_replaceMediaObjectImageSrc($a_material, 0)); 1848 1849 if ($add_mobs) { 1850 $mobs = ilObjMediaObject::_getMobsOfObject("spl:html", $this->getId()); 1851 foreach ($mobs as $mob) { 1852 $mob_obj = new ilObjMediaObject($mob); 1853 $imgattrs = array( 1854 "label" => "il_" . IL_INST_ID . "_mob_" . $mob, 1855 "uri" => "objects/" . "il_" . IL_INST_ID . "_mob_" . $mob . "/" . $mob_obj->getTitle(), 1856 "type" => "spl:html", 1857 "id" => $this->getId() 1858 ); 1859 $a_xml_writer->xmlElement("matimage", $imgattrs, null); 1860 } 1861 } 1862 if ($close_material_tag) { 1863 $a_xml_writer->xmlEndTag("material"); 1864 } 1865 } 1866 1867 /** 1868 * Prepares a string for a text area output in surveys 1869 * 1870 * @param string $txt_output String which should be prepared for output 1871 * @access public 1872 */ 1873 public function prepareTextareaOutput($txt_output, $prepare_for_latex_output = false) 1874 { 1875 return ilUtil::prepareTextareaOutput($txt_output, $prepare_for_latex_output); 1876 } 1877 1878 /** 1879 * Returns the question data fields from the database 1880 * 1881 * @param integer $id The question ID from the database 1882 * @return array Array containing the question fields and data from the database 1883 * @access public 1884 */ 1885 public function getQuestionDataArray($id) 1886 { 1887 return array(); 1888 } 1889 1890 /** 1891 * Creates the user data of the svy_answer table from the POST data 1892 * 1893 * @return array User data according to the svy_answer table 1894 * @access public 1895 */ 1896 public function &getWorkingDataFromUserInput($post_data) 1897 { 1898 // overwrite in inherited classes 1899 $data = array(); 1900 return $data; 1901 } 1902 1903 /** 1904 * Import additional meta data from the question import file. Usually 1905 * the meta data section is used to store question elements which are not 1906 * part of the standard XML schema. 1907 * 1908 * @return array $a_meta Array containing the additional meta data 1909 * @access public 1910 */ 1911 public function importAdditionalMetadata($a_meta) 1912 { 1913 // overwrite in inherited classes 1914 } 1915 1916 /** 1917 * Import response data from the question import file 1918 * 1919 * @return array $a_data Array containing the response data 1920 * @access public 1921 */ 1922 public function importResponses($a_data) 1923 { 1924 // overwrite in inherited classes 1925 } 1926 1927 /** 1928 * Import bipolar adjectives from the question import file 1929 * 1930 * @return array $a_data Array containing the adjectives 1931 * @access public 1932 */ 1933 public function importAdjectives($a_data) 1934 { 1935 // overwrite in inherited classes 1936 } 1937 1938 /** 1939 * Import matrix rows from the question import file 1940 * 1941 * @return array $a_data Array containing the matrix rows 1942 * @access public 1943 */ 1944 public function importMatrix($a_data) 1945 { 1946 // overwrite in inherited classes 1947 } 1948 1949 /** 1950 * Returns if the question is usable for preconditions 1951 * 1952 * @return boolean TRUE if the question is usable for a precondition, FALSE otherwise 1953 * @access public 1954 */ 1955 public function usableForPrecondition() 1956 { 1957 // overwrite in inherited classes 1958 return false; 1959 } 1960 1961 /** 1962 * Returns the available relations for the question 1963 * 1964 * @return array An array containing the available relations 1965 * @access public 1966 */ 1967 public function getAvailableRelations() 1968 { 1969 // overwrite in inherited classes 1970 return array(); 1971 } 1972 1973 /** 1974 * Returns the options for preconditions 1975 * 1976 * @return array 1977 */ 1978 public function getPreconditionOptions() 1979 { 1980 // overwrite in inherited classes 1981 } 1982 1983 /** 1984 * Returns the output for a precondition value 1985 * 1986 * @param string $value The precondition value 1987 * @return string The output of the precondition value 1988 * @access public 1989 */ 1990 public function getPreconditionValueOutput($value) 1991 { 1992 // overwrite in inherited classes 1993 return $value; 1994 } 1995 1996 /** 1997 * Creates a form property for the precondition value 1998 * 1999 * @return The ILIAS form element 2000 * @access public 2001 */ 2002 public function getPreconditionSelectValue($default = "", $title, $variable) 2003 { 2004 // overwrite in inherited classes 2005 return null; 2006 } 2007 2008 public function setOriginalId($original_id) 2009 { 2010 $this->original_id = $original_id; 2011 } 2012 2013 public function getOriginalId() 2014 { 2015 return $this->original_id; 2016 } 2017 2018 public function getMaterial() 2019 { 2020 return $this->material; 2021 } 2022 2023 public function setSubtype($a_subtype) 2024 { 2025 // do nothing 2026 } 2027 2028 public function getSubtype() 2029 { 2030 // do nothing 2031 return null; 2032 } 2033 2034 /** 2035 * Object getter 2036 */ 2037 public function __get($value) 2038 { 2039 switch ($value) { 2040 default: 2041 if (array_key_exists($value, $this->arrData)) { 2042 return $this->arrData[$value]; 2043 } else { 2044 return null; 2045 } 2046 break; 2047 } 2048 } 2049 2050 /** 2051 * Object setter 2052 */ 2053 public function __set($key, $value) 2054 { 2055 switch ($key) { 2056 default: 2057 $this->arrData[$key] = $value; 2058 break; 2059 } 2060 } 2061 2062 /** 2063 * Change original id of existing question in db 2064 * 2065 * @param int $a_question_id 2066 * @param int $a_original_id 2067 * @param int $a_object_id 2068 */ 2069 public static function _changeOriginalId($a_question_id, $a_original_id, $a_object_id) 2070 { 2071 global $DIC; 2072 2073 $ilDB = $DIC->database(); 2074 2075 $ilDB->manipulate("UPDATE svy_question" . 2076 " SET original_id = " . $ilDB->quote($a_original_id, "integer") . "," . 2077 " obj_fi = " . $ilDB->quote($a_object_id, "integer") . 2078 " WHERE question_id = " . $ilDB->quote($a_question_id, "integer")); 2079 } 2080 2081 public function getCopyIds($a_group_by_survey = false) 2082 { 2083 $ilDB = $this->db; 2084 2085 $set = $ilDB->query("SELECT q.question_id,s.obj_fi" . 2086 " FROM svy_question q" . 2087 " JOIN svy_svy_qst sq ON (sq.question_fi = q.question_id)" . 2088 " JOIN svy_svy s ON (s.survey_id = sq.survey_fi)" . 2089 " WHERE original_id = " . $ilDB->quote($this->getId(), "integer")); 2090 $res = array(); 2091 while ($row = $ilDB->fetchAssoc($set)) { 2092 if (!$a_group_by_survey) { 2093 $res[] = $row["question_id"]; 2094 } else { 2095 $res[$row["obj_fi"]][] = $row["question_id"]; 2096 } 2097 } 2098 return $res; 2099 } 2100 2101 public function hasCopies() 2102 { 2103 return (bool) sizeof($this->getCopyIds()); 2104 } 2105 2106 public static function _lookupSurveyObjId($a_question_id) 2107 { 2108 global $DIC; 2109 2110 $ilDB = $DIC->database(); 2111 2112 $set = $ilDB->query("SELECT svy_svy.obj_fi FROM svy_svy_qst" . 2113 " JOIN svy_svy ON (svy_svy.survey_id = svy_svy_qst.survey_fi)" . 2114 " WHERE svy_svy_qst.question_fi = " . $ilDB->quote($a_question_id, "integer")); 2115 $row = $ilDB->fetchAssoc($set); 2116 if ($ilDB->numRows($set)) { 2117 return $row["obj_fi"]; 2118 } 2119 } 2120 2121 /** 2122 * Lookip obj fi 2123 * 2124 * @param 2125 * @return 2126 */ 2127 public static function lookupObjFi($a_qid) 2128 { 2129 global $DIC; 2130 2131 $ilDB = $DIC->database(); 2132 2133 $set = $ilDB->query( 2134 "SELECT obj_fi FROM svy_question " . 2135 " WHERE question_id = " . $ilDB->quote($a_qid, "integer") 2136 ); 2137 $rec = $ilDB->fetchAssoc($set); 2138 return $rec["obj_fi"]; 2139 } 2140 2141 /** 2142 * Strip slashes with add space fallback, see https://mantis.ilias.de/view.php?id=19727 2143 * and https://mantis.ilias.de/view.php?id=24200 2144 * 2145 * @param string $a_str string 2146 * @return string 2147 */ 2148 public function stripSlashesAddSpaceFallback($a_str) 2149 { 2150 $str = ilUtil::stripSlashes($a_str); 2151 if ($str != $a_str) { 2152 $str = ilUtil::stripSlashes(str_replace("<", "< ", $a_str)); 2153 } 2154 return $str; 2155 } 2156} 2157