ILIAS  Release_4_4_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 
187  function initDefaultRoles()
188  {
189  return array();
190  }
191 
205  function notify($a_event,$a_ref_id,$a_parent_non_rbac_id,$a_node_id,$a_params = 0)
206  {
207  global $tree;
208 
209  switch ($a_event)
210  {
211  case "link":
212 
213  //var_dump("<pre>",$a_params,"</pre>");
214  //echo "Module name ".$this->getRefId()." triggered by link event. Objects linked into target object ref_id: ".$a_ref_id;
215  //exit;
216  break;
217 
218  case "cut":
219 
220  //echo "Module name ".$this->getRefId()." triggered by cut event. Objects are removed from target object ref_id: ".$a_ref_id;
221  //exit;
222  break;
223 
224  case "copy":
225 
226  //var_dump("<pre>",$a_params,"</pre>");
227  //echo "Module name ".$this->getRefId()." triggered by copy event. Objects are copied into target object ref_id: ".$a_ref_id;
228  //exit;
229  break;
230 
231  case "paste":
232 
233  //echo "Module name ".$this->getRefId()." triggered by paste (cut) event. Objects are pasted into target object ref_id: ".$a_ref_id;
234  //exit;
235  break;
236 
237  case "new":
238 
239  //echo "Module name ".$this->getRefId()." triggered by paste (new) event. Objects are applied to target object ref_id: ".$a_ref_id;
240  //exit;
241  break;
242  }
243 
244  // At the beginning of the recursive process it avoids second call of the notify function with the same parameter
245  if ($a_node_id==$_GET["ref_id"])
246  {
247  $parent_obj =& $this->ilias->obj_factory->getInstanceByRefId($a_node_id);
248  $parent_type = $parent_obj->getType();
249  if($parent_type == $this->getType())
250  {
251  $a_node_id = (int) $tree->getParentId($a_node_id);
252  }
253  }
254 
255  parent::notify($a_event,$a_ref_id,$a_parent_non_rbac_id,$a_node_id,$a_params);
256  }
257 
264  function deleteQuestion($question_id)
265  {
266  include_once "./Modules/Test/classes/class.ilObjTest.php";
267  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
268 
269  $question = assQuestion::_instanciateQuestion($question_id);
270  $this->addQuestionChangeListeners($question);
271  $question->delete($question_id);
272  }
273 
277  public function addQuestionChangeListeners(assQuestion $question)
278  {
279  global $ilDB;
280 
281  foreach(ilObjTest::getPoolQuestionChangeListeners($ilDB, $this->getId()) as $listener)
282  {
283  $question->addQuestionChangeListener($listener);
284  }
285  }
286 
292  function loadFromDb()
293  {
294  global $ilDB;
295 
296  $result = $ilDB->queryF("SELECT * FROM qpl_questionpool WHERE obj_fi = %s",
297  array('integer'),
298  array($this->getId())
299  );
300  if ($result->numRows() == 1)
301  {
302  $row = $ilDB->fetchAssoc($result);
303  $this->setOnline($row['isonline']);
304  $this->setShowTaxonomies($row['show_taxonomies']);
305  $this->setNavTaxonomyId($row['nav_taxonomy']);
306  }
307  }
308 
314  function saveToDb()
315  {
316  global $ilDB;
317 
318  $result = $ilDB->queryF("SELECT id_questionpool FROM qpl_questionpool WHERE obj_fi = %s",
319  array('integer'),
320  array($this->getId())
321  );
322 
323  if ($result->numRows() == 1)
324  {
325  $result = $ilDB->update('qpl_questionpool',
326  array(
327  'isonline' => array('text', $this->getOnline()),
328  'show_taxonomies' => array('integer', (int)$this->getShowTaxonomies()),
329  'nav_taxonomy' => array('integer', (int)$this->getNavTaxonomyId()),
330  'tstamp' => array('integer', time())
331  ),
332  array(
333  'obj_fi' => array('integer', $this->getId())
334  )
335  );
336  }
337  else
338  {
339  $next_id = $ilDB->nextId('qpl_questionpool');
340 
341  $result = $ilDB->insert('qpl_questionpool', array(
342  'id_questionpool' => array('integer', $next_id),
343  'isonline' => array('text', $this->getOnline()),
344  'show_taxonomies' => array('integer', (int)$this->getShowTaxonomies()),
345  'nav_taxonomy' => array('integer', (int)$this->getNavTaxonomyId()),
346  'tstamp' => array('integer', time()),
347  'obj_fi' => array('integer', $this->getId())
348  ));
349  }
350  }
351 
359  function getQuestiontype($question_id)
360  {
361  global $ilDB;
362 
363  if ($question_id < 1)
364  {
365  return;
366  }
367 
368  $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",
369  array('integer'),
370  array($question_id)
371  );
372  if ($result->numRows() == 1)
373  {
374  $data = $ilDB->fetchAssoc($result);
375  return $data["type_tag"];
376  }
377  else
378  {
379  return;
380  }
381  }
382 
388  function getDescription()
389  {
390  return parent::getDescription();
391  }
392 
396  function setDescription($a_description)
397  {
398  parent::setDescription($a_description);
399  }
400 
406  function getTitle()
407  {
408  return parent::getTitle();
409  }
410 
414  function setTitle($a_title)
415  {
416  parent::setTitle($a_title);
417  }
418 
426  function isInUse($question_id)
427  {
428  global $ilDB;
429 
430  $result = $ilDB->queryF("SELECT COUNT(solution_id) solution_count FROM tst_solutions WHERE question_fi = %s",
431  array('integer'),
432  array($question_id)
433  );
434  $row = $ilDB->fetchAssoc($result);
435  return $row["solution_count"];
436  }
437 
438  function &createQuestion($question_type, $question_id = -1)
439  {
440  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
441  if ($question_id > 0) return assQuestion::_instanciateQuestionGUI($question_id);
442  assQuestion::_includeClass($question_type, 1);
443  $question_type_gui = $question_type . "GUI";
444  $question_gui =& new $question_type_gui();
445  return $question_gui;
446  }
447 
454  function duplicateQuestion($question_id)
455  {
456  $question =& $this->createQuestion("", $question_id);
457  $newtitle = $question->object->getTitle();
458  if ($question->object->questionTitleExists($this->getId(), $question->object->getTitle()))
459  {
460  $counter = 2;
461  while ($question->object->questionTitleExists($this->getId(), $question->object->getTitle() . " ($counter)"))
462  {
463  $counter++;
464  }
465  $newtitle = $question->object->getTitle() . " ($counter)";
466  }
467  $new_id = $question->object->duplicate(false, $newtitle);
468  // update question count of question pool
470  return $new_id;
471  }
472 
480  function copyQuestion($question_id, $questionpool_to)
481  {
482  $question_gui =& $this->createQuestion("", $question_id);
483  if ($question_gui->object->getObjId() == $questionpool_to)
484  {
485  // the question is copied into the same question pool
486  return $this->duplicateQuestion($question_id);
487  }
488  else
489  {
490  // the question is copied into another question pool
491  $newtitle = $question_gui->object->getTitle();
492  if ($question_gui->object->questionTitleExists($this->getId(), $question_gui->object->getTitle()))
493  {
494  $counter = 2;
495  while ($question_gui->object->questionTitleExists($this->getId(), $question_gui->object->getTitle() . " ($counter)"))
496  {
497  $counter++;
498  }
499  $newtitle = $question_gui->object->getTitle() . " ($counter)";
500  }
501  return $question_gui->object->copyObject($this->getId(), $newtitle);
502  }
503  }
504 
510  public function getPrintviewQuestions()
511  {
512  global $ilDB;
513 
514  $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",
515  array('integer'),
516  array($this->getId())
517  );
518  $rows = array();
519  $types = $this->getQuestionTypeTranslations();
520  if ($query_result->numRows())
521  {
522  while ($row = $ilDB->fetchAssoc($query_result))
523  {
524  $row['ttype'] = $types[$row['type_tag']];
525  if ($row["plugin"])
526  {
527  if ($this->isPluginActive($row["type_tag"]))
528  {
529  array_push($rows, $row);
530  }
531  }
532  else
533  {
534  array_push($rows, $row);
535  }
536  }
537  }
538  return $rows;
539  }
540 
547  function exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog, $questions)
548  {
549  global $ilBench;
550 
551  $this->mob_ids = array();
552  $this->file_ids = array();
553 
554  $attrs = array();
555  $attrs["Type"] = "Questionpool_Test";
556  $a_xml_writer->xmlStartTag("ContentObject", $attrs);
557 
558  // MetaData
559  $this->exportXMLMetaData($a_xml_writer);
560 
561  // PageObjects
562  $expLog->write(date("[y-m-d H:i:s] ")."Start Export Page Objects");
563  $ilBench->start("ContentObjectExport", "exportPageObjects");
564  $this->exportXMLPageObjects($a_xml_writer, $a_inst, $expLog, $questions);
565  $ilBench->stop("ContentObjectExport", "exportPageObjects");
566  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export Page Objects");
567 
568  // MediaObjects
569  $expLog->write(date("[y-m-d H:i:s] ")."Start Export Media Objects");
570  $ilBench->start("ContentObjectExport", "exportMediaObjects");
571  $this->exportXMLMediaObjects($a_xml_writer, $a_inst, $a_target_dir, $expLog);
572  $ilBench->stop("ContentObjectExport", "exportMediaObjects");
573  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export Media Objects");
574 
575  // FileItems
576  $expLog->write(date("[y-m-d H:i:s] ")."Start Export File Items");
577  $ilBench->start("ContentObjectExport", "exportFileItems");
578  $this->exportFileItems($a_target_dir, $expLog);
579  $ilBench->stop("ContentObjectExport", "exportFileItems");
580  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export File Items");
581 
582  $a_xml_writer->xmlEndTag("ContentObject");
583  }
584 
591  function exportXMLMetaData(&$a_xml_writer)
592  {
593  include_once("Services/MetaData/classes/class.ilMD2XML.php");
594  $md2xml = new ilMD2XML($this->getId(), 0, $this->getType());
595  $md2xml->setExportMode(true);
596  $md2xml->startExport();
597  $a_xml_writer->appendXML($md2xml->getXML());
598  }
599 
600  function modifyExportIdentifier($a_tag, $a_param, $a_value)
601  {
602  if ($a_tag == "Identifier" && $a_param == "Entry")
603  {
604  include_once "./Services/Utilities/classes/class.ilUtil.php";
605  $a_value = ilUtil::insertInstIntoID($a_value);
606  }
607 
608  return $a_value;
609  }
610 
611 
618  function exportXMLPageObjects(&$a_xml_writer, $a_inst, &$expLog, $questions)
619  {
620  global $ilBench;
621 
622  include_once "./Modules/LearningModule/classes/class.ilLMPageObject.php";
623 
624  foreach ($questions as $question_id)
625  {
626  $ilBench->start("ContentObjectExport", "exportPageObject");
627  $expLog->write(date("[y-m-d H:i:s] ")."Page Object ".$question_id);
628 
629  $attrs = array();
630  $a_xml_writer->xmlStartTag("PageObject", $attrs);
631 
632 
633  // export xml to writer object
634  $ilBench->start("ContentObjectExport", "exportPageObject_XML");
635  include_once("./Modules/TestQuestionPool/classes/class.ilAssQuestionPage.php");
636  $page_object = new ilAssQuestionPage($question_id);
637  $page_object->buildDom();
638  $page_object->insertInstIntoIDs($a_inst);
639  $mob_ids = $page_object->collectMediaObjects(false);
640  require_once 'Services/COPage/classes/class.ilPCFileList.php';
641  $file_ids = ilPCFileList::collectFileItems($page_object, $page_object->getDomDoc());
642  $xml = $page_object->getXMLFromDom(false, false, false, "", true);
643  $xml = str_replace("&","&amp;", $xml);
644  $a_xml_writer->appendXML($xml);
645  $page_object->freeDom();
646  unset ($page_object);
647 
648  $ilBench->stop("ContentObjectExport", "exportPageObject_XML");
649 
650  // collect media objects
651  $ilBench->start("ContentObjectExport", "exportPageObject_CollectMedia");
652  //$mob_ids = $page_obj->getMediaObjectIDs();
653  foreach($mob_ids as $mob_id)
654  {
655  $this->mob_ids[$mob_id] = $mob_id;
656  }
657  $ilBench->stop("ContentObjectExport", "exportPageObject_CollectMedia");
658 
659  // collect all file items
660  $ilBench->start("ContentObjectExport", "exportPageObject_CollectFileItems");
661  //$file_ids = $page_obj->getFileItemIds();
662  foreach($file_ids as $file_id)
663  {
664  $this->file_ids[$file_id] = $file_id;
665  }
666  $ilBench->stop("ContentObjectExport", "exportPageObject_CollectFileItems");
667 
668  $a_xml_writer->xmlEndTag("PageObject");
669  //unset($page_obj);
670 
671  $ilBench->stop("ContentObjectExport", "exportPageObject");
672 
673 
674  }
675  }
676 
683  function exportXMLMediaObjects(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
684  {
685  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
686 
687  foreach ($this->mob_ids as $mob_id)
688  {
689  $expLog->write(date("[y-m-d H:i:s] ")."Media Object ".$mob_id);
690  if (ilObjMediaObject::_exists($mob_id))
691  {
692  $media_obj = new ilObjMediaObject($mob_id);
693  $media_obj->exportXML($a_xml_writer, $a_inst);
694  $media_obj->exportFiles($a_target_dir);
695  unset($media_obj);
696  }
697  }
698  }
699 
704  function exportFileItems($a_target_dir, &$expLog)
705  {
706  include_once("./Modules/File/classes/class.ilObjFile.php");
707 
708  foreach ($this->file_ids as $file_id)
709  {
710  $expLog->write(date("[y-m-d H:i:s] ")."File Item ".$file_id);
711  $file_obj = new ilObjFile($file_id, false);
712  $file_obj->export($a_target_dir);
713  unset($file_obj);
714  }
715  }
716 
723  {
724  include_once "./Services/Utilities/classes/class.ilUtil.php";
725  $qpl_data_dir = ilUtil::getDataDir()."/qpl_data";
726  ilUtil::makeDir($qpl_data_dir);
727  if(!is_writable($qpl_data_dir))
728  {
729  $this->ilias->raiseError("Questionpool Data Directory (".$qpl_data_dir
730  .") not writeable.",$this->ilias->error_obj->FATAL);
731  }
732 
733  // create learning module directory (data_dir/lm_data/lm_<id>)
734  $qpl_dir = $qpl_data_dir."/qpl_".$this->getId();
735  ilUtil::makeDir($qpl_dir);
736  if(!@is_dir($qpl_dir))
737  {
738  $this->ilias->raiseError("Creation of Questionpool Directory failed.",$this->ilias->error_obj->FATAL);
739  }
740  // create Export subdirectory (data_dir/lm_data/lm_<id>/Export)
741  ilUtil::makeDir($this->getExportDirectory('xls'));
742  if(!@is_dir($this->getExportDirectory('xls')))
743  {
744  $this->ilias->raiseError("Creation of Export Directory failed.",$this->ilias->error_obj->FATAL);
745  }
746  ilUtil::makeDir($this->getExportDirectory('zip'));
747  if(!@is_dir($this->getExportDirectory('zip')))
748  {
749  $this->ilias->raiseError("Creation of Export Directory failed.",$this->ilias->error_obj->FATAL);
750  }
751  }
752 
756  function getExportDirectory($type = "")
757  {
758  include_once "./Services/Utilities/classes/class.ilUtil.php";
759  switch ($type)
760  {
761  case 'xls':
762  case 'zip':
763  $export_dir = ilUtil::getDataDir()."/qpl_data"."/qpl_".$this->getId()."/export_$type";
764  break;
765  default:
766  $export_dir = ilUtil::getDataDir()."/qpl_data"."/qpl_".$this->getId()."/export";
767  break;
768  }
769  return $export_dir;
770  }
771 
777  static function _createImportDirectory()
778  {
779  global $ilias;
780 
781  include_once "./Services/Utilities/classes/class.ilUtil.php";
782  $qpl_data_dir = ilUtil::getDataDir()."/qpl_data";
783  ilUtil::makeDir($qpl_data_dir);
784 
785  if(!is_writable($qpl_data_dir))
786  {
787  $ilias->raiseError("Questionpool Data Directory (".$qpl_data_dir
788  .") not writeable.",$ilias->error_obj->FATAL);
789  }
790 
791  // create questionpool directory (data_dir/qpl_data/qpl_import)
792  $qpl_dir = $qpl_data_dir."/qpl_import";
793  ilUtil::makeDir($qpl_dir);
794  if(!@is_dir($qpl_dir))
795  {
796  $ilias->raiseError("Creation of Questionpool Directory failed.",$ilias->error_obj->FATAL);
797  }
798  return $qpl_dir;
799  }
800 
804  function _setImportDirectory($a_import_dir = null)
805  {
806  if (strlen($a_import_dir))
807  {
808  $_SESSION["qpl_import_dir"] = $a_import_dir;
809  }
810  else
811  {
812  unset($_SESSION["qpl_import_dir"]);
813  }
814  }
815 
820  {
821  if (strlen($_SESSION["qpl_import_dir"]))
822  {
823  return $_SESSION["qpl_import_dir"];
824  }
825  return null;
826  }
827 
829  {
831  }
832 
838  function &getAllQuestions()
839  {
840  global $ilDB;
841 
842  $result = $ilDB->queryF("SELECT question_id FROM qpl_questions WHERE obj_fi = %s AND qpl_questions.tstamp > 0 AND original_id IS NULL",
843  array('integer'),
844  array($this->getId())
845  );
846  $questions = array();
847  while ($row = $ilDB->fetchAssoc($result))
848  {
849  array_push($questions, $row["question_id"]);
850  }
851  return $questions;
852  }
853 
854  function &getAllQuestionIds()
855  {
856  global $ilDB;
857 
858  $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",
859  array('integer','text'),
860  array($this->getId(), 1)
861  );
862  $questions = array();
863  if ($query_result->numRows())
864  {
865  while ($row = $ilDB->fetchAssoc($query_result))
866  {
867  if ($row["plugin"])
868  {
869  if ($this->isPluginActive($row["type_tag"]))
870  {
871  array_push($questions, $row["question_id"]);
872  }
873  }
874  else
875  {
876  array_push($questions, $row["question_id"]);
877  }
878  }
879  }
880  return $questions;
881  }
882 
887  function getImportMapping()
888  {
889  if (!is_array($this->import_mapping))
890  {
891  return array();
892  }
893  else
894  {
895  return $this->import_mapping;
896  }
897  }
898 
906  function toXML($questions)
907  {
908  $xml = "";
909  // export button was pressed
910  if (count($questions) > 0)
911  {
912  foreach ($questions as $key => $value)
913  {
914  $question =& $this->createQuestion("", $value);
915  $xml .= $question->object->toXML();
916  }
917  if (count($questions) > 1)
918  {
919  $xml = preg_replace("/<\/questestinterop>\s*<.xml.*?>\s*<questestinterop>/", "", $xml);
920  }
921  }
922  $xml = preg_replace("/(<\?xml[^>]*?>)/", "\\1" . "<!DOCTYPE questestinterop SYSTEM \"ims_qtiasiv1p2p1.dtd\">", $xml);
923  return $xml;
924  }
925 
934  function _getQuestionCount($questionpool_id, $complete_questions_only = FALSE)
935  {
936  global $ilDB;
937  if ($complete_questions_only)
938  {
939  $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",
940  array('integer', 'text'),
941  array($questionpool_id, 1)
942  );
943  }
944  else
945  {
946  $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",
947  array('integer'),
948  array($questionpool_id)
949  );
950  }
951  $row = $ilDB->fetchAssoc($result);
952  return $row["question_count"];
953  }
954 
962  function setOnline($a_online_status)
963  {
964  switch ($a_online_status)
965  {
966  case 0:
967  case 1:
968  $this->online = $a_online_status;
969  break;
970  default:
971  $this->online = 0;
972  break;
973  }
974  }
975 
976  function getOnline()
977  {
978  if (strcmp($this->online, "") == 0) $this->online = "0";
979  return $this->online;
980  }
981 
983  {
984  $this->showTaxonomies = $showTaxonomies;
985  }
986 
987  public function getShowTaxonomies()
988  {
989  return $this->showTaxonomies;
990  }
991 
993  {
994  $this->navTaxonomyId = $navTaxonomyId;
995  }
996 
997  public function getNavTaxonomyId()
998  {
999  return $this->navTaxonomyId;
1000  }
1001 
1002  public function isNavTaxonomyActive()
1003  {
1004  return $this->getShowTaxonomies() && (int)$this->getNavTaxonomyId();
1005  }
1006 
1007  function _lookupOnline($a_obj_id, $is_reference = FALSE)
1008  {
1009  global $ilDB;
1010 
1011  if ($is_reference)
1012  {
1013  $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",
1014  array('integer'),
1015  array($a_obj_id)
1016  );
1017  }
1018  else
1019  {
1020  $result = $ilDB->queryF("SELECT isonline FROM qpl_questionpool WHERE obj_fi = %s",
1021  array('integer'),
1022  array($a_obj_id)
1023  );
1024  }
1025  if ($result->numRows() == 1)
1026  {
1027  $row = $ilDB->fetchAssoc($result);
1028  return $row["isonline"];
1029  }
1030  return 0;
1031  }
1032 
1039  function _hasEqualPoints($a_obj_id, $is_reference = FALSE)
1040  {
1041  global $ilDB;
1042 
1043  if ($is_reference)
1044  {
1045  $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",
1046  array('integer'),
1047  array($a_obj_id)
1048  );
1049  }
1050  else
1051  {
1052  $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",
1053  array('integer'),
1054  array($a_obj_id)
1055  );
1056  }
1057  if ($result->numRows() == 1)
1058  {
1059  $row = $ilDB->fetchAssoc($result);
1060  if ($row["equal_points"] == 1)
1061  {
1062  return 1;
1063  }
1064  else
1065  {
1066  return 0;
1067  }
1068  }
1069  return 0;
1070  }
1071 
1078  {
1079  global $ilDB;
1080 
1081  $success = false;
1082  if (array_key_exists("qpl_clipboard", $_SESSION))
1083  {
1084  $success = true;
1085  foreach ($_SESSION["qpl_clipboard"] as $question_object)
1086  {
1087  if (strcmp($question_object["action"], "move") == 0)
1088  {
1089  $result = $ilDB->queryF("SELECT obj_fi FROM qpl_questions WHERE question_id = %s",
1090  array('integer'),
1091  array($question_object["question_id"])
1092  );
1093  if ($result->numRows() == 1)
1094  {
1095  $row = $ilDB->fetchAssoc($result);
1096  $source_questionpool = $row["obj_fi"];
1097  // change the questionpool id in the qpl_questions table
1098  $affectedRows = $ilDB->manipulateF("UPDATE qpl_questions SET obj_fi = %s WHERE question_id = %s",
1099  array('integer','integer'),
1100  array($this->getId(), $question_object["question_id"])
1101  );
1102  if(!$affectedRows)
1103  {
1104  $success = false;
1105  }
1106 
1107  // move question data to the new target directory
1108  $source_path = CLIENT_WEB_DIR . "/assessment/" . $source_questionpool . "/" . $question_object["question_id"] . "/";
1109  if (@is_dir($source_path))
1110  {
1111  $target_path = CLIENT_WEB_DIR . "/assessment/" . $this->getId() . "/";
1112  if (!@is_dir($target_path))
1113  {
1114  include_once "./Services/Utilities/classes/class.ilUtil.php";
1115  ilUtil::makeDirParents($target_path);
1116  }
1117  @rename($source_path, $target_path . $question_object["question_id"]);
1118  }
1119  // update question count of source question pool
1120  ilObjQuestionPool::_updateQuestionCount($source_questionpool);
1121  }
1122  }
1123  else
1124  {
1125  $new_question_id = $this->copyQuestion($question_object["question_id"], $this->getId());
1126  if(!$new_question_id)
1127  {
1128  $success = false;
1129  }
1130  }
1131  }
1132  }
1133  // update question count of question pool
1135  unset($_SESSION["qpl_clipboard"]);
1136 
1137  return (bool)$success;
1138  }
1139 
1146  function copyToClipboard($question_id)
1147  {
1148  if (!array_key_exists("qpl_clipboard", $_SESSION))
1149  {
1150  $_SESSION["qpl_clipboard"] = array();
1151  }
1152  $_SESSION["qpl_clipboard"][$question_id] = array("question_id" => $question_id, "action" => "copy");
1153  }
1154 
1161  function moveToClipboard($question_id)
1162  {
1163  if (!array_key_exists("qpl_clipboard", $_SESSION))
1164  {
1165  $_SESSION["qpl_clipboard"] = array();
1166  }
1167  $_SESSION["qpl_clipboard"][$question_id] = array("question_id" => $question_id, "action" => "move");
1168  }
1169 
1170  public function cleanupClipboard($deletedQuestionId)
1171  {
1172  if( !isset($_SESSION['qpl_clipboard']) )
1173  {
1174  return;
1175  }
1176 
1177  if( !isset($_SESSION['qpl_clipboard'][$deletedQuestionId]) )
1178  {
1179  return;
1180  }
1181 
1182  unset($_SESSION['qpl_clipboard'][$deletedQuestionId]);
1183 
1184  if( !count($_SESSION['qpl_clipboard']) )
1185  {
1186  unset($_SESSION['qpl_clipboard']);
1187  }
1188  }
1189 
1197  function _isWriteable($object_id, $user_id)
1198  {
1199  global $rbacsystem;
1200 
1201  include_once "./Services/Object/classes/class.ilObject.php";
1202  $refs = ilObject::_getAllReferences($object_id);
1203  if (count($refs))
1204  {
1205  foreach ($refs as $ref_id)
1206  {
1207  if ($rbacsystem->checkAccess("write", $ref_id) && (ilObject::_hasUntrashedReference($object_id)))
1208  {
1209  return true;
1210  }
1211  }
1212  }
1213  return false;
1214  }
1215 
1223  function &getQuestionDetails($question_ids)
1224  {
1225  global $ilDB;
1226 
1227  $result = array();
1228  $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");
1229  if ($query_result->numRows())
1230  {
1231  while ($row = $ilDB->fetchAssoc($query_result))
1232  {
1233  array_push($result, $row);
1234  }
1235  }
1236  return $result;
1237  }
1238 
1247  function &getDeleteableQuestionDetails($question_ids)
1248  {
1249  global $ilDB, $ilLog;
1250 
1251  $result = array();
1252  $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");
1253  if ($query_result->numRows())
1254  {
1255  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
1256  while ($row = $ilDB->fetchAssoc($query_result))
1257  {
1258  if (!assQuestion::_isUsedInRandomTest($row["question_id"]))
1259  {
1260  array_push($result, $row);
1261  }
1262  else
1263  {
1264  // the question was used in a random test prior to ILIAS 3.7 so it was inserted
1265  // as a reference to the original question pool object and not as a copy. To allow
1266  // the deletion of the question pool object, a copy must be created and all database references
1267  // of the original question must changed with the reference of the copy
1268 
1269  // 1. Create a copy of the original question
1270  $question =& $this->createQuestion("", $row["question_id"]);
1271  $duplicate_id = $question->object->duplicate(true);
1272  if ($duplicate_id > 0)
1273  {
1274  // 2. replace the question id in the solutions
1275  $affectedRows = $ilDB->manipulateF("UPDATE tst_solutions SET question_fi = %s WHERE question_fi = %s",
1276  array('integer','integer'),
1277  array($duplicate_id, $row["question_id"])
1278  );
1279 
1280  // 3. replace the question id in the question list of random tests
1281  $affectedRows = $ilDB->manipulateF("UPDATE tst_test_rnd_qst SET question_fi = %s WHERE question_fi = %s",
1282  array('integer','integer'),
1283  array($duplicate_id, $row["question_id"])
1284  );
1285 
1286  // 4. replace the question id in the test results
1287  $affectedRows = $ilDB->manipulateF("UPDATE tst_test_result SET question_fi = %s WHERE question_fi = %s",
1288  array('integer','integer'),
1289  array($duplicate_id, $row["question_id"])
1290  );
1291 
1292  // 5. replace the question id in the test&assessment log
1293  $affectedRows = $ilDB->manipulateF("UPDATE ass_log SET question_fi = %s WHERE question_fi = %s",
1294  array('integer','integer'),
1295  array($duplicate_id, $row["question_id"])
1296  );
1297 
1298  // 6. The original question can be deleted, so add it to the list of questions
1299  array_push($result, $row);
1300  }
1301  }
1302  }
1303  }
1304  return $result;
1305  }
1306 
1314  {
1315  global $tree;
1316  $path = $tree->getPathFull($ref_id);
1317  $items = array();
1318  $counter = 0;
1319  foreach ($path as $item)
1320  {
1321  if (($counter > 0) && ($counter < count($path)-1))
1322  {
1323  array_push($items, $item["title"]);
1324  }
1325  $counter++;
1326  }
1327  $fullpath = join(" > ", $items);
1328  include_once "./Services/Utilities/classes/class.ilStr.php";
1329  if (strlen($fullpath) > 60)
1330  {
1331  $fullpath = ilStr::subStr($fullpath, 0, 30) . "..." . ilStr::subStr($fullpath, ilStr::strLen($fullpath)-30, 30);
1332  }
1333  return $fullpath;
1334  }
1335 
1342  function &_getAvailableQuestionpools($use_object_id = FALSE, $equal_points = FALSE, $could_be_offline = FALSE, $showPath = FALSE, $with_questioncount = FALSE, $permission = "read", $usr_id = "")
1343  {
1344  global $ilUser;
1345  global $ilDB;
1346 
1347  $result_array = array();
1348  $permission = (strlen($permission) == 0) ? "read" : $permission;
1349  $qpls = ilUtil::_getObjectsByOperations("qpl", $permission, (strlen($usr_id)) ? $usr_id : $ilUser->getId(), -1);
1350  $obj_ids = array();
1351  foreach ($qpls as $ref_id)
1352  {
1353  $obj_id = ilObject::_lookupObjId($ref_id);
1354  $obj_ids[$ref_id] = $obj_id;
1355  }
1356  $titles = ilObject::_prepareCloneSelection($qpls, "qpl");
1357  if (count($obj_ids))
1358  {
1359  $in = $ilDB->in('object_data.obj_id', $obj_ids, false, 'integer');
1360  if ($could_be_offline)
1361  {
1362  $result = $ilDB->query("SELECT qpl_questionpool.*, object_data.title FROM qpl_questionpool, object_data WHERE ".
1363  "qpl_questionpool.obj_fi = object_data.obj_id AND $in ORDER BY object_data.title");
1364  }
1365  else
1366  {
1367  $result = $ilDB->queryF("SELECT qpl_questionpool.*, object_data.title FROM qpl_questionpool, object_data WHERE ".
1368  "qpl_questionpool.obj_fi = object_data.obj_id AND $in AND qpl_questionpool.isonline = %s ".
1369  "ORDER BY object_data.title",
1370  array('text'),
1371  array(1)
1372  );
1373  }
1374  while ($row = $ilDB->fetchAssoc($result))
1375  {
1376  $add = TRUE;
1377  if ($equal_points)
1378  {
1379  if (!ilObjQuestionPool::_hasEqualPoints($row["obj_fi"]))
1380  {
1381  $add = FALSE;
1382  }
1383  }
1384  if ($add)
1385  {
1386  $ref_id = array_search($row["obj_fi"], $obj_ids);
1387  $title = (($showPath) ? $titles[$ref_id] : $row["title"]);
1388  if ($with_questioncount)
1389  {
1390  $title .= " [" . $row["questioncount"] . " " . ($row["questioncount"] == 1 ? $this->lng->txt("ass_question") : $this->lng->txt("assQuestions")) . "]";
1391  }
1392 
1393  if ($use_object_id)
1394  {
1395  $result_array[$row["obj_fi"]] = array(
1396  'qpl_id' => $row['obj_fi'],
1397  'qpl_title' => $row['title'],
1398  "title" => $title,
1399  "count" => $row["questioncount"]
1400  );
1401  }
1402  else
1403  {
1404  $result_array[$ref_id] = array(
1405  'qpl_id' => $row['obj_fi'],
1406  'qpl_title' => $row['title'],
1407  "title" => $title,
1408  "count" => $row["questioncount"]
1409  );
1410  }
1411  }
1412  }
1413  }
1414  return $result_array;
1415  }
1416 
1417  function &getQplQuestions()
1418  {
1419  global $ilDB;
1420 
1421  $questions = array();
1422  $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",
1423  array('integer'),
1424  array($this->getId())
1425  );
1426  while ($row = $ilDB->fetchAssoc($result))
1427  {
1428  array_push($questions, $row["question_id"]);
1429  }
1430  return $questions;
1431  }
1432 
1438  function cloneObject($a_target_id,$a_copy_id = 0)
1439  {
1440  global $ilLog;
1441  $newObj = parent::cloneObject($a_target_id,$a_copy_id);
1442  $newObj->setOnline($this->getOnline());
1443  $newObj->saveToDb();
1444  // clone the questions in the question pool
1445  $questions =& $this->getQplQuestions();
1446  foreach ($questions as $question_id)
1447  {
1448  $newObj->copyQuestion($question_id, $newObj->getId());
1449  }
1450 
1451  // clone meta data
1452  include_once "./Services/MetaData/classes/class.ilMD.php";
1453  $md = new ilMD($this->getId(),0,$this->getType());
1454  $new_md =& $md->cloneMD($newObj->getId(),0,$newObj->getType());
1455 
1456  // update the metadata with the new title of the question pool
1457  $newObj->updateMetaData();
1458  return $newObj;
1459  }
1460 
1461  function &getQuestionTypes($all_tags = FALSE, $fixOrder = false)
1462  {
1463  return $this->_getQuestionTypes($all_tags, $fixOrder);
1464  }
1465 
1466  function &_getQuestionTypes($all_tags = FALSE, $fixOrder = false)
1467  {
1468  global $ilDB;
1469  global $lng;
1470 
1471  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
1473  $lng->loadLanguageModule("assessment");
1474  $result = $ilDB->query("SELECT * FROM qpl_qst_type");
1475  $types = array();
1476  while ($row = $ilDB->fetchAssoc($result))
1477  {
1478  if ($all_tags || (!in_array($row["question_type_id"], $forbidden_types)))
1479  {
1480  global $ilLog;
1481 
1482  if ($row["plugin"] == 0)
1483  {
1484  $types[$lng->txt($row["type_tag"])] = $row;
1485  }
1486  else
1487  {
1488  global $ilPluginAdmin;
1489  $pl_names = $ilPluginAdmin->getActivePluginsForSlot(IL_COMP_MODULE, "TestQuestionPool", "qst");
1490  foreach ($pl_names as $pl_name)
1491  {
1492  $pl = ilPlugin::getPluginObject(IL_COMP_MODULE, "TestQuestionPool", "qst", $pl_name);
1493  if (strcmp($pl->getQuestionType(), $row["type_tag"]) == 0)
1494  {
1495  $types[$pl->getQuestionTypeTranslation()] = $row;
1496  }
1497  }
1498  }
1499  }
1500  }
1501 
1502  require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionTypeOrderer.php';
1504  $orderer = new ilAssQuestionTypeOrderer($types, $orderMode);
1505  $types = $orderer->getOrderedTypes();
1506 
1507  return $types;
1508  }
1509 
1510  public static function getQuestionTypeByTypeId($type_id) {
1511  global $ilDB;
1512  $query = "SELECT type_tag FROM qpl_qst_type WHERE question_type_id = %s";
1513  $types = array('integer');
1514  $values = array($type_id);
1515  $result = $ilDB->queryF($query, $types, $values);
1516  if ($row = $ilDB->fetchAssoc($result)) {
1517  return $row['type_tag'];
1518  }
1519  }
1520 
1521  public static function getQuestionTypeTranslations()
1522  {
1523  global $ilDB;
1524  global $lng;
1525  global $ilLog;
1526  global $ilPluginAdmin;
1527 
1528  $lng->loadLanguageModule("assessment");
1529  $result = $ilDB->query("SELECT * FROM qpl_qst_type");
1530  $types = array();
1531  while ($row = $ilDB->fetchAssoc($result))
1532  {
1533  if ($row["plugin"] == 0)
1534  {
1535  $types[$row['type_tag']] = $lng->txt($row["type_tag"]);
1536  }
1537  else
1538  {
1539  $pl_names = $ilPluginAdmin->getActivePluginsForSlot(IL_COMP_MODULE, "TestQuestionPool", "qst");
1540  foreach ($pl_names as $pl_name)
1541  {
1542  $pl = ilPlugin::getPluginObject(IL_COMP_MODULE, "TestQuestionPool", "qst", $pl_name);
1543  if (strcmp($pl->getQuestionType(), $row["type_tag"]) == 0)
1544  {
1545  $types[$row['type_tag']] = $pl->getQuestionTypeTranslation();
1546  }
1547  }
1548  }
1549  }
1550  ksort($types);
1551  return $types;
1552  }
1553 
1559  static function &_getSelfAssessmentQuestionTypes($all_tags = FALSE)
1560  {
1561 /* $allowed_types = array(
1562  "assSingleChoice" => 1,
1563  "assMultipleChoice" => 2,
1564  "assClozeTest" => 3,
1565  "assMatchingQuestion" => 4,
1566  "assOrderingQuestion" => 5,
1567  "assOrderingHorizontal" => 6,
1568  "assImagemapQuestion" => 7,
1569  "assTextQuestion" => 8,
1570  "assTextSubset" => 9,
1571  "assErrorText" => 10
1572  );*/
1573  $allowed_types = array(
1574  "assSingleChoice" => 1,
1575  "assMultipleChoice" => 2,
1576  "assClozeTest" => 3,
1577  "assMatchingQuestion" => 4,
1578  "assOrderingQuestion" => 5,
1579  "assOrderingHorizontal" => 6,
1580  "assImagemapQuestion" => 7,
1581  "assTextSubset" => 9,
1582  "assErrorText" => 10
1583  );
1584  $satypes = array();
1585  $qtypes = ilObjQuestionPool::_getQuestionTypes($all_tags);
1586  foreach($qtypes as $k => $t)
1587  {
1588  //if (in_array($t["type_tag"], $allowed_types))
1589  if (isset($allowed_types[$t["type_tag"]]))
1590  {
1591  $t["order"] = $allowed_types[$t["type_tag"]];
1592  $satypes[$k] = $t;
1593  }
1594  }
1595  return $satypes;
1596  }
1597 
1598 
1599  function &getQuestionList()
1600  {
1601  global $ilDB;
1602 
1603  $questions = array();
1604  $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",
1605  array('integer'),
1606  array($this->getId())
1607  );
1608  while ($row = $ilDB->fetchAssoc($result))
1609  {
1610  array_push($questions, $row);
1611  }
1612  return $questions;
1613  }
1614 
1621  public static function _updateQuestionCount($object_id)
1622  {
1623  global $ilDB;
1624  $result = $ilDB->manipulateF("UPDATE qpl_questionpool SET questioncount = %s, tstamp = %s WHERE obj_fi = %s",
1625  array('integer','integer','integer'),
1626  array(ilObjQuestionPool::_getQuestionCount($object_id, TRUE), time(), $object_id)
1627  );
1628  }
1629 
1636  function isPluginActive($a_pname)
1637  {
1638  global $ilPluginAdmin;
1639  if ($ilPluginAdmin->isActive(IL_COMP_MODULE, "TestQuestionPool", "qst", $a_pname))
1640  {
1641  return TRUE;
1642  }
1643  else
1644  {
1645  return FALSE;
1646  }
1647  }
1648 
1649  /*
1650  * Remove all questions with owner = 0
1651  */
1652  public function purgeQuestions()
1653  {
1654  global $ilDB, $ilUser;
1655 
1656  require_once 'Modules/TestQuestionPool/classes/class.ilAssIncompleteQuestionPurger.php';
1657  $incompleteQuestionPurger = new ilAssIncompleteQuestionPurger($ilDB);
1658  $incompleteQuestionPurger->setOwnerId($ilUser->getId());
1659  $incompleteQuestionPurger->purge();
1660  }
1661 
1667  public function getTaxonomyIds()
1668  {
1669  require_once 'Services/Taxonomy/classes/class.ilObjTaxonomy.php';
1670  return ilObjTaxonomy::getUsageOfObject( $this->getId() );
1671  }
1672 
1673 } // END class.ilObjQuestionPool
1674 ?>