ILIAS  Release_5_0_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.ilObjQuestionPool.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3 
4 include_once "./Modules/Test/classes/inc.AssessmentConstants.php";
5 
17 {
23  var $online;
24 
30  private $showTaxonomies = null;
31 
37  private $navTaxonomyId = null;
38 
43  private $import_dir;
44 
51  function ilObjQuestionPool($a_id = 0,$a_call_by_reference = true)
52  {
53  $this->type = "qpl";
54  $this->ilObject($a_id,$a_call_by_reference);
55  $this->setOnline(0);
56  }
57 
61  function create($a_upload = false)
62  {
64 
65  // meta data will be created by
66  // import parser
67  if (!$a_upload)
68  {
69  $this->createMetaData();
70  }
71  }
72 
79  function createReference()
80  {
82  $this->saveToDb();
83  return $result;
84  }
85 
92  function update()
93  {
94  $this->updateMetaData();
95  if (!parent::update())
96  {
97  return false;
98  }
99 
100  // put here object specific stuff
101 
102  return true;
103  }
104 
105  function updateMetaData()
106  {
107  global $ilUser;
108  include_once "./Services/MetaData/classes/class.ilMD.php";
109  $md =& new ilMD($this->getId(), 0, $this->getType());
110  $md_gen =& $md->getGeneral();
111  if ($md_gen == false)
112  {
113  include_once "./Services/MetaData/classes/class.ilMDCreator.php";
114  $md_creator = new ilMDCreator($this->getId(),0,$this->getType());
115  $md_creator->setTitle($this->getTitle());
116  $md_creator->setTitleLanguage($ilUser->getPref('language'));
117  $md_creator->create();
118  }
120  }
121 
127  function read($a_force_db = false)
128  {
129  parent::read($a_force_db);
130  $this->loadFromDb();
131  }
132 
133 
140  function delete()
141  {
142  // always call parent delete function first!!
143  if (!parent::delete())
144  {
145  return false;
146  }
147 
148  // delete meta data
149  $this->deleteMetaData();
150 
151  //put here your module specific stuff
152  $this->deleteQuestionpool();
153 
154  return true;
155  }
156 
158  {
159  $questions =& $this->getAllQuestions();
160 
161  if (count($questions))
162  {
163  foreach ($questions as $question_id)
164  {
165  $this->deleteQuestion($question_id);
166  }
167  }
168 
169  // delete export files
170  include_once "./Services/Utilities/classes/class.ilUtil.php";
171  $qpl_data_dir = ilUtil::getDataDir()."/qpl_data";
172  $directory = $qpl_data_dir."/qpl_".$this->getId();
173  if (is_dir($directory))
174  {
175  include_once "./Services/Utilities/classes/class.ilUtil.php";
176  ilUtil::delDir($directory);
177  }
178  }
179 
180 
194  function notify($a_event,$a_ref_id,$a_parent_non_rbac_id,$a_node_id,$a_params = 0)
195  {
196  global $tree;
197 
198  switch ($a_event)
199  {
200  case "link":
201 
202  //var_dump("<pre>",$a_params,"</pre>");
203  //echo "Module name ".$this->getRefId()." triggered by link event. Objects linked into target object ref_id: ".$a_ref_id;
204  //exit;
205  break;
206 
207  case "cut":
208 
209  //echo "Module name ".$this->getRefId()." triggered by cut event. Objects are removed from target object ref_id: ".$a_ref_id;
210  //exit;
211  break;
212 
213  case "copy":
214 
215  //var_dump("<pre>",$a_params,"</pre>");
216  //echo "Module name ".$this->getRefId()." triggered by copy event. Objects are copied into target object ref_id: ".$a_ref_id;
217  //exit;
218  break;
219 
220  case "paste":
221 
222  //echo "Module name ".$this->getRefId()." triggered by paste (cut) event. Objects are pasted into target object ref_id: ".$a_ref_id;
223  //exit;
224  break;
225 
226  case "new":
227 
228  //echo "Module name ".$this->getRefId()." triggered by paste (new) event. Objects are applied to target object ref_id: ".$a_ref_id;
229  //exit;
230  break;
231  }
232 
233  // At the beginning of the recursive process it avoids second call of the notify function with the same parameter
234  if ($a_node_id==$_GET["ref_id"])
235  {
236  $parent_obj =& $this->ilias->obj_factory->getInstanceByRefId($a_node_id);
237  $parent_type = $parent_obj->getType();
238  if($parent_type == $this->getType())
239  {
240  $a_node_id = (int) $tree->getParentId($a_node_id);
241  }
242  }
243 
244  parent::notify($a_event,$a_ref_id,$a_parent_non_rbac_id,$a_node_id,$a_params);
245  }
246 
253  function deleteQuestion($question_id)
254  {
255  include_once "./Modules/Test/classes/class.ilObjTest.php";
256  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
257 
258  $question = assQuestion::_instanciateQuestion($question_id);
259  $this->addQuestionChangeListeners($question);
260  $question->delete($question_id);
261  }
262 
266  public function addQuestionChangeListeners(assQuestion $question)
267  {
268  global $ilDB;
269 
270  foreach(ilObjTest::getPoolQuestionChangeListeners($ilDB, $this->getId()) as $listener)
271  {
272  $question->addQuestionChangeListener($listener);
273  }
274  }
275 
281  function loadFromDb()
282  {
283  global $ilDB;
284 
285  $result = $ilDB->queryF("SELECT * FROM qpl_questionpool WHERE obj_fi = %s",
286  array('integer'),
287  array($this->getId())
288  );
289  if ($result->numRows() == 1)
290  {
291  $row = $ilDB->fetchAssoc($result);
292  $this->setOnline($row['isonline']);
293  $this->setShowTaxonomies($row['show_taxonomies']);
294  $this->setNavTaxonomyId($row['nav_taxonomy']);
295  }
296  }
297 
303  function saveToDb()
304  {
305  global $ilDB;
306 
307  $result = $ilDB->queryF("SELECT id_questionpool FROM qpl_questionpool WHERE obj_fi = %s",
308  array('integer'),
309  array($this->getId())
310  );
311 
312  if ($result->numRows() == 1)
313  {
314  $result = $ilDB->update('qpl_questionpool',
315  array(
316  'isonline' => array('text', $this->getOnline()),
317  'show_taxonomies' => array('integer', (int)$this->getShowTaxonomies()),
318  'nav_taxonomy' => array('integer', (int)$this->getNavTaxonomyId()),
319  'tstamp' => array('integer', time())
320  ),
321  array(
322  'obj_fi' => array('integer', $this->getId())
323  )
324  );
325  }
326  else
327  {
328  $next_id = $ilDB->nextId('qpl_questionpool');
329 
330  $result = $ilDB->insert('qpl_questionpool', array(
331  'id_questionpool' => array('integer', $next_id),
332  'isonline' => array('text', $this->getOnline()),
333  'show_taxonomies' => array('integer', (int)$this->getShowTaxonomies()),
334  'nav_taxonomy' => array('integer', (int)$this->getNavTaxonomyId()),
335  'tstamp' => array('integer', time()),
336  'obj_fi' => array('integer', $this->getId())
337  ));
338  }
339  }
340 
348  function getQuestiontype($question_id)
349  {
350  global $ilDB;
351 
352  if ($question_id < 1)
353  {
354  return;
355  }
356 
357  $result = $ilDB->queryF("SELECT qpl_qst_type.type_tag FROM qpl_questions, qpl_qst_type WHERE qpl_questions.question_type_fi = qpl_qst_type.question_type_id AND qpl_questions.question_id = %s",
358  array('integer'),
359  array($question_id)
360  );
361  if ($result->numRows() == 1)
362  {
363  $data = $ilDB->fetchAssoc($result);
364  return $data["type_tag"];
365  }
366  else
367  {
368  return;
369  }
370  }
371 
377  function getDescription()
378  {
379  return parent::getDescription();
380  }
381 
385  function setDescription($a_description)
386  {
387  parent::setDescription($a_description);
388  }
389 
395  function getTitle()
396  {
397  return parent::getTitle();
398  }
399 
403  function setTitle($a_title)
404  {
405  parent::setTitle($a_title);
406  }
407 
415  function isInUse($question_id)
416  {
417  global $ilDB;
418 
419  $result = $ilDB->queryF("SELECT COUNT(solution_id) solution_count FROM tst_solutions WHERE question_fi = %s",
420  array('integer'),
421  array($question_id)
422  );
423  $row = $ilDB->fetchAssoc($result);
424  return $row["solution_count"];
425  }
426 
427  function &createQuestion($question_type, $question_id = -1)
428  {
429  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
430  if ($question_id > 0) return assQuestion::_instanciateQuestionGUI($question_id);
431  assQuestion::_includeClass($question_type, 1);
432  $question_type_gui = $question_type . "GUI";
433  $question_gui =& new $question_type_gui();
434  return $question_gui;
435  }
436 
443  function duplicateQuestion($question_id)
444  {
445  $question =& $this->createQuestion("", $question_id);
446  $newtitle = $question->object->getTitle();
447  if ($question->object->questionTitleExists($this->getId(), $question->object->getTitle()))
448  {
449  $counter = 2;
450  while ($question->object->questionTitleExists($this->getId(), $question->object->getTitle() . " ($counter)"))
451  {
452  $counter++;
453  }
454  $newtitle = $question->object->getTitle() . " ($counter)";
455  }
456  $new_id = $question->object->duplicate(false, $newtitle);
457  // update question count of question pool
459  return $new_id;
460  }
461 
469  function copyQuestion($question_id, $questionpool_to)
470  {
471  $question_gui =& $this->createQuestion("", $question_id);
472  if ($question_gui->object->getObjId() == $questionpool_to)
473  {
474  // the question is copied into the same question pool
475  return $this->duplicateQuestion($question_id);
476  }
477  else
478  {
479  // the question is copied into another question pool
480  $newtitle = $question_gui->object->getTitle();
481  if ($question_gui->object->questionTitleExists($this->getId(), $question_gui->object->getTitle()))
482  {
483  $counter = 2;
484  while ($question_gui->object->questionTitleExists($this->getId(), $question_gui->object->getTitle() . " ($counter)"))
485  {
486  $counter++;
487  }
488  $newtitle = $question_gui->object->getTitle() . " ($counter)";
489  }
490  return $question_gui->object->copyObject($this->getId(), $newtitle);
491  }
492  }
493 
499  public function getPrintviewQuestions()
500  {
501  global $ilDB;
502 
503  $query_result = $ilDB->queryF("SELECT qpl_questions.*, qpl_qst_type.type_tag, qpl_qst_type.plugin, qpl_questions.tstamp updated FROM qpl_questions, qpl_qst_type WHERE qpl_questions.original_id IS NULL AND qpl_questions.tstamp > 0 AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id AND qpl_questions.obj_fi = %s",
504  array('integer'),
505  array($this->getId())
506  );
507  $rows = array();
508  $types = $this->getQuestionTypeTranslations();
509  if ($query_result->numRows())
510  {
511  while ($row = $ilDB->fetchAssoc($query_result))
512  {
513  $row['ttype'] = $types[$row['type_tag']];
514  if ($row["plugin"])
515  {
516  if ($this->isPluginActive($row["type_tag"]))
517  {
518  array_push($rows, $row);
519  }
520  }
521  else
522  {
523  array_push($rows, $row);
524  }
525  }
526  }
527  return $rows;
528  }
529 
536  function exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog, $questions)
537  {
538  global $ilBench;
539 
540  $this->mob_ids = array();
541  $this->file_ids = array();
542 
543  $attrs = array();
544  $attrs["Type"] = "Questionpool_Test";
545  $a_xml_writer->xmlStartTag("ContentObject", $attrs);
546 
547  // MetaData
548  $this->exportXMLMetaData($a_xml_writer);
549 
550  // PageObjects
551  $expLog->write(date("[y-m-d H:i:s] ")."Start Export Page Objects");
552  $ilBench->start("ContentObjectExport", "exportPageObjects");
553  $this->exportXMLPageObjects($a_xml_writer, $a_inst, $expLog, $questions);
554  $ilBench->stop("ContentObjectExport", "exportPageObjects");
555  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export Page Objects");
556 
557  // MediaObjects
558  $expLog->write(date("[y-m-d H:i:s] ")."Start Export Media Objects");
559  $ilBench->start("ContentObjectExport", "exportMediaObjects");
560  $this->exportXMLMediaObjects($a_xml_writer, $a_inst, $a_target_dir, $expLog);
561  $ilBench->stop("ContentObjectExport", "exportMediaObjects");
562  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export Media Objects");
563 
564  // FileItems
565  $expLog->write(date("[y-m-d H:i:s] ")."Start Export File Items");
566  $ilBench->start("ContentObjectExport", "exportFileItems");
567  $this->exportFileItems($a_target_dir, $expLog);
568  $ilBench->stop("ContentObjectExport", "exportFileItems");
569  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export File Items");
570 
571  $a_xml_writer->xmlEndTag("ContentObject");
572  }
573 
580  function exportXMLMetaData(&$a_xml_writer)
581  {
582  include_once("Services/MetaData/classes/class.ilMD2XML.php");
583  $md2xml = new ilMD2XML($this->getId(), 0, $this->getType());
584  $md2xml->setExportMode(true);
585  $md2xml->startExport();
586  $a_xml_writer->appendXML($md2xml->getXML());
587  }
588 
589  function modifyExportIdentifier($a_tag, $a_param, $a_value)
590  {
591  if ($a_tag == "Identifier" && $a_param == "Entry")
592  {
593  include_once "./Services/Utilities/classes/class.ilUtil.php";
594  $a_value = ilUtil::insertInstIntoID($a_value);
595  }
596 
597  return $a_value;
598  }
599 
600 
607  function exportXMLPageObjects(&$a_xml_writer, $a_inst, &$expLog, $questions)
608  {
609  global $ilBench;
610 
611  include_once "./Modules/LearningModule/classes/class.ilLMPageObject.php";
612 
613  foreach ($questions as $question_id)
614  {
615  $ilBench->start("ContentObjectExport", "exportPageObject");
616  $expLog->write(date("[y-m-d H:i:s] ")."Page Object ".$question_id);
617 
618  $attrs = array();
619  $a_xml_writer->xmlStartTag("PageObject", $attrs);
620 
621 
622  // export xml to writer object
623  $ilBench->start("ContentObjectExport", "exportPageObject_XML");
624  include_once("./Modules/TestQuestionPool/classes/class.ilAssQuestionPage.php");
625  $page_object = new ilAssQuestionPage($question_id);
626  $page_object->buildDom();
627  $page_object->insertInstIntoIDs($a_inst);
628  $mob_ids = $page_object->collectMediaObjects(false);
629  require_once 'Services/COPage/classes/class.ilPCFileList.php';
630  $file_ids = ilPCFileList::collectFileItems($page_object, $page_object->getDomDoc());
631  $xml = $page_object->getXMLFromDom(false, false, false, "", true);
632  $xml = str_replace("&","&amp;", $xml);
633  $a_xml_writer->appendXML($xml);
634  $page_object->freeDom();
635  unset ($page_object);
636 
637  $ilBench->stop("ContentObjectExport", "exportPageObject_XML");
638 
639  // collect media objects
640  $ilBench->start("ContentObjectExport", "exportPageObject_CollectMedia");
641  //$mob_ids = $page_obj->getMediaObjectIDs();
642  foreach($mob_ids as $mob_id)
643  {
644  $this->mob_ids[$mob_id] = $mob_id;
645  }
646  $ilBench->stop("ContentObjectExport", "exportPageObject_CollectMedia");
647 
648  // collect all file items
649  $ilBench->start("ContentObjectExport", "exportPageObject_CollectFileItems");
650  //$file_ids = $page_obj->getFileItemIds();
651  foreach($file_ids as $file_id)
652  {
653  $this->file_ids[$file_id] = $file_id;
654  }
655  $ilBench->stop("ContentObjectExport", "exportPageObject_CollectFileItems");
656 
657  $a_xml_writer->xmlEndTag("PageObject");
658  //unset($page_obj);
659 
660  $ilBench->stop("ContentObjectExport", "exportPageObject");
661 
662 
663  }
664  }
665 
672  function exportXMLMediaObjects(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
673  {
674  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
675 
676  foreach ($this->mob_ids as $mob_id)
677  {
678  $expLog->write(date("[y-m-d H:i:s] ")."Media Object ".$mob_id);
679  if (ilObjMediaObject::_exists($mob_id))
680  {
681  $media_obj = new ilObjMediaObject($mob_id);
682  $media_obj->exportXML($a_xml_writer, $a_inst);
683  $media_obj->exportFiles($a_target_dir);
684  unset($media_obj);
685  }
686  }
687  }
688 
693  function exportFileItems($a_target_dir, &$expLog)
694  {
695  include_once("./Modules/File/classes/class.ilObjFile.php");
696 
697  foreach ($this->file_ids as $file_id)
698  {
699  $expLog->write(date("[y-m-d H:i:s] ")."File Item ".$file_id);
700  $file_obj = new ilObjFile($file_id, false);
701  $file_obj->export($a_target_dir);
702  unset($file_obj);
703  }
704  }
705 
712  {
713  include_once "./Services/Utilities/classes/class.ilUtil.php";
714  $qpl_data_dir = ilUtil::getDataDir()."/qpl_data";
715  ilUtil::makeDir($qpl_data_dir);
716  if(!is_writable($qpl_data_dir))
717  {
718  $this->ilias->raiseError("Questionpool Data Directory (".$qpl_data_dir
719  .") not writeable.",$this->ilias->error_obj->FATAL);
720  }
721 
722  // create learning module directory (data_dir/lm_data/lm_<id>)
723  $qpl_dir = $qpl_data_dir."/qpl_".$this->getId();
724  ilUtil::makeDir($qpl_dir);
725  if(!@is_dir($qpl_dir))
726  {
727  $this->ilias->raiseError("Creation of Questionpool Directory failed.",$this->ilias->error_obj->FATAL);
728  }
729  // create Export subdirectory (data_dir/lm_data/lm_<id>/Export)
730  ilUtil::makeDir($this->getExportDirectory('xls'));
731  if(!@is_dir($this->getExportDirectory('xls')))
732  {
733  $this->ilias->raiseError("Creation of Export Directory failed.",$this->ilias->error_obj->FATAL);
734  }
735  ilUtil::makeDir($this->getExportDirectory('zip'));
736  if(!@is_dir($this->getExportDirectory('zip')))
737  {
738  $this->ilias->raiseError("Creation of Export Directory failed.",$this->ilias->error_obj->FATAL);
739  }
740  }
741 
745  function getExportDirectory($type = "")
746  {
747  include_once "./Services/Utilities/classes/class.ilUtil.php";
748  switch ($type)
749  {
750  case 'xls':
751  case 'zip':
752  $export_dir = ilUtil::getDataDir()."/qpl_data"."/qpl_".$this->getId()."/export_$type";
753  break;
754  default:
755  $export_dir = ilUtil::getDataDir()."/qpl_data"."/qpl_".$this->getId()."/export";
756  break;
757  }
758  return $export_dir;
759  }
760 
766  static function _createImportDirectory()
767  {
768  global $ilias;
769 
770  include_once "./Services/Utilities/classes/class.ilUtil.php";
771  $qpl_data_dir = ilUtil::getDataDir()."/qpl_data";
772  ilUtil::makeDir($qpl_data_dir);
773 
774  if(!is_writable($qpl_data_dir))
775  {
776  $ilias->raiseError("Questionpool Data Directory (".$qpl_data_dir
777  .") not writeable.",$ilias->error_obj->FATAL);
778  }
779 
780  // create questionpool directory (data_dir/qpl_data/qpl_import)
781  $qpl_dir = $qpl_data_dir."/qpl_import";
782  ilUtil::makeDir($qpl_dir);
783  if(!@is_dir($qpl_dir))
784  {
785  $ilias->raiseError("Creation of Questionpool Directory failed.",$ilias->error_obj->FATAL);
786  }
787  return $qpl_dir;
788  }
789 
793  function _setImportDirectory($a_import_dir = null)
794  {
795  if (strlen($a_import_dir))
796  {
797  $_SESSION["qpl_import_dir"] = $a_import_dir;
798  }
799  else
800  {
801  unset($_SESSION["qpl_import_dir"]);
802  }
803  }
804 
809  {
810  if (strlen($_SESSION["qpl_import_dir"]))
811  {
812  return $_SESSION["qpl_import_dir"];
813  }
814  return null;
815  }
816 
818  {
820  }
821 
827  function &getAllQuestions()
828  {
829  global $ilDB;
830 
831  $result = $ilDB->queryF("SELECT question_id FROM qpl_questions WHERE obj_fi = %s AND qpl_questions.tstamp > 0 AND original_id IS NULL",
832  array('integer'),
833  array($this->getId())
834  );
835  $questions = array();
836  while ($row = $ilDB->fetchAssoc($result))
837  {
838  array_push($questions, $row["question_id"]);
839  }
840  return $questions;
841  }
842 
843  function &getAllQuestionIds()
844  {
845  global $ilDB;
846 
847  $query_result = $ilDB->queryF("SELECT question_id, qpl_qst_type.type_tag, qpl_qst_type.plugin FROM qpl_questions, qpl_qst_type WHERE original_id IS NULL AND qpl_questions.tstamp > 0 AND obj_fi = %s AND complete = %s AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id",
848  array('integer','text'),
849  array($this->getId(), 1)
850  );
851  $questions = array();
852  if ($query_result->numRows())
853  {
854  while ($row = $ilDB->fetchAssoc($query_result))
855  {
856  if ($row["plugin"])
857  {
858  if ($this->isPluginActive($row["type_tag"]))
859  {
860  array_push($questions, $row["question_id"]);
861  }
862  }
863  else
864  {
865  array_push($questions, $row["question_id"]);
866  }
867  }
868  }
869  return $questions;
870  }
871 
876  function getImportMapping()
877  {
878  if (!is_array($this->import_mapping))
879  {
880  return array();
881  }
882  else
883  {
884  return $this->import_mapping;
885  }
886  }
887 
895  function toXML($questions)
896  {
897  $xml = "";
898  // export button was pressed
899  if (count($questions) > 0)
900  {
901  foreach ($questions as $key => $value)
902  {
903  $question =& $this->createQuestion("", $value);
904  $xml .= $question->object->toXML();
905  }
906  if (count($questions) > 1)
907  {
908  $xml = preg_replace("/<\/questestinterop>\s*<.xml.*?>\s*<questestinterop>/", "", $xml);
909  }
910  }
911  $xml = preg_replace("/(<\?xml[^>]*?>)/", "\\1" . "<!DOCTYPE questestinterop SYSTEM \"ims_qtiasiv1p2p1.dtd\">", $xml);
912  return $xml;
913  }
914 
923  function _getQuestionCount($questionpool_id, $complete_questions_only = FALSE)
924  {
925  global $ilDB;
926  if ($complete_questions_only)
927  {
928  $result = $ilDB->queryF("SELECT COUNT(question_id) question_count FROM qpl_questions WHERE obj_fi = %s AND qpl_questions.tstamp > 0 AND original_id IS NULL AND complete = %s",
929  array('integer', 'text'),
930  array($questionpool_id, 1)
931  );
932  }
933  else
934  {
935  $result = $ilDB->queryF("SELECT COUNT(question_id) question_count FROM qpl_questions WHERE obj_fi = %s AND qpl_questions.tstamp > 0 AND original_id IS NULL",
936  array('integer'),
937  array($questionpool_id)
938  );
939  }
940  $row = $ilDB->fetchAssoc($result);
941  return $row["question_count"];
942  }
943 
951  function setOnline($a_online_status)
952  {
953  switch ($a_online_status)
954  {
955  case 0:
956  case 1:
957  $this->online = $a_online_status;
958  break;
959  default:
960  $this->online = 0;
961  break;
962  }
963  }
964 
965  function getOnline()
966  {
967  if (strcmp($this->online, "") == 0) $this->online = "0";
968  return $this->online;
969  }
970 
972  {
973  $this->showTaxonomies = $showTaxonomies;
974  }
975 
976  public function getShowTaxonomies()
977  {
978  return $this->showTaxonomies;
979  }
980 
982  {
983  $this->navTaxonomyId = $navTaxonomyId;
984  }
985 
986  public function getNavTaxonomyId()
987  {
988  return $this->navTaxonomyId;
989  }
990 
991  public function isNavTaxonomyActive()
992  {
993  return $this->getShowTaxonomies() && (int)$this->getNavTaxonomyId();
994  }
995 
996  function _lookupOnline($a_obj_id, $is_reference = FALSE)
997  {
998  global $ilDB;
999 
1000  if ($is_reference)
1001  {
1002  $result = $ilDB->queryF("SELECT qpl_questionpool.isonline FROM qpl_questionpool,object_reference WHERE object_reference.ref_id = %s AND object_reference.obj_id = qpl_questionpool.obj_fi",
1003  array('integer'),
1004  array($a_obj_id)
1005  );
1006  }
1007  else
1008  {
1009  $result = $ilDB->queryF("SELECT isonline FROM qpl_questionpool WHERE obj_fi = %s",
1010  array('integer'),
1011  array($a_obj_id)
1012  );
1013  }
1014  if ($result->numRows() == 1)
1015  {
1016  $row = $ilDB->fetchAssoc($result);
1017  return $row["isonline"];
1018  }
1019  return 0;
1020  }
1021 
1028  function _hasEqualPoints($a_obj_id, $is_reference = FALSE)
1029  {
1030  global $ilDB;
1031 
1032  if ($is_reference)
1033  {
1034  $result = $ilDB->queryF("SELECT count(DISTINCT qpl_questions.points) equal_points FROM qpl_questions, object_reference WHERE object_reference.ref_id = %s AND qpl_questions.tstamp > 0 AND object_reference.obj_id = qpl_questions.obj_fi AND qpl_questions.original_id IS NULL",
1035  array('integer'),
1036  array($a_obj_id)
1037  );
1038  }
1039  else
1040  {
1041  $result = $ilDB->queryF("SELECT count(DISTINCT points) equal_points FROM qpl_questions WHERE obj_fi = %s AND qpl_questions.tstamp > 0 AND qpl_questions.original_id IS NULL",
1042  array('integer'),
1043  array($a_obj_id)
1044  );
1045  }
1046  if ($result->numRows() == 1)
1047  {
1048  $row = $ilDB->fetchAssoc($result);
1049  if ($row["equal_points"] == 1)
1050  {
1051  return 1;
1052  }
1053  else
1054  {
1055  return 0;
1056  }
1057  }
1058  return 0;
1059  }
1060 
1067  {
1068  global $ilDB;
1069 
1070  $success = false;
1071  if (array_key_exists("qpl_clipboard", $_SESSION))
1072  {
1073  $success = true;
1074  foreach ($_SESSION["qpl_clipboard"] as $question_object)
1075  {
1076  if (strcmp($question_object["action"], "move") == 0)
1077  {
1078  $result = $ilDB->queryF("SELECT obj_fi FROM qpl_questions WHERE question_id = %s",
1079  array('integer'),
1080  array($question_object["question_id"])
1081  );
1082  if ($result->numRows() == 1)
1083  {
1084  $row = $ilDB->fetchAssoc($result);
1085  $source_questionpool = $row["obj_fi"];
1086  // change the questionpool id in the qpl_questions table
1087  $affectedRows = $ilDB->manipulateF("UPDATE qpl_questions SET obj_fi = %s WHERE question_id = %s",
1088  array('integer','integer'),
1089  array($this->getId(), $question_object["question_id"])
1090  );
1091  if(!$affectedRows)
1092  {
1093  $success = false;
1094  }
1095 
1096  // move question data to the new target directory
1097  $source_path = CLIENT_WEB_DIR . "/assessment/" . $source_questionpool . "/" . $question_object["question_id"] . "/";
1098  if (@is_dir($source_path))
1099  {
1100  $target_path = CLIENT_WEB_DIR . "/assessment/" . $this->getId() . "/";
1101  if (!@is_dir($target_path))
1102  {
1103  include_once "./Services/Utilities/classes/class.ilUtil.php";
1104  ilUtil::makeDirParents($target_path);
1105  }
1106  @rename($source_path, $target_path . $question_object["question_id"]);
1107  }
1108  // update question count of source question pool
1109  ilObjQuestionPool::_updateQuestionCount($source_questionpool);
1110  }
1111  }
1112  else
1113  {
1114  $new_question_id = $this->copyQuestion($question_object["question_id"], $this->getId());
1115  if(!$new_question_id)
1116  {
1117  $success = false;
1118  }
1119  }
1120  }
1121  }
1122  // update question count of question pool
1124  unset($_SESSION["qpl_clipboard"]);
1125 
1126  return (bool)$success;
1127  }
1128 
1135  function copyToClipboard($question_id)
1136  {
1137  if (!array_key_exists("qpl_clipboard", $_SESSION))
1138  {
1139  $_SESSION["qpl_clipboard"] = array();
1140  }
1141  $_SESSION["qpl_clipboard"][$question_id] = array("question_id" => $question_id, "action" => "copy");
1142  }
1143 
1150  function moveToClipboard($question_id)
1151  {
1152  if (!array_key_exists("qpl_clipboard", $_SESSION))
1153  {
1154  $_SESSION["qpl_clipboard"] = array();
1155  }
1156  $_SESSION["qpl_clipboard"][$question_id] = array("question_id" => $question_id, "action" => "move");
1157  }
1158 
1159  public function cleanupClipboard($deletedQuestionId)
1160  {
1161  if( !isset($_SESSION['qpl_clipboard']) )
1162  {
1163  return;
1164  }
1165 
1166  if( !isset($_SESSION['qpl_clipboard'][$deletedQuestionId]) )
1167  {
1168  return;
1169  }
1170 
1171  unset($_SESSION['qpl_clipboard'][$deletedQuestionId]);
1172 
1173  if( !count($_SESSION['qpl_clipboard']) )
1174  {
1175  unset($_SESSION['qpl_clipboard']);
1176  }
1177  }
1178 
1186  function _isWriteable($object_id, $user_id)
1187  {
1188  global $rbacsystem;
1189 
1190  include_once "./Services/Object/classes/class.ilObject.php";
1191  $refs = ilObject::_getAllReferences($object_id);
1192  if (count($refs))
1193  {
1194  foreach ($refs as $ref_id)
1195  {
1196  if ($rbacsystem->checkAccess("write", $ref_id) && (ilObject::_hasUntrashedReference($object_id)))
1197  {
1198  return true;
1199  }
1200  }
1201  }
1202  return false;
1203  }
1204 
1212  function &getQuestionDetails($question_ids)
1213  {
1214  global $ilDB;
1215 
1216  $result = array();
1217  $query_result = $ilDB->query("SELECT qpl_questions.*, qpl_qst_type.type_tag FROM qpl_questions, qpl_qst_type WHERE qpl_questions.question_type_fi = qpl_qst_type.question_type_id AND " . $ilDB->in('qpl_questions.question_id', $question_ids, false, 'integer') . " ORDER BY qpl_questions.title");
1218  if ($query_result->numRows())
1219  {
1220  while ($row = $ilDB->fetchAssoc($query_result))
1221  {
1222  array_push($result, $row);
1223  }
1224  }
1225  return $result;
1226  }
1227 
1236  function &getDeleteableQuestionDetails($question_ids)
1237  {
1238  global $ilDB, $ilLog;
1239 
1240  $result = array();
1241  $query_result = $ilDB->query("SELECT qpl_questions.*, qpl_qst_type.type_tag FROM qpl_questions, qpl_qst_type WHERE qpl_questions.question_type_fi = qpl_qst_type.question_type_id AND " . $ilDB->in('qpl_questions.question_id', $question_ids, false, 'integer') . " ORDER BY qpl_questions.title");
1242  if ($query_result->numRows())
1243  {
1244  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
1245  while ($row = $ilDB->fetchAssoc($query_result))
1246  {
1247  if (!assQuestion::_isUsedInRandomTest($row["question_id"]))
1248  {
1249  array_push($result, $row);
1250  }
1251  else
1252  {
1253  // the question was used in a random test prior to ILIAS 3.7 so it was inserted
1254  // as a reference to the original question pool object and not as a copy. To allow
1255  // the deletion of the question pool object, a copy must be created and all database references
1256  // of the original question must changed with the reference of the copy
1257 
1258  // 1. Create a copy of the original question
1259  $question =& $this->createQuestion("", $row["question_id"]);
1260  $duplicate_id = $question->object->duplicate(true);
1261  if ($duplicate_id > 0)
1262  {
1263  // 2. replace the question id in the solutions
1264  $affectedRows = $ilDB->manipulateF("UPDATE tst_solutions SET question_fi = %s WHERE question_fi = %s",
1265  array('integer','integer'),
1266  array($duplicate_id, $row["question_id"])
1267  );
1268 
1269  // 3. replace the question id in the question list of random tests
1270  $affectedRows = $ilDB->manipulateF("UPDATE tst_test_rnd_qst SET question_fi = %s WHERE question_fi = %s",
1271  array('integer','integer'),
1272  array($duplicate_id, $row["question_id"])
1273  );
1274 
1275  // 4. replace the question id in the test results
1276  $affectedRows = $ilDB->manipulateF("UPDATE tst_test_result SET question_fi = %s WHERE question_fi = %s",
1277  array('integer','integer'),
1278  array($duplicate_id, $row["question_id"])
1279  );
1280 
1281  // 5. replace the question id in the test&assessment log
1282  $affectedRows = $ilDB->manipulateF("UPDATE ass_log SET question_fi = %s WHERE question_fi = %s",
1283  array('integer','integer'),
1284  array($duplicate_id, $row["question_id"])
1285  );
1286 
1287  // 6. The original question can be deleted, so add it to the list of questions
1288  array_push($result, $row);
1289  }
1290  }
1291  }
1292  }
1293  return $result;
1294  }
1295 
1303  {
1304  global $tree;
1305  $path = $tree->getPathFull($ref_id);
1306  $items = array();
1307  $counter = 0;
1308  foreach ($path as $item)
1309  {
1310  if (($counter > 0) && ($counter < count($path)-1))
1311  {
1312  array_push($items, $item["title"]);
1313  }
1314  $counter++;
1315  }
1316  $fullpath = join(" > ", $items);
1317  include_once "./Services/Utilities/classes/class.ilStr.php";
1318  if (strlen($fullpath) > 60)
1319  {
1320  $fullpath = ilStr::subStr($fullpath, 0, 30) . "..." . ilStr::subStr($fullpath, ilStr::strLen($fullpath)-30, 30);
1321  }
1322  return $fullpath;
1323  }
1324 
1331  function &_getAvailableQuestionpools($use_object_id = FALSE, $equal_points = FALSE, $could_be_offline = FALSE, $showPath = FALSE, $with_questioncount = FALSE, $permission = "read", $usr_id = "")
1332  {
1333  global $ilUser, $ilDB, $lng;
1334 
1335  $result_array = array();
1336  $permission = (strlen($permission) == 0) ? "read" : $permission;
1337  $qpls = ilUtil::_getObjectsByOperations("qpl", $permission, (strlen($usr_id)) ? $usr_id : $ilUser->getId(), -1);
1338  $obj_ids = array();
1339  foreach ($qpls as $ref_id)
1340  {
1341  $obj_id = ilObject::_lookupObjId($ref_id);
1342  $obj_ids[$ref_id] = $obj_id;
1343  }
1344  $titles = ilObject::_prepareCloneSelection($qpls, "qpl");
1345  if (count($obj_ids))
1346  {
1347  $in = $ilDB->in('object_data.obj_id', $obj_ids, false, 'integer');
1348  if ($could_be_offline)
1349  {
1350  $result = $ilDB->query("SELECT qpl_questionpool.*, object_data.title FROM qpl_questionpool, object_data WHERE ".
1351  "qpl_questionpool.obj_fi = object_data.obj_id AND $in ORDER BY object_data.title");
1352  }
1353  else
1354  {
1355  $result = $ilDB->queryF("SELECT qpl_questionpool.*, object_data.title FROM qpl_questionpool, object_data WHERE ".
1356  "qpl_questionpool.obj_fi = object_data.obj_id AND $in AND qpl_questionpool.isonline = %s ".
1357  "ORDER BY object_data.title",
1358  array('text'),
1359  array(1)
1360  );
1361  }
1362  while ($row = $ilDB->fetchAssoc($result))
1363  {
1364  $add = TRUE;
1365  if ($equal_points)
1366  {
1367  if (!ilObjQuestionPool::_hasEqualPoints($row["obj_fi"]))
1368  {
1369  $add = FALSE;
1370  }
1371  }
1372  if ($add)
1373  {
1374  $ref_id = array_search($row["obj_fi"], $obj_ids);
1375  $title = (($showPath) ? $titles[$ref_id] : $row["title"]);
1376  if ($with_questioncount)
1377  {
1378  $title .= " [" . $row["questioncount"] . " " . ($row["questioncount"] == 1 ? $lng->txt("ass_question") : $lng->txt("assQuestions")) . "]";
1379  }
1380 
1381  if ($use_object_id)
1382  {
1383  $result_array[$row["obj_fi"]] = array(
1384  'qpl_id' => $row['obj_fi'],
1385  'qpl_title' => $row['title'],
1386  "title" => $title,
1387  "count" => $row["questioncount"]
1388  );
1389  }
1390  else
1391  {
1392  $result_array[$ref_id] = array(
1393  'qpl_id' => $row['obj_fi'],
1394  'qpl_title' => $row['title'],
1395  "title" => $title,
1396  "count" => $row["questioncount"]
1397  );
1398  }
1399  }
1400  }
1401  }
1402  return $result_array;
1403  }
1404 
1405  function &getQplQuestions()
1406  {
1407  global $ilDB;
1408 
1409  $questions = array();
1410  $result = $ilDB->queryF("SELECT qpl_questions.question_id FROM qpl_questions WHERE qpl_questions.original_id IS NULL AND qpl_questions.tstamp > 0 AND qpl_questions.obj_fi = %s",
1411  array('integer'),
1412  array($this->getId())
1413  );
1414  while ($row = $ilDB->fetchAssoc($result))
1415  {
1416  array_push($questions, $row["question_id"]);
1417  }
1418  return $questions;
1419  }
1420 
1426  function cloneObject($a_target_id,$a_copy_id = 0)
1427  {
1428  global $ilLog;
1429 
1430  $newObj = parent::cloneObject($a_target_id,$a_copy_id);
1431 
1432  //copy online status if object is not the root copy object
1433  $cp_options = ilCopyWizardOptions::_getInstance($a_copy_id);
1434 
1435  if(!$cp_options->isRootNode($this->getRefId()))
1436  {
1437  $newObj->setOnline($this->getOnline());
1438  }
1439 
1440  $newObj->setShowTaxonomies($this->getShowTaxonomies());
1441  $newObj->saveToDb();
1442 
1443  // clone the questions in the question pool
1444  $questions =& $this->getQplQuestions();
1445  $questionIdsMap = array();
1446  foreach ($questions as $question_id)
1447  {
1448  $newQuestionId = $newObj->copyQuestion($question_id, $newObj->getId());
1449  $questionIdsMap[$question_id] = $newQuestionId;
1450  }
1451 
1452  // clone meta data
1453  include_once "./Services/MetaData/classes/class.ilMD.php";
1454  $md = new ilMD($this->getId(),0,$this->getType());
1455  $new_md =& $md->cloneMD($newObj->getId(),0,$newObj->getType());
1456 
1457  // update the metadata with the new title of the question pool
1458  $newObj->updateMetaData();
1459 
1460  require_once 'Modules/TestQuestionPool/classes/class.ilQuestionPoolTaxonomiesDuplicator.php';
1461  $duplicator = new ilQuestionPoolTaxonomiesDuplicator();
1462  $duplicator->setSourceObjId($this->getId());
1463  $duplicator->setSourceObjType($this->getType());
1464  $duplicator->setTargetObjId($newObj->getId());
1465  $duplicator->setTargetObjType($newObj->getType());
1466  $duplicator->setQuestionIdMapping($questionIdsMap);
1467  $duplicator->duplicate();
1468 
1469  $duplicatedTaxKeyMap = $duplicator->getDuplicatedTaxonomiesKeysMap();
1470  $newObj->setNavTaxonomyId($duplicatedTaxKeyMap->getMappedTaxonomyId($this->getNavTaxonomyId()));
1471  $newObj->saveToDb();
1472 
1473  return $newObj;
1474  }
1475 
1476  function &getQuestionTypes($all_tags = FALSE, $fixOrder = false)
1477  {
1478  return $this->_getQuestionTypes($all_tags, $fixOrder);
1479  }
1480 
1481  function &_getQuestionTypes($all_tags = FALSE, $fixOrder = false)
1482  {
1483  global $ilDB;
1484  global $lng;
1485 
1486  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
1488  $lng->loadLanguageModule("assessment");
1489  $result = $ilDB->query("SELECT * FROM qpl_qst_type");
1490  $types = array();
1491  while ($row = $ilDB->fetchAssoc($result))
1492  {
1493  if ($all_tags || (!in_array($row["question_type_id"], $forbidden_types)))
1494  {
1495  global $ilLog;
1496 
1497  if ($row["plugin"] == 0)
1498  {
1499  $types[$lng->txt($row["type_tag"])] = $row;
1500  }
1501  else
1502  {
1503  global $ilPluginAdmin;
1504  $pl_names = $ilPluginAdmin->getActivePluginsForSlot(IL_COMP_MODULE, "TestQuestionPool", "qst");
1505  foreach ($pl_names as $pl_name)
1506  {
1507  $pl = ilPlugin::getPluginObject(IL_COMP_MODULE, "TestQuestionPool", "qst", $pl_name);
1508  if (strcmp($pl->getQuestionType(), $row["type_tag"]) == 0)
1509  {
1510  $types[$pl->getQuestionTypeTranslation()] = $row;
1511  }
1512  }
1513  }
1514  }
1515  }
1516 
1517  require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionTypeOrderer.php';
1519  $orderer = new ilAssQuestionTypeOrderer($types, $orderMode);
1520  $types = $orderer->getOrderedTypes();
1521 
1522  return $types;
1523  }
1524 
1525  public static function getQuestionTypeByTypeId($type_id) {
1526  global $ilDB;
1527  $query = "SELECT type_tag FROM qpl_qst_type WHERE question_type_id = %s";
1528  $types = array('integer');
1529  $values = array($type_id);
1530  $result = $ilDB->queryF($query, $types, $values);
1531  if ($row = $ilDB->fetchAssoc($result)) {
1532  return $row['type_tag'];
1533  }
1534  }
1535 
1536  public static function getQuestionTypeTranslations()
1537  {
1538  global $ilDB;
1539  global $lng;
1540  global $ilLog;
1541  global $ilPluginAdmin;
1542 
1543  $lng->loadLanguageModule("assessment");
1544  $result = $ilDB->query("SELECT * FROM qpl_qst_type");
1545  $types = array();
1546  while ($row = $ilDB->fetchAssoc($result))
1547  {
1548  if ($row["plugin"] == 0)
1549  {
1550  $types[$row['type_tag']] = $lng->txt($row["type_tag"]);
1551  }
1552  else
1553  {
1554  $pl_names = $ilPluginAdmin->getActivePluginsForSlot(IL_COMP_MODULE, "TestQuestionPool", "qst");
1555  foreach ($pl_names as $pl_name)
1556  {
1557  $pl = ilPlugin::getPluginObject(IL_COMP_MODULE, "TestQuestionPool", "qst", $pl_name);
1558  if (strcmp($pl->getQuestionType(), $row["type_tag"]) == 0)
1559  {
1560  $types[$row['type_tag']] = $pl->getQuestionTypeTranslation();
1561  }
1562  }
1563  }
1564  }
1565  ksort($types);
1566  return $types;
1567  }
1568 
1574  static function &_getSelfAssessmentQuestionTypes($all_tags = FALSE)
1575  {
1576 /* $allowed_types = array(
1577  "assSingleChoice" => 1,
1578  "assMultipleChoice" => 2,
1579  "assClozeTest" => 3,
1580  "assMatchingQuestion" => 4,
1581  "assOrderingQuestion" => 5,
1582  "assOrderingHorizontal" => 6,
1583  "assImagemapQuestion" => 7,
1584  "assTextQuestion" => 8,
1585  "assTextSubset" => 9,
1586  "assErrorText" => 10
1587  );*/
1588  $allowed_types = array(
1589  "assSingleChoice" => 1,
1590  "assMultipleChoice" => 2,
1591  "assKprimChoice" => 3,
1592  "assClozeTest" => 4,
1593  "assMatchingQuestion" => 5,
1594  "assOrderingQuestion" => 6,
1595  "assOrderingHorizontal" => 7,
1596  "assImagemapQuestion" => 8,
1597  "assTextSubset" => 9,
1598  "assErrorText" => 10
1599  );
1600  $satypes = array();
1601  $qtypes = ilObjQuestionPool::_getQuestionTypes($all_tags);
1602  foreach($qtypes as $k => $t)
1603  {
1604  //if (in_array($t["type_tag"], $allowed_types))
1605  if (isset($allowed_types[$t["type_tag"]]))
1606  {
1607  $t["order"] = $allowed_types[$t["type_tag"]];
1608  $satypes[$k] = $t;
1609  }
1610  }
1611  return $satypes;
1612  }
1613 
1614 
1615  function &getQuestionList()
1616  {
1617  global $ilDB;
1618 
1619  $questions = array();
1620  $result = $ilDB->queryF("SELECT qpl_questions.*, qpl_qst_type.* FROM qpl_questions, qpl_qst_type WHERE qpl_questions.original_id IS NULL AND qpl_questions.obj_fi = %s AND qpl_questions.tstamp > 0 AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id",
1621  array('integer'),
1622  array($this->getId())
1623  );
1624  while ($row = $ilDB->fetchAssoc($result))
1625  {
1626  array_push($questions, $row);
1627  }
1628  return $questions;
1629  }
1630 
1637  public static function _updateQuestionCount($object_id)
1638  {
1639  global $ilDB;
1640  $result = $ilDB->manipulateF("UPDATE qpl_questionpool SET questioncount = %s, tstamp = %s WHERE obj_fi = %s",
1641  array('integer','integer','integer'),
1642  array(ilObjQuestionPool::_getQuestionCount($object_id, TRUE), time(), $object_id)
1643  );
1644  }
1645 
1652  function isPluginActive($a_pname)
1653  {
1654  global $ilPluginAdmin;
1655  if ($ilPluginAdmin->isActive(IL_COMP_MODULE, "TestQuestionPool", "qst", $a_pname))
1656  {
1657  return TRUE;
1658  }
1659  else
1660  {
1661  return FALSE;
1662  }
1663  }
1664 
1665  /*
1666  * Remove all questions with owner = 0
1667  */
1668  public function purgeQuestions()
1669  {
1670  global $ilDB, $ilUser;
1671 
1672  require_once 'Modules/TestQuestionPool/classes/class.ilAssIncompleteQuestionPurger.php';
1673  $incompleteQuestionPurger = new ilAssIncompleteQuestionPurger($ilDB);
1674  $incompleteQuestionPurger->setOwnerId($ilUser->getId());
1675  $incompleteQuestionPurger->purge();
1676  }
1677 
1683  public function getTaxonomyIds()
1684  {
1685  require_once 'Services/Taxonomy/classes/class.ilObjTaxonomy.php';
1686  return ilObjTaxonomy::getUsageOfObject( $this->getId() );
1687  }
1688 
1689 } // END class.ilObjQuestionPool
1690 ?>