ILIAS  release_4-3 Revision
 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-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3 
4 include_once "./Modules/Test/classes/inc.AssessmentConstants.php";
5 
17 {
23  var $online;
24 
29  private $import_dir;
30 
37  function ilObjQuestionPool($a_id = 0,$a_call_by_reference = true)
38  {
39  $this->type = "qpl";
40  $this->ilObject($a_id,$a_call_by_reference);
41  $this->setOnline(0);
42  }
43 
47  function create($a_upload = false)
48  {
50 
51  // meta data will be created by
52  // import parser
53  if (!$a_upload)
54  {
55  $this->createMetaData();
56  }
57  }
58 
65  function createReference()
66  {
68  $this->saveToDb();
69  return $result;
70  }
71 
78  function update()
79  {
80  $this->updateMetaData();
81  if (!parent::update())
82  {
83  return false;
84  }
85 
86  // put here object specific stuff
87 
88  return true;
89  }
90 
91  function updateMetaData()
92  {
93  global $ilUser;
94  include_once "./Services/MetaData/classes/class.ilMD.php";
95  $md =& new ilMD($this->getId(), 0, $this->getType());
96  $md_gen =& $md->getGeneral();
97  if ($md_gen == false)
98  {
99  include_once "./Services/MetaData/classes/class.ilMDCreator.php";
100  $md_creator = new ilMDCreator($this->getId(),0,$this->getType());
101  $md_creator->setTitle($this->getTitle());
102  $md_creator->setTitleLanguage($ilUser->getPref('language'));
103  $md_creator->create();
104  }
106  }
107 
113  function read($a_force_db = false)
114  {
115  parent::read($a_force_db);
116  $this->loadFromDb();
117  }
118 
119 
126  function delete()
127  {
128  // always call parent delete function first!!
129  if (!parent::delete())
130  {
131  return false;
132  }
133 
134  // delete meta data
135  $this->deleteMetaData();
136 
137  //put here your module specific stuff
138  $this->deleteQuestionpool();
139 
140  return true;
141  }
142 
144  {
145  $questions =& $this->getAllQuestions();
146 
147  if (count($questions))
148  {
149  foreach ($questions as $question_id)
150  {
151  $this->deleteQuestion($question_id);
152  }
153  }
154 
155  // delete export files
156  include_once "./Services/Utilities/classes/class.ilUtil.php";
157  $qpl_data_dir = ilUtil::getDataDir()."/qpl_data";
158  $directory = $qpl_data_dir."/qpl_".$this->getId();
159  if (is_dir($directory))
160  {
161  include_once "./Services/Utilities/classes/class.ilUtil.php";
162  ilUtil::delDir($directory);
163  }
164  }
165 
173  function initDefaultRoles()
174  {
175  return array();
176  }
177 
191  function notify($a_event,$a_ref_id,$a_parent_non_rbac_id,$a_node_id,$a_params = 0)
192  {
193  global $tree;
194 
195  switch ($a_event)
196  {
197  case "link":
198 
199  //var_dump("<pre>",$a_params,"</pre>");
200  //echo "Module name ".$this->getRefId()." triggered by link event. Objects linked into target object ref_id: ".$a_ref_id;
201  //exit;
202  break;
203 
204  case "cut":
205 
206  //echo "Module name ".$this->getRefId()." triggered by cut event. Objects are removed from target object ref_id: ".$a_ref_id;
207  //exit;
208  break;
209 
210  case "copy":
211 
212  //var_dump("<pre>",$a_params,"</pre>");
213  //echo "Module name ".$this->getRefId()." triggered by copy event. Objects are copied into target object ref_id: ".$a_ref_id;
214  //exit;
215  break;
216 
217  case "paste":
218 
219  //echo "Module name ".$this->getRefId()." triggered by paste (cut) event. Objects are pasted into target object ref_id: ".$a_ref_id;
220  //exit;
221  break;
222 
223  case "new":
224 
225  //echo "Module name ".$this->getRefId()." triggered by paste (new) event. Objects are applied to target object ref_id: ".$a_ref_id;
226  //exit;
227  break;
228  }
229 
230  // At the beginning of the recursive process it avoids second call of the notify function with the same parameter
231  if ($a_node_id==$_GET["ref_id"])
232  {
233  $parent_obj =& $this->ilias->obj_factory->getInstanceByRefId($a_node_id);
234  $parent_type = $parent_obj->getType();
235  if($parent_type == $this->getType())
236  {
237  $a_node_id = (int) $tree->getParentId($a_node_id);
238  }
239  }
240 
241  parent::notify($a_event,$a_ref_id,$a_parent_non_rbac_id,$a_node_id,$a_params);
242  }
243 
250  function deleteQuestion($question_id)
251  {
252  include_once "./Modules/Test/classes/class.ilObjTest.php";
253 
254  $question =& ilObjTest::_instanciateQuestion($question_id);
255  $question->delete($question_id);
256  }
257 
263  function loadFromDb()
264  {
265  global $ilDB;
266 
267  $result = $ilDB->queryF("SELECT * FROM qpl_questionpool WHERE obj_fi = %s",
268  array('integer'),
269  array($this->getId())
270  );
271  if ($result->numRows() == 1)
272  {
273  $row = $ilDB->fetchAssoc($result);
274  $this->setOnline($row["isonline"]);
275  }
276  }
277 
283  function saveToDb()
284  {
285  global $ilDB;
286 
287  $result = $ilDB->queryF("SELECT id_questionpool FROM qpl_questionpool WHERE obj_fi = %s",
288  array('integer'),
289  array($this->getId())
290  );
291  if ($result->numRows() == 1)
292  {
293  $result = $ilDB->manipulateF("UPDATE qpl_questionpool SET isonline = %s, tstamp = %s WHERE obj_fi = %s",
294  array('text','integer','integer'),
295  array($this->getOnline(), time(), $this->getId())
296  );
297  }
298  else
299  {
300  $next_id = $ilDB->nextId('qpl_questionpool');
301  $result = $ilDB->manipulateF("INSERT INTO qpl_questionpool (id_questionpool, isonline, tstamp, obj_fi) VALUES (%s, %s, %s, %s)",
302  array('integer','text','integer','integer'),
303  array($next_id, $this->getOnline(), time(), $this->getId())
304  );
305  }
306  }
307 
315  function getQuestiontype($question_id)
316  {
317  global $ilDB;
318 
319  if ($question_id < 1)
320  {
321  return;
322  }
323 
324  $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",
325  array('integer'),
326  array($question_id)
327  );
328  if ($result->numRows() == 1)
329  {
330  $data = $ilDB->fetchAssoc($result);
331  return $data["type_tag"];
332  }
333  else
334  {
335  return;
336  }
337  }
338 
344  function getDescription()
345  {
346  return parent::getDescription();
347  }
348 
352  function setDescription($a_description)
353  {
354  parent::setDescription($a_description);
355  }
356 
362  function getTitle()
363  {
364  return parent::getTitle();
365  }
366 
370  function setTitle($a_title)
371  {
372  parent::setTitle($a_title);
373  }
374 
382  function isInUse($question_id)
383  {
384  global $ilDB;
385 
386  $result = $ilDB->queryF("SELECT COUNT(solution_id) solution_count FROM tst_solutions WHERE question_fi = %s",
387  array('integer'),
388  array($question_id)
389  );
390  $row = $ilDB->fetchAssoc($result);
391  return $row["solution_count"];
392  }
393 
394  function &createQuestion($question_type, $question_id = -1)
395  {
396  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
397  if ($question_id > 0) return assQuestion::_instanciateQuestionGUI($question_id);
398  assQuestion::_includeClass($question_type, 1);
399  $question_type_gui = $question_type . "GUI";
400  $question_gui =& new $question_type_gui();
401  return $question_gui;
402  }
403 
410  function duplicateQuestion($question_id)
411  {
412  $question =& $this->createQuestion("", $question_id);
413  $newtitle = $question->object->getTitle();
414  if ($question->object->questionTitleExists($this->getId(), $question->object->getTitle()))
415  {
416  $counter = 2;
417  while ($question->object->questionTitleExists($this->getId(), $question->object->getTitle() . " ($counter)"))
418  {
419  $counter++;
420  }
421  $newtitle = $question->object->getTitle() . " ($counter)";
422  }
423  $new_id = $question->object->duplicate(false, $newtitle);
424  // update question count of question pool
426  return $new_id;
427  }
428 
436  function copyQuestion($question_id, $questionpool_to)
437  {
438  $question_gui =& $this->createQuestion("", $question_id);
439  if ($question_gui->object->getObjId() == $questionpool_to)
440  {
441  // the question is copied into the same question pool
442  return $this->duplicateQuestion($question_id);
443  }
444  else
445  {
446  // the question is copied into another question pool
447  $newtitle = $question_gui->object->getTitle();
448  if ($question_gui->object->questionTitleExists($this->getId(), $question_gui->object->getTitle()))
449  {
450  $counter = 2;
451  while ($question_gui->object->questionTitleExists($this->getId(), $question_gui->object->getTitle() . " ($counter)"))
452  {
453  $counter++;
454  }
455  $newtitle = $question_gui->object->getTitle() . " ($counter)";
456  }
457  return $question_gui->object->copyObject($this->getId(), $newtitle);
458  }
459  }
460 
466  function getQuestionBrowserData($arrFilter)
467  {
468  global $ilUser;
469  global $ilDB;
470 
471  $where = "";
472  if (is_array($arrFilter))
473  {
474  if (array_key_exists('title', $arrFilter) && strlen($arrFilter['title']))
475  {
476  $where .= " AND " . $ilDB->like('qpl_questions.title', 'text', "%%" . $arrFilter['title'] . "%%");
477  }
478  if (array_key_exists('description', $arrFilter) && strlen($arrFilter['description']))
479  {
480  $where .= " AND " . $ilDB->like('qpl_questions.description', 'text', "%%" . $arrFilter['description'] . "%%");
481  }
482  if (array_key_exists('author', $arrFilter) && strlen($arrFilter['author']))
483  {
484  $where .= " AND " . $ilDB->like('qpl_questions.author', 'text', "%%" . $arrFilter['author'] . "%%");
485  }
486  if (array_key_exists('type', $arrFilter) && strlen($arrFilter['type']))
487  {
488  $where .= " AND qpl_qst_type.type_tag = " . $ilDB->quote($arrFilter['type'], 'text');
489  }
490  }
491  $query_result = $ilDB->queryF("SELECT qpl_questions.*, qpl_qst_type.type_tag, qpl_qst_type.plugin 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" . $where,
492  array('integer'),
493  array($this->getId())
494  );
495  $types = $this->getQuestionTypeTranslations();
496  $rows = array();
497  if ($query_result->numRows())
498  {
499  while ($row = $ilDB->fetchAssoc($query_result))
500  {
501  $row['ttype'] = $types[$row['type_tag']];
502  if ($row["plugin"])
503  {
504  if ($this->isPluginActive($row["type_tag"]))
505  {
506  array_push($rows, $row);
507  }
508  }
509  else
510  {
511  array_push($rows, $row);
512  }
513  }
514  }
515  return $rows;
516  }
517 
523  public function getPrintviewQuestions()
524  {
525  global $ilDB;
526 
527  $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",
528  array('integer'),
529  array($this->getId())
530  );
531  $rows = array();
532  $types = $this->getQuestionTypeTranslations();
533  if ($query_result->numRows())
534  {
535  while ($row = $ilDB->fetchAssoc($query_result))
536  {
537  $row['ttype'] = $types[$row['type_tag']];
538  if ($row["plugin"])
539  {
540  if ($this->isPluginActive($row["type_tag"]))
541  {
542  array_push($rows, $row);
543  }
544  }
545  else
546  {
547  array_push($rows, $row);
548  }
549  }
550  }
551  return $rows;
552  }
553 
560  function exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog, $questions)
561  {
562  global $ilBench;
563 
564  $this->mob_ids = array();
565  $this->file_ids = array();
566 
567  $attrs = array();
568  $attrs["Type"] = "Questionpool_Test";
569  $a_xml_writer->xmlStartTag("ContentObject", $attrs);
570 
571  // MetaData
572  $this->exportXMLMetaData($a_xml_writer);
573 
574  // PageObjects
575  $expLog->write(date("[y-m-d H:i:s] ")."Start Export Page Objects");
576  $ilBench->start("ContentObjectExport", "exportPageObjects");
577  $this->exportXMLPageObjects($a_xml_writer, $a_inst, $expLog, $questions);
578  $ilBench->stop("ContentObjectExport", "exportPageObjects");
579  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export Page Objects");
580 
581  // MediaObjects
582  $expLog->write(date("[y-m-d H:i:s] ")."Start Export Media Objects");
583  $ilBench->start("ContentObjectExport", "exportMediaObjects");
584  $this->exportXMLMediaObjects($a_xml_writer, $a_inst, $a_target_dir, $expLog);
585  $ilBench->stop("ContentObjectExport", "exportMediaObjects");
586  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export Media Objects");
587 
588  // FileItems
589  $expLog->write(date("[y-m-d H:i:s] ")."Start Export File Items");
590  $ilBench->start("ContentObjectExport", "exportFileItems");
591  $this->exportFileItems($a_target_dir, $expLog);
592  $ilBench->stop("ContentObjectExport", "exportFileItems");
593  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export File Items");
594 
595  $a_xml_writer->xmlEndTag("ContentObject");
596  }
597 
604  function exportXMLMetaData(&$a_xml_writer)
605  {
606  include_once("Services/MetaData/classes/class.ilMD2XML.php");
607  $md2xml = new ilMD2XML($this->getId(), 0, $this->getType());
608  $md2xml->setExportMode(true);
609  $md2xml->startExport();
610  $a_xml_writer->appendXML($md2xml->getXML());
611  }
612 
613  function modifyExportIdentifier($a_tag, $a_param, $a_value)
614  {
615  if ($a_tag == "Identifier" && $a_param == "Entry")
616  {
617  include_once "./Services/Utilities/classes/class.ilUtil.php";
618  $a_value = ilUtil::insertInstIntoID($a_value);
619  }
620 
621  return $a_value;
622  }
623 
624 
631  function exportXMLPageObjects(&$a_xml_writer, $a_inst, &$expLog, $questions)
632  {
633  global $ilBench;
634 
635  include_once "./Modules/LearningModule/classes/class.ilLMPageObject.php";
636 
637  foreach ($questions as $question_id)
638  {
639  $ilBench->start("ContentObjectExport", "exportPageObject");
640  $expLog->write(date("[y-m-d H:i:s] ")."Page Object ".$question_id);
641 
642  $attrs = array();
643  $a_xml_writer->xmlStartTag("PageObject", $attrs);
644 
645 
646  // export xml to writer object
647  $ilBench->start("ContentObjectExport", "exportPageObject_XML");
648  $page_object = new ilPageObject("qpl", $question_id);
649  $page_object->buildDom();
650  $page_object->insertInstIntoIDs($a_inst);
651  $mob_ids = $page_object->collectMediaObjects(false);
652  $file_ids = $page_object->collectFileItems();
653  $xml = $page_object->getXMLFromDom(false, false, false, "", true);
654  $xml = str_replace("&","&amp;", $xml);
655  $a_xml_writer->appendXML($xml);
656  $page_object->freeDom();
657  unset ($page_object);
658 
659  $ilBench->stop("ContentObjectExport", "exportPageObject_XML");
660 
661  // collect media objects
662  $ilBench->start("ContentObjectExport", "exportPageObject_CollectMedia");
663  //$mob_ids = $page_obj->getMediaObjectIDs();
664  foreach($mob_ids as $mob_id)
665  {
666  $this->mob_ids[$mob_id] = $mob_id;
667  }
668  $ilBench->stop("ContentObjectExport", "exportPageObject_CollectMedia");
669 
670  // collect all file items
671  $ilBench->start("ContentObjectExport", "exportPageObject_CollectFileItems");
672  //$file_ids = $page_obj->getFileItemIds();
673  foreach($file_ids as $file_id)
674  {
675  $this->file_ids[$file_id] = $file_id;
676  }
677  $ilBench->stop("ContentObjectExport", "exportPageObject_CollectFileItems");
678 
679  $a_xml_writer->xmlEndTag("PageObject");
680  //unset($page_obj);
681 
682  $ilBench->stop("ContentObjectExport", "exportPageObject");
683 
684 
685  }
686  }
687 
694  function exportXMLMediaObjects(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
695  {
696  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
697 
698  foreach ($this->mob_ids as $mob_id)
699  {
700  $expLog->write(date("[y-m-d H:i:s] ")."Media Object ".$mob_id);
701  if (ilObjMediaObject::_exists($mob_id))
702  {
703  $media_obj = new ilObjMediaObject($mob_id);
704  $media_obj->exportXML($a_xml_writer, $a_inst);
705  $media_obj->exportFiles($a_target_dir);
706  unset($media_obj);
707  }
708  }
709  }
710 
715  function exportFileItems($a_target_dir, &$expLog)
716  {
717  include_once("./Modules/File/classes/class.ilObjFile.php");
718 
719  foreach ($this->file_ids as $file_id)
720  {
721  $expLog->write(date("[y-m-d H:i:s] ")."File Item ".$file_id);
722  $file_obj = new ilObjFile($file_id, false);
723  $file_obj->export($a_target_dir);
724  unset($file_obj);
725  }
726  }
727 
734  {
735  include_once "./Services/Utilities/classes/class.ilUtil.php";
736  $qpl_data_dir = ilUtil::getDataDir()."/qpl_data";
737  ilUtil::makeDir($qpl_data_dir);
738  if(!is_writable($qpl_data_dir))
739  {
740  $this->ilias->raiseError("Questionpool Data Directory (".$qpl_data_dir
741  .") not writeable.",$this->ilias->error_obj->FATAL);
742  }
743 
744  // create learning module directory (data_dir/lm_data/lm_<id>)
745  $qpl_dir = $qpl_data_dir."/qpl_".$this->getId();
746  ilUtil::makeDir($qpl_dir);
747  if(!@is_dir($qpl_dir))
748  {
749  $this->ilias->raiseError("Creation of Questionpool Directory failed.",$this->ilias->error_obj->FATAL);
750  }
751  // create Export subdirectory (data_dir/lm_data/lm_<id>/Export)
752  ilUtil::makeDir($this->getExportDirectory('xls'));
753  if(!@is_dir($this->getExportDirectory('xls')))
754  {
755  $this->ilias->raiseError("Creation of Export Directory failed.",$this->ilias->error_obj->FATAL);
756  }
757  ilUtil::makeDir($this->getExportDirectory('zip'));
758  if(!@is_dir($this->getExportDirectory('zip')))
759  {
760  $this->ilias->raiseError("Creation of Export Directory failed.",$this->ilias->error_obj->FATAL);
761  }
762  }
763 
767  function getExportDirectory($type = "")
768  {
769  include_once "./Services/Utilities/classes/class.ilUtil.php";
770  switch ($type)
771  {
772  case 'xls':
773  case 'zip':
774  $export_dir = ilUtil::getDataDir()."/qpl_data"."/qpl_".$this->getId()."/export_$type";
775  break;
776  default:
777  $export_dir = ilUtil::getDataDir()."/qpl_data"."/qpl_".$this->getId()."/export";
778  break;
779  }
780  return $export_dir;
781  }
782 
788  static function _createImportDirectory()
789  {
790  global $ilias;
791 
792  include_once "./Services/Utilities/classes/class.ilUtil.php";
793  $qpl_data_dir = ilUtil::getDataDir()."/qpl_data";
794  ilUtil::makeDir($qpl_data_dir);
795 
796  if(!is_writable($qpl_data_dir))
797  {
798  $ilias->raiseError("Questionpool Data Directory (".$qpl_data_dir
799  .") not writeable.",$ilias->error_obj->FATAL);
800  }
801 
802  // create questionpool directory (data_dir/qpl_data/qpl_import)
803  $qpl_dir = $qpl_data_dir."/qpl_import";
804  ilUtil::makeDir($qpl_dir);
805  if(!@is_dir($qpl_dir))
806  {
807  $ilias->raiseError("Creation of Questionpool Directory failed.",$ilias->error_obj->FATAL);
808  }
809  return $qpl_dir;
810  }
811 
815  function _setImportDirectory($a_import_dir = null)
816  {
817  if (strlen($a_import_dir))
818  {
819  $_SESSION["qpl_import_dir"] = $a_import_dir;
820  }
821  else
822  {
823  unset($_SESSION["qpl_import_dir"]);
824  }
825  }
826 
831  {
832  if (strlen($_SESSION["qpl_import_dir"]))
833  {
834  return $_SESSION["qpl_import_dir"];
835  }
836  return null;
837  }
838 
840  {
842  }
843 
849  function &getAllQuestions()
850  {
851  global $ilDB;
852 
853  $result = $ilDB->queryF("SELECT question_id FROM qpl_questions WHERE obj_fi = %s AND qpl_questions.tstamp > 0 AND original_id IS NULL",
854  array('integer'),
855  array($this->getId())
856  );
857  $questions = array();
858  while ($row = $ilDB->fetchAssoc($result))
859  {
860  array_push($questions, $row["question_id"]);
861  }
862  return $questions;
863  }
864 
865  function &getAllQuestionIds()
866  {
867  global $ilDB;
868 
869  $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",
870  array('integer','text'),
871  array($this->getId(), 1)
872  );
873  $questions = array();
874  if ($query_result->numRows())
875  {
876  while ($row = $ilDB->fetchAssoc($query_result))
877  {
878  if ($row["plugin"])
879  {
880  if ($this->isPluginActive($row["type_tag"]))
881  {
882  array_push($questions, $row["question_id"]);
883  }
884  }
885  else
886  {
887  array_push($questions, $row["question_id"]);
888  }
889  }
890  }
891  return $questions;
892  }
893 
898  function getImportMapping()
899  {
900  if (!is_array($this->import_mapping))
901  {
902  return array();
903  }
904  else
905  {
906  return $this->import_mapping;
907  }
908  }
909 
917  function toXML($questions)
918  {
919  $xml = "";
920  // export button was pressed
921  if (count($questions) > 0)
922  {
923  foreach ($questions as $key => $value)
924  {
925  $question =& $this->createQuestion("", $value);
926  $xml .= $question->object->toXML();
927  }
928  if (count($questions) > 1)
929  {
930  $xml = preg_replace("/<\/questestinterop>\s*<.xml.*?>\s*<questestinterop>/", "", $xml);
931  }
932  }
933  $xml = preg_replace("/(<\?xml[^>]*?>)/", "\\1" . "<!DOCTYPE questestinterop SYSTEM \"ims_qtiasiv1p2p1.dtd\">", $xml);
934  return $xml;
935  }
936 
945  function _getQuestionCount($questionpool_id, $complete_questions_only = FALSE)
946  {
947  global $ilDB;
948  if ($complete_questions_only)
949  {
950  $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",
951  array('integer', 'text'),
952  array($questionpool_id, 1)
953  );
954  }
955  else
956  {
957  $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",
958  array('integer'),
959  array($questionpool_id)
960  );
961  }
962  $row = $ilDB->fetchAssoc($result);
963  return $row["question_count"];
964  }
965 
973  function setOnline($a_online_status)
974  {
975  switch ($a_online_status)
976  {
977  case 0:
978  case 1:
979  $this->online = $a_online_status;
980  break;
981  default:
982  $this->online = 0;
983  break;
984  }
985  }
986 
987  function getOnline()
988  {
989  if (strcmp($this->online, "") == 0) $this->online = "0";
990  return $this->online;
991  }
992 
993  function _lookupOnline($a_obj_id, $is_reference = FALSE)
994  {
995  global $ilDB;
996 
997  if ($is_reference)
998  {
999  $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",
1000  array('integer'),
1001  array($a_obj_id)
1002  );
1003  }
1004  else
1005  {
1006  $result = $ilDB->queryF("SELECT isonline FROM qpl_questionpool WHERE obj_fi = %s",
1007  array('integer'),
1008  array($a_obj_id)
1009  );
1010  }
1011  if ($result->numRows() == 1)
1012  {
1013  $row = $ilDB->fetchAssoc($result);
1014  return $row["isonline"];
1015  }
1016  return 0;
1017  }
1018 
1025  function _hasEqualPoints($a_obj_id, $is_reference = FALSE)
1026  {
1027  global $ilDB;
1028 
1029  if ($is_reference)
1030  {
1031  $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",
1032  array('integer'),
1033  array($a_obj_id)
1034  );
1035  }
1036  else
1037  {
1038  $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",
1039  array('integer'),
1040  array($a_obj_id)
1041  );
1042  }
1043  if ($result->numRows() == 1)
1044  {
1045  $row = $ilDB->fetchAssoc($result);
1046  if ($row["equal_points"] == 1)
1047  {
1048  return 1;
1049  }
1050  else
1051  {
1052  return 0;
1053  }
1054  }
1055  return 0;
1056  }
1057 
1064  {
1065  global $ilDB;
1066 
1067  if (array_key_exists("qpl_clipboard", $_SESSION))
1068  {
1069  foreach ($_SESSION["qpl_clipboard"] as $question_object)
1070  {
1071  if (strcmp($question_object["action"], "move") == 0)
1072  {
1073  $result = $ilDB->queryF("SELECT obj_fi FROM qpl_questions WHERE question_id = %s",
1074  array('integer'),
1075  array($question_object["question_id"])
1076  );
1077  if ($result->numRows() == 1)
1078  {
1079  $row = $ilDB->fetchAssoc($result);
1080  $source_questionpool = $row["obj_fi"];
1081  // change the questionpool id in the qpl_questions table
1082  $affectedRows = $ilDB->manipulateF("UPDATE qpl_questions SET obj_fi = %s WHERE question_id = %s",
1083  array('integer','integer'),
1084  array($this->getId(), $question_object["question_id"])
1085  );
1086 
1087  // move question data to the new target directory
1088  $source_path = CLIENT_WEB_DIR . "/assessment/" . $source_questionpool . "/" . $question_object["question_id"] . "/";
1089  if (@is_dir($source_path))
1090  {
1091  $target_path = CLIENT_WEB_DIR . "/assessment/" . $this->getId() . "/";
1092  if (!@is_dir($target_path))
1093  {
1094  include_once "./Services/Utilities/classes/class.ilUtil.php";
1095  ilUtil::makeDirParents($target_path);
1096  }
1097  @rename($source_path, $target_path . $question_object["question_id"]);
1098  }
1099  // update question count of source question pool
1100  ilObjQuestionPool::_updateQuestionCount($source_questionpool);
1101  }
1102  }
1103  else
1104  {
1105  $this->copyQuestion($question_object["question_id"], $this->getId());
1106  }
1107  }
1108  }
1109  // update question count of question pool
1111  unset($_SESSION["qpl_clipboard"]);
1112  }
1113 
1120  function copyToClipboard($question_id)
1121  {
1122  if (!array_key_exists("qpl_clipboard", $_SESSION))
1123  {
1124  $_SESSION["qpl_clipboard"] = array();
1125  }
1126  $_SESSION["qpl_clipboard"][$question_id] = array("question_id" => $question_id, "action" => "copy");
1127  }
1128 
1135  function moveToClipboard($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" => "move");
1142  }
1143 
1144  public function cleanupClipboard($deletedQuestionId)
1145  {
1146  if( !isset($_SESSION['qpl_clipboard']) )
1147  {
1148  return;
1149  }
1150 
1151  if( !isset($_SESSION['qpl_clipboard'][$deletedQuestionId]) )
1152  {
1153  return;
1154  }
1155 
1156  unset($_SESSION['qpl_clipboard'][$deletedQuestionId]);
1157 
1158  if( !count($_SESSION['qpl_clipboard']) )
1159  {
1160  unset($_SESSION['qpl_clipboard']);
1161  }
1162  }
1163 
1171  function _isWriteable($object_id, $user_id)
1172  {
1173  global $rbacsystem;
1174 
1175  include_once "./Services/Object/classes/class.ilObject.php";
1176  $refs = ilObject::_getAllReferences($object_id);
1177  if (count($refs))
1178  {
1179  foreach ($refs as $ref_id)
1180  {
1181  if ($rbacsystem->checkAccess("write", $ref_id) && (ilObject::_hasUntrashedReference($object_id)))
1182  {
1183  return true;
1184  }
1185  }
1186  }
1187  return false;
1188  }
1189 
1197  function &getQuestionDetails($question_ids)
1198  {
1199  global $ilDB;
1200 
1201  $result = array();
1202  $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");
1203  if ($query_result->numRows())
1204  {
1205  while ($row = $ilDB->fetchAssoc($query_result))
1206  {
1207  array_push($result, $row);
1208  }
1209  }
1210  return $result;
1211  }
1212 
1221  function &getDeleteableQuestionDetails($question_ids)
1222  {
1223  global $ilDB, $ilLog;
1224 
1225  $result = array();
1226  $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");
1227  if ($query_result->numRows())
1228  {
1229  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
1230  while ($row = $ilDB->fetchAssoc($query_result))
1231  {
1232  if (!assQuestion::_isUsedInRandomTest($row["question_id"]))
1233  {
1234  array_push($result, $row);
1235  }
1236  else
1237  {
1238  // the question was used in a random test prior to ILIAS 3.7 so it was inserted
1239  // as a reference to the original question pool object and not as a copy. To allow
1240  // the deletion of the question pool object, a copy must be created and all database references
1241  // of the original question must changed with the reference of the copy
1242 
1243  // 1. Create a copy of the original question
1244  $question =& $this->createQuestion("", $row["question_id"]);
1245  $duplicate_id = $question->object->duplicate(true);
1246  if ($duplicate_id > 0)
1247  {
1248  // 2. replace the question id in the solutions
1249  $affectedRows = $ilDB->manipulateF("UPDATE tst_solutions SET question_fi = %s WHERE question_fi = %s",
1250  array('integer','integer'),
1251  array($duplicate_id, $row["question_id"])
1252  );
1253 
1254  // 3. replace the question id in the question list of random tests
1255  $affectedRows = $ilDB->manipulateF("UPDATE tst_test_rnd_qst SET question_fi = %s WHERE question_fi = %s",
1256  array('integer','integer'),
1257  array($duplicate_id, $row["question_id"])
1258  );
1259 
1260  // 4. replace the question id in the test results
1261  $affectedRows = $ilDB->manipulateF("UPDATE tst_test_result SET question_fi = %s WHERE question_fi = %s",
1262  array('integer','integer'),
1263  array($duplicate_id, $row["question_id"])
1264  );
1265 
1266  // 5. replace the question id in the test&assessment log
1267  $affectedRows = $ilDB->manipulateF("UPDATE ass_log SET question_fi = %s WHERE question_fi = %s",
1268  array('integer','integer'),
1269  array($duplicate_id, $row["question_id"])
1270  );
1271 
1272  // 6. The original question can be deleted, so add it to the list of questions
1273  array_push($result, $row);
1274  }
1275  }
1276  }
1277  }
1278  return $result;
1279  }
1280 
1288  {
1289  global $tree;
1290  $path = $tree->getPathFull($ref_id);
1291  $items = array();
1292  $counter = 0;
1293  foreach ($path as $item)
1294  {
1295  if (($counter > 0) && ($counter < count($path)-1))
1296  {
1297  array_push($items, $item["title"]);
1298  }
1299  $counter++;
1300  }
1301  $fullpath = join(" > ", $items);
1302  include_once "./Services/Utilities/classes/class.ilStr.php";
1303  if (strlen($fullpath) > 60)
1304  {
1305  $fullpath = ilStr::subStr($fullpath, 0, 30) . "..." . ilStr::subStr($fullpath, ilStr::strLen($fullpath)-30, 30);
1306  }
1307  return $fullpath;
1308  }
1309 
1316  function &_getAvailableQuestionpools($use_object_id = FALSE, $equal_points = FALSE, $could_be_offline = FALSE, $showPath = FALSE, $with_questioncount = FALSE, $permission = "read", $usr_id = "")
1317  {
1318  global $ilUser;
1319  global $ilDB;
1320 
1321  $result_array = array();
1322  $permission = (strlen($permission) == 0) ? "read" : $permission;
1323  $qpls = ilUtil::_getObjectsByOperations("qpl", $permission, (strlen($usr_id)) ? $usr_id : $ilUser->getId(), -1);
1324  $obj_ids = array();
1325  foreach ($qpls as $ref_id)
1326  {
1327  $obj_id = ilObject::_lookupObjId($ref_id);
1328  $obj_ids[$ref_id] = $obj_id;
1329  }
1330  $titles = ilObject::_prepareCloneSelection($qpls, "qpl");
1331  if (count($obj_ids))
1332  {
1333  $in = $ilDB->in('object_data.obj_id', $obj_ids, false, 'integer');
1334  if ($could_be_offline)
1335  {
1336  $result = $ilDB->query("SELECT qpl_questionpool.*, object_data.title FROM qpl_questionpool, object_data WHERE ".
1337  "qpl_questionpool.obj_fi = object_data.obj_id AND $in ORDER BY object_data.title");
1338  }
1339  else
1340  {
1341  $result = $ilDB->queryF("SELECT qpl_questionpool.*, object_data.title FROM qpl_questionpool, object_data WHERE ".
1342  "qpl_questionpool.obj_fi = object_data.obj_id AND $in AND qpl_questionpool.isonline = %s ".
1343  "ORDER BY object_data.title",
1344  array('text'),
1345  array(1)
1346  );
1347  }
1348  while ($row = $ilDB->fetchAssoc($result))
1349  {
1350  $add = TRUE;
1351  if ($equal_points)
1352  {
1353  if (!ilObjQuestionPool::_hasEqualPoints($row["obj_fi"]))
1354  {
1355  $add = FALSE;
1356  }
1357  }
1358  if ($add)
1359  {
1360  $ref_id = array_search($row["obj_fi"], $obj_ids);
1361  $title = (($showPath) ? $titles[$ref_id] : $row["title"]);
1362  if ($with_questioncount)
1363  {
1364  $title .= " [" . $row["questioncount"] . " " . ($row["questioncount"] == 1 ? $this->lng->txt("ass_question") : $this->lng->txt("assQuestions")) . "]";
1365  }
1366 
1367  if ($use_object_id)
1368  {
1369  $result_array[$row["obj_fi"]] = array("title" => $title, "count" => $row["questioncount"]);
1370  }
1371  else
1372  {
1373  $result_array[$ref_id] = array("title" => $title, "count" => $row["questioncount"]);
1374  }
1375  }
1376  }
1377  }
1378  return $result_array;
1379  }
1380 
1381  function &getQplQuestions()
1382  {
1383  global $ilDB;
1384 
1385  $questions = array();
1386  $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",
1387  array('integer'),
1388  array($this->getId())
1389  );
1390  while ($row = $ilDB->fetchAssoc($result))
1391  {
1392  array_push($questions, $row["question_id"]);
1393  }
1394  return $questions;
1395  }
1396 
1402  function cloneObject($a_target_id,$a_copy_id = 0)
1403  {
1404  global $ilLog;
1405  $newObj = parent::cloneObject($a_target_id,$a_copy_id);
1406  $newObj->setOnline($this->getOnline());
1407  $newObj->saveToDb();
1408  // clone the questions in the question pool
1409  $questions =& $this->getQplQuestions();
1410  foreach ($questions as $question_id)
1411  {
1412  $newObj->copyQuestion($question_id, $newObj->getId());
1413  }
1414 
1415  // clone meta data
1416  include_once "./Services/MetaData/classes/class.ilMD.php";
1417  $md = new ilMD($this->getId(),0,$this->getType());
1418  $new_md =& $md->cloneMD($newObj->getId(),0,$newObj->getType());
1419 
1420  // update the metadata with the new title of the question pool
1421  $newObj->updateMetaData();
1422  return $newObj;
1423  }
1424 
1425  function &getQuestionTypes($all_tags = FALSE, $fixOrder = false)
1426  {
1427  return $this->_getQuestionTypes($all_tags, $fixOrder);
1428  }
1429 
1430  function &_getQuestionTypes($all_tags = FALSE, $fixOrder = false)
1431  {
1432  global $ilDB;
1433  global $lng;
1434 
1435  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
1437  $lng->loadLanguageModule("assessment");
1438  $result = $ilDB->query("SELECT * FROM qpl_qst_type");
1439  $types = array();
1440  while ($row = $ilDB->fetchAssoc($result))
1441  {
1442  if ($all_tags || (!in_array($row["question_type_id"], $forbidden_types)))
1443  {
1444  global $ilLog;
1445 
1446  if ($row["plugin"] == 0)
1447  {
1448  $types[$lng->txt($row["type_tag"])] = $row;
1449  }
1450  else
1451  {
1452  global $ilPluginAdmin;
1453  $pl_names = $ilPluginAdmin->getActivePluginsForSlot(IL_COMP_MODULE, "TestQuestionPool", "qst");
1454  foreach ($pl_names as $pl_name)
1455  {
1456  $pl = ilPlugin::getPluginObject(IL_COMP_MODULE, "TestQuestionPool", "qst", $pl_name);
1457  if (strcmp($pl->getQuestionType(), $row["type_tag"]) == 0)
1458  {
1459  $types[$pl->getQuestionTypeTranslation()] = $row;
1460  }
1461  }
1462  }
1463  }
1464  }
1465 
1466  require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionTypeOrderer.php';
1468  $orderer = new ilAssQuestionTypeOrderer($types, $orderMode);
1469  $types = $orderer->getOrderedTypes();
1470 
1471  return $types;
1472  }
1473 
1474  public static function getQuestionTypeByTypeId($type_id) {
1475  global $ilDB;
1476  $query = "SELECT type_tag FROM qpl_qst_type WHERE question_type_id = %s";
1477  $types = array('integer');
1478  $values = array($type_id);
1479  $result = $ilDB->queryF($query, $types, $values);
1480  if ($row = $ilDB->fetchAssoc($result)) {
1481  return $row['type_tag'];
1482  }
1483  }
1484 
1485  public function &getQuestionTypeTranslations()
1486  {
1487  global $ilDB;
1488  global $lng;
1489  global $ilLog;
1490  global $ilPluginAdmin;
1491 
1492  $lng->loadLanguageModule("assessment");
1493  $result = $ilDB->query("SELECT * FROM qpl_qst_type");
1494  $types = array();
1495  while ($row = $ilDB->fetchAssoc($result))
1496  {
1497  if ($row["plugin"] == 0)
1498  {
1499  $types[$row['type_tag']] = $lng->txt($row["type_tag"]);
1500  }
1501  else
1502  {
1503  $pl_names = $ilPluginAdmin->getActivePluginsForSlot(IL_COMP_MODULE, "TestQuestionPool", "qst");
1504  foreach ($pl_names as $pl_name)
1505  {
1506  $pl = ilPlugin::getPluginObject(IL_COMP_MODULE, "TestQuestionPool", "qst", $pl_name);
1507  if (strcmp($pl->getQuestionType(), $row["type_tag"]) == 0)
1508  {
1509  $types[$row['type_tag']] = $pl->getQuestionTypeTranslation();
1510  }
1511  }
1512  }
1513  }
1514  ksort($types);
1515  return $types;
1516  }
1517 
1523  static function &_getSelfAssessmentQuestionTypes($all_tags = FALSE)
1524  {
1525 /* $allowed_types = array(
1526  "assSingleChoice" => 1,
1527  "assMultipleChoice" => 2,
1528  "assClozeTest" => 3,
1529  "assMatchingQuestion" => 4,
1530  "assOrderingQuestion" => 5,
1531  "assOrderingHorizontal" => 6,
1532  "assImagemapQuestion" => 7,
1533  "assTextQuestion" => 8,
1534  "assTextSubset" => 9,
1535  "assErrorText" => 10
1536  );*/
1537  $allowed_types = array(
1538  "assSingleChoice" => 1,
1539  "assMultipleChoice" => 2,
1540  "assClozeTest" => 3,
1541  "assMatchingQuestion" => 4,
1542  "assOrderingQuestion" => 5,
1543  "assOrderingHorizontal" => 6,
1544  "assImagemapQuestion" => 7,
1545  "assTextSubset" => 9,
1546  "assErrorText" => 10
1547  );
1548  $satypes = array();
1549  $qtypes = ilObjQuestionPool::_getQuestionTypes($all_tags);
1550  foreach($qtypes as $k => $t)
1551  {
1552  //if (in_array($t["type_tag"], $allowed_types))
1553  if (isset($allowed_types[$t["type_tag"]]))
1554  {
1555  $t["order"] = $allowed_types[$t["type_tag"]];
1556  $satypes[$k] = $t;
1557  }
1558  }
1559  return $satypes;
1560  }
1561 
1562 
1563  function &getQuestionList()
1564  {
1565  global $ilDB;
1566 
1567  $questions = array();
1568  $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",
1569  array('integer'),
1570  array($this->getId())
1571  );
1572  while ($row = $ilDB->fetchAssoc($result))
1573  {
1574  array_push($questions, $row);
1575  }
1576  return $questions;
1577  }
1578 
1585  public static function _updateQuestionCount($object_id)
1586  {
1587  global $ilDB;
1588  $result = $ilDB->manipulateF("UPDATE qpl_questionpool SET questioncount = %s, tstamp = %s WHERE obj_fi = %s",
1589  array('integer','integer','integer'),
1590  array(ilObjQuestionPool::_getQuestionCount($object_id, TRUE), time(), $object_id)
1591  );
1592  }
1593 
1600  function isPluginActive($a_pname)
1601  {
1602  global $ilPluginAdmin;
1603  if ($ilPluginAdmin->isActive(IL_COMP_MODULE, "TestQuestionPool", "qst", $a_pname))
1604  {
1605  return TRUE;
1606  }
1607  else
1608  {
1609  return FALSE;
1610  }
1611  }
1612 
1613  /*
1614  * Remove all questions with owner = 0
1615  */
1616  public function purgeQuestions()
1617  {
1618  global $ilDB, $ilUser;
1619 
1620  require_once 'Modules/TestQuestionPool/classes/class.ilAssIncompleteQuestionPurger.php';
1621  $incompleteQuestionPurger = new ilAssIncompleteQuestionPurger($ilDB);
1622  $incompleteQuestionPurger->setOwnerId($ilUser->getId());
1623  $incompleteQuestionPurger->purge();
1624  }
1625 } // END class.ilObjQuestionPool
1626 ?>