ILIAS  Release_4_1_x_branch Revision 61804
 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 
31  function ilObjQuestionPool($a_id = 0,$a_call_by_reference = true)
32  {
33  $this->type = "qpl";
34  $this->ilObject($a_id,$a_call_by_reference);
35  $this->setOnline(0);
36  }
37 
41  function create($a_upload = false)
42  {
44 
45  // meta data will be created by
46  // import parser
47  if (!$a_upload)
48  {
49  $this->createMetaData();
50  }
51  }
52 
59  function createReference()
60  {
62  $this->saveToDb();
63  return $result;
64  }
65 
72  function update()
73  {
74  $this->updateMetaData();
75  if (!parent::update())
76  {
77  return false;
78  }
79 
80  // put here object specific stuff
81 
82  return true;
83  }
84 
85  function updateMetaData()
86  {
87  global $ilUser;
88  include_once "./Services/MetaData/classes/class.ilMD.php";
89  $md =& new ilMD($this->getId(), 0, $this->getType());
90  $md_gen =& $md->getGeneral();
91  if ($md_gen == false)
92  {
93  include_once "./Services/MetaData/classes/class.ilMDCreator.php";
94  $md_creator = new ilMDCreator($this->getId(),0,$this->getType());
95  $md_creator->setTitle($this->getTitle());
96  $md_creator->setTitleLanguage($ilUser->getPref('language'));
97  $md_creator->create();
98  }
100  }
101 
107  function read($a_force_db = false)
108  {
109  parent::read($a_force_db);
110  $this->loadFromDb();
111  }
112 
113 
120  function delete()
121  {
122  // always call parent delete function first!!
123  if (!parent::delete())
124  {
125  return false;
126  }
127 
128  // delete meta data
129  $this->deleteMetaData();
130 
131  //put here your module specific stuff
132  $this->deleteQuestionpool();
133 
134  return true;
135  }
136 
138  {
139  $questions =& $this->getAllQuestions();
140 
141  if (count($questions))
142  {
143  foreach ($questions as $question_id)
144  {
145  $this->deleteQuestion($question_id);
146  }
147  }
148 
149  // delete export files
150  include_once "./Services/Utilities/classes/class.ilUtil.php";
151  $qpl_data_dir = ilUtil::getDataDir()."/qpl_data";
152  $directory = $qpl_data_dir."/qpl_".$this->getId();
153  if (is_dir($directory))
154  {
155  include_once "./Services/Utilities/classes/class.ilUtil.php";
156  ilUtil::delDir($directory);
157  }
158  }
159 
167  function initDefaultRoles()
168  {
169  return array();
170  }
171 
185  function notify($a_event,$a_ref_id,$a_parent_non_rbac_id,$a_node_id,$a_params = 0)
186  {
187  global $tree;
188 
189  switch ($a_event)
190  {
191  case "link":
192 
193  //var_dump("<pre>",$a_params,"</pre>");
194  //echo "Module name ".$this->getRefId()." triggered by link event. Objects linked into target object ref_id: ".$a_ref_id;
195  //exit;
196  break;
197 
198  case "cut":
199 
200  //echo "Module name ".$this->getRefId()." triggered by cut event. Objects are removed from target object ref_id: ".$a_ref_id;
201  //exit;
202  break;
203 
204  case "copy":
205 
206  //var_dump("<pre>",$a_params,"</pre>");
207  //echo "Module name ".$this->getRefId()." triggered by copy event. Objects are copied into target object ref_id: ".$a_ref_id;
208  //exit;
209  break;
210 
211  case "paste":
212 
213  //echo "Module name ".$this->getRefId()." triggered by paste (cut) event. Objects are pasted into target object ref_id: ".$a_ref_id;
214  //exit;
215  break;
216 
217  case "new":
218 
219  //echo "Module name ".$this->getRefId()." triggered by paste (new) event. Objects are applied to target object ref_id: ".$a_ref_id;
220  //exit;
221  break;
222  }
223 
224  // At the beginning of the recursive process it avoids second call of the notify function with the same parameter
225  if ($a_node_id==$_GET["ref_id"])
226  {
227  $parent_obj =& $this->ilias->obj_factory->getInstanceByRefId($a_node_id);
228  $parent_type = $parent_obj->getType();
229  if($parent_type == $this->getType())
230  {
231  $a_node_id = (int) $tree->getParentId($a_node_id);
232  }
233  }
234 
235  parent::notify($a_event,$a_ref_id,$a_parent_non_rbac_id,$a_node_id,$a_params);
236  }
237 
244  function deleteQuestion($question_id)
245  {
246  include_once "./Modules/Test/classes/class.ilObjTest.php";
247 
248  $question =& ilObjTest::_instanciateQuestion($question_id);
249  $question->delete($question_id);
250  }
251 
257  function loadFromDb()
258  {
259  global $ilDB;
260 
261  $result = $ilDB->queryF("SELECT * FROM qpl_questionpool WHERE obj_fi = %s",
262  array('integer'),
263  array($this->getId())
264  );
265  if ($result->numRows() == 1)
266  {
267  $row = $ilDB->fetchAssoc($result);
268  $this->setOnline($row["isonline"]);
269  }
270  }
271 
277  function saveToDb()
278  {
279  global $ilDB;
280 
281  $result = $ilDB->queryF("SELECT id_questionpool FROM qpl_questionpool WHERE obj_fi = %s",
282  array('integer'),
283  array($this->getId())
284  );
285  if ($result->numRows() == 1)
286  {
287  $result = $ilDB->manipulateF("UPDATE qpl_questionpool SET isonline = %s, tstamp = %s WHERE obj_fi = %s",
288  array('text','integer','integer'),
289  array($this->getOnline(), time(), $this->getId())
290  );
291  }
292  else
293  {
294  $next_id = $ilDB->nextId('qpl_questionpool');
295  $result = $ilDB->manipulateF("INSERT INTO qpl_questionpool (id_questionpool, isonline, tstamp, obj_fi) VALUES (%s, %s, %s, %s)",
296  array('integer','text','integer','integer'),
297  array($next_id, $this->getOnline(), time(), $this->getId())
298  );
299  }
300  }
301 
309  function getQuestiontype($question_id)
310  {
311  global $ilDB;
312 
313  if ($question_id < 1)
314  {
315  return;
316  }
317 
318  $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",
319  array('integer'),
320  array($question_id)
321  );
322  if ($result->numRows() == 1)
323  {
324  $data = $ilDB->fetchAssoc($result);
325  return $data["type_tag"];
326  }
327  else
328  {
329  return;
330  }
331  }
332 
338  function getDescription()
339  {
340  return parent::getDescription();
341  }
342 
346  function setDescription($a_description)
347  {
348  parent::setDescription($a_description);
349  }
350 
356  function getTitle()
357  {
358  return parent::getTitle();
359  }
360 
364  function setTitle($a_title)
365  {
366  parent::setTitle($a_title);
367  }
368 
376  function isInUse($question_id)
377  {
378  global $ilDB;
379 
380  $result = $ilDB->queryF("SELECT COUNT(solution_id) solution_count FROM tst_solutions WHERE question_fi = %s",
381  array('integer'),
382  array($question_id)
383  );
384  $row = $ilDB->fetchAssoc($result);
385  return $row["solution_count"];
386  }
387 
388  function &createQuestion($question_type, $question_id = -1)
389  {
390  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
391  if ($question_id > 0) return assQuestion::_instanciateQuestionGUI($question_id);
392  assQuestion::_includeClass($question_type, 1);
393  $question_type_gui = $question_type . "GUI";
394  $question_gui =& new $question_type_gui();
395  return $question_gui;
396  }
397 
404  function duplicateQuestion($question_id)
405  {
406  $question =& $this->createQuestion("", $question_id);
407  $newtitle = $question->object->getTitle();
408  if ($question->object->questionTitleExists($this->getId(), $question->object->getTitle()))
409  {
410  $counter = 2;
411  while ($question->object->questionTitleExists($this->getId(), $question->object->getTitle() . " ($counter)"))
412  {
413  $counter++;
414  }
415  $newtitle = $question->object->getTitle() . " ($counter)";
416  }
417  $question->object->duplicate(false, $newtitle);
418  // update question count of question pool
420  }
421 
429  function copyQuestion($question_id, $questionpool_to)
430  {
431  $question_gui =& $this->createQuestion("", $question_id);
432  if ($question_gui->object->getObjId() == $questionpool_to)
433  {
434  // the question is copied into the same question pool
435  $this->duplicateQuestion($question_id);
436  }
437  else
438  {
439  // the question is copied into another question pool
440  $newtitle = $question_gui->object->getTitle();
441  if ($question_gui->object->questionTitleExists($this->getId(), $question_gui->object->getTitle()))
442  {
443  $counter = 2;
444  while ($question_gui->object->questionTitleExists($this->getId(), $question_gui->object->getTitle() . " ($counter)"))
445  {
446  $counter++;
447  }
448  $newtitle = $question_gui->object->getTitle() . " ($counter)";
449  }
450  $question_gui->object->copyObject($this->getId(), $newtitle);
451  }
452  }
453 
459  function getQuestionBrowserData($arrFilter)
460  {
461  global $ilUser;
462  global $ilDB;
463 
464  $where = "";
465  if (is_array($arrFilter))
466  {
467  if (array_key_exists('title', $arrFilter) && strlen($arrFilter['title']))
468  {
469  $where .= " AND " . $ilDB->like('qpl_questions.title', 'text', "%%" . $arrFilter['title'] . "%%");
470  }
471  if (array_key_exists('description', $arrFilter) && strlen($arrFilter['description']))
472  {
473  $where .= " AND " . $ilDB->like('qpl_questions.description', 'text', "%%" . $arrFilter['description'] . "%%");
474  }
475  if (array_key_exists('author', $arrFilter) && strlen($arrFilter['author']))
476  {
477  $where .= " AND " . $ilDB->like('qpl_questions.author', 'text', "%%" . $arrFilter['author'] . "%%");
478  }
479  if (array_key_exists('type', $arrFilter) && strlen($arrFilter['type']))
480  {
481  $where .= " AND qpl_qst_type.type_tag = " . $ilDB->quote($arrFilter['type'], 'text');
482  }
483  }
484  $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,
485  array('integer'),
486  array($this->getId())
487  );
488  $types = $this->getQuestionTypeTranslations();
489  $rows = array();
490  if ($query_result->numRows())
491  {
492  while ($row = $ilDB->fetchAssoc($query_result))
493  {
494  $row['ttype'] = $types[$row['type_tag']];
495  if ($row["plugin"])
496  {
497  if ($this->isPluginActive($row["type_tag"]))
498  {
499  array_push($rows, $row);
500  }
501  }
502  else
503  {
504  array_push($rows, $row);
505  }
506  }
507  }
508  return $rows;
509  }
510 
517  {
518  global $ilDB;
519 
520  $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",
521  array('integer'),
522  array($this->getId())
523  );
524  $rows = array();
525  $types = $this->getQuestionTypeTranslations();
526  if ($query_result->numRows())
527  {
528  while ($row = $ilDB->fetchAssoc($query_result))
529  {
530  $row['ttype'] = $types[$row['type_tag']];
531  if ($row["plugin"])
532  {
533  if ($this->isPluginActive($row["type_tag"]))
534  {
535  array_push($rows, $row);
536  }
537  }
538  else
539  {
540  array_push($rows, $row);
541  }
542  }
543  }print_r($row);
544  return $rows;
545  }
546 
553  function exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog, $questions)
554  {
555  global $ilBench;
556 
557  $this->mob_ids = array();
558  $this->file_ids = array();
559 
560  $attrs = array();
561  $attrs["Type"] = "Questionpool_Test";
562  $a_xml_writer->xmlStartTag("ContentObject", $attrs);
563 
564  // MetaData
565  $this->exportXMLMetaData($a_xml_writer);
566 
567  // PageObjects
568  $expLog->write(date("[y-m-d H:i:s] ")."Start Export Page Objects");
569  $ilBench->start("ContentObjectExport", "exportPageObjects");
570  $this->exportXMLPageObjects($a_xml_writer, $a_inst, $expLog, $questions);
571  $ilBench->stop("ContentObjectExport", "exportPageObjects");
572  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export Page Objects");
573 
574  // MediaObjects
575  $expLog->write(date("[y-m-d H:i:s] ")."Start Export Media Objects");
576  $ilBench->start("ContentObjectExport", "exportMediaObjects");
577  $this->exportXMLMediaObjects($a_xml_writer, $a_inst, $a_target_dir, $expLog);
578  $ilBench->stop("ContentObjectExport", "exportMediaObjects");
579  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export Media Objects");
580 
581  // FileItems
582  $expLog->write(date("[y-m-d H:i:s] ")."Start Export File Items");
583  $ilBench->start("ContentObjectExport", "exportFileItems");
584  $this->exportFileItems($a_target_dir, $expLog);
585  $ilBench->stop("ContentObjectExport", "exportFileItems");
586  $expLog->write(date("[y-m-d H:i:s] ")."Finished Export File Items");
587 
588  $a_xml_writer->xmlEndTag("ContentObject");
589  }
590 
597  function exportXMLMetaData(&$a_xml_writer)
598  {
599  include_once("Services/MetaData/classes/class.ilMD2XML.php");
600  $md2xml = new ilMD2XML($this->getId(), 0, $this->getType());
601  $md2xml->setExportMode(true);
602  $md2xml->startExport();
603  $a_xml_writer->appendXML($md2xml->getXML());
604  }
605 
606  function modifyExportIdentifier($a_tag, $a_param, $a_value)
607  {
608  if ($a_tag == "Identifier" && $a_param == "Entry")
609  {
610  include_once "./Services/Utilities/classes/class.ilUtil.php";
611  $a_value = ilUtil::insertInstIntoID($a_value);
612  }
613 
614  return $a_value;
615  }
616 
617 
624  function exportXMLPageObjects(&$a_xml_writer, $a_inst, &$expLog, $questions)
625  {
626  global $ilBench;
627 
628  include_once "./Modules/LearningModule/classes/class.ilLMPageObject.php";
629 
630  foreach ($questions as $question_id)
631  {
632  $ilBench->start("ContentObjectExport", "exportPageObject");
633  $expLog->write(date("[y-m-d H:i:s] ")."Page Object ".$question_id);
634 
635  $attrs = array();
636  $a_xml_writer->xmlStartTag("PageObject", $attrs);
637 
638 
639  // export xml to writer object
640  $ilBench->start("ContentObjectExport", "exportPageObject_XML");
641  $page_object = new ilPageObject("qpl", $question_id);
642  $page_object->buildDom();
643  $page_object->insertInstIntoIDs($a_inst);
644  $mob_ids = $page_object->collectMediaObjects(false);
645  $file_ids = $page_object->collectFileItems();
646  $xml = $page_object->getXMLFromDom(false, false, false, "", true);
647  $xml = str_replace("&","&amp;", $xml);
648  $a_xml_writer->appendXML($xml);
649  $page_object->freeDom();
650  unset ($page_object);
651 
652  $ilBench->stop("ContentObjectExport", "exportPageObject_XML");
653 
654  // collect media objects
655  $ilBench->start("ContentObjectExport", "exportPageObject_CollectMedia");
656  //$mob_ids = $page_obj->getMediaObjectIDs();
657  foreach($mob_ids as $mob_id)
658  {
659  $this->mob_ids[$mob_id] = $mob_id;
660  }
661  $ilBench->stop("ContentObjectExport", "exportPageObject_CollectMedia");
662 
663  // collect all file items
664  $ilBench->start("ContentObjectExport", "exportPageObject_CollectFileItems");
665  //$file_ids = $page_obj->getFileItemIds();
666  foreach($file_ids as $file_id)
667  {
668  $this->file_ids[$file_id] = $file_id;
669  }
670  $ilBench->stop("ContentObjectExport", "exportPageObject_CollectFileItems");
671 
672  $a_xml_writer->xmlEndTag("PageObject");
673  //unset($page_obj);
674 
675  $ilBench->stop("ContentObjectExport", "exportPageObject");
676 
677 
678  }
679  }
680 
687  function exportXMLMediaObjects(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
688  {
689  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
690 
691  foreach ($this->mob_ids as $mob_id)
692  {
693  $expLog->write(date("[y-m-d H:i:s] ")."Media Object ".$mob_id);
694  if (ilObjMediaObject::_exists($mob_id))
695  {
696  $media_obj = new ilObjMediaObject($mob_id);
697  $media_obj->exportXML($a_xml_writer, $a_inst);
698  $media_obj->exportFiles($a_target_dir);
699  unset($media_obj);
700  }
701  }
702  }
703 
708  function exportFileItems($a_target_dir, &$expLog)
709  {
710  include_once("./Modules/File/classes/class.ilObjFile.php");
711 
712  foreach ($this->file_ids as $file_id)
713  {
714  $expLog->write(date("[y-m-d H:i:s] ")."File Item ".$file_id);
715  $file_obj = new ilObjFile($file_id, false);
716  $file_obj->export($a_target_dir);
717  unset($file_obj);
718  }
719  }
720 
727  {
728  include_once "./Services/Utilities/classes/class.ilUtil.php";
729  $qpl_data_dir = ilUtil::getDataDir()."/qpl_data";
730  ilUtil::makeDir($qpl_data_dir);
731  if(!is_writable($qpl_data_dir))
732  {
733  $this->ilias->raiseError("Questionpool Data Directory (".$qpl_data_dir
734  .") not writeable.",$this->ilias->error_obj->FATAL);
735  }
736 
737  // create learning module directory (data_dir/lm_data/lm_<id>)
738  $qpl_dir = $qpl_data_dir."/qpl_".$this->getId();
739  ilUtil::makeDir($qpl_dir);
740  if(!@is_dir($qpl_dir))
741  {
742  $this->ilias->raiseError("Creation of Questionpool Directory failed.",$this->ilias->error_obj->FATAL);
743  }
744  // create Export subdirectory (data_dir/lm_data/lm_<id>/Export)
745  $export_dir = $qpl_dir."/export";
746  ilUtil::makeDir($export_dir);
747  if(!@is_dir($export_dir))
748  {
749  $this->ilias->raiseError("Creation of Export Directory failed.",$this->ilias->error_obj->FATAL);
750  }
751  }
752 
757  {
758  include_once "./Services/Utilities/classes/class.ilUtil.php";
759  $export_dir = ilUtil::getDataDir()."/qpl_data"."/qpl_".$this->getId()."/export";
760  return $export_dir;
761  }
762 
767  {
768  // quit if import dir not available
769  if (!@is_dir($dir) or
770  !is_writeable($dir))
771  {
772  return array();
773  }
774  // open directory
775  $dir = dir($dir);
776 
777  // initialize array
778  $file = array();
779 
780  // get files and save the in the array
781  while ($entry = $dir->read())
782  {
783  if ($entry != "." and
784  $entry != ".." and
785  (substr($entry, -4) == ".zip" or substr($entry, -4) == ".xls") and
786  ereg("^[0-9]{10}_{2}[0-9]+_{2}(qpl__)*[0-9]+\.(zip|xls)\$", $entry))
787  {
788  $file[] = $entry;
789  }
790  }
791 
792  // close import directory
793  $dir->close();
794 
795  // sort files
796  sort ($file);
797  reset ($file);
798  return $file;
799  }
800 
807  {
808  global $ilias;
809 
810  include_once "./Services/Utilities/classes/class.ilUtil.php";
811  $qpl_data_dir = ilUtil::getDataDir()."/qpl_data";
812  ilUtil::makeDir($qpl_data_dir);
813 
814  if(!is_writable($qpl_data_dir))
815  {
816  $ilias->raiseError("Questionpool Data Directory (".$qpl_data_dir
817  .") not writeable.",$ilias->error_obj->FATAL);
818  }
819 
820  // create questionpool directory (data_dir/qpl_data/qpl_import)
821  $qpl_dir = $qpl_data_dir."/qpl_import";
822  ilUtil::makeDir($qpl_dir);
823  if(!@is_dir($qpl_dir))
824  {
825  $ilias->raiseError("Creation of Questionpool Directory failed.",$ilias->error_obj->FATAL);
826  }
827  }
828 
833  {
834  include_once "./Services/Utilities/classes/class.ilUtil.php";
835  $import_dir = ilUtil::getDataDir()."/qpl_data/qpl_import";
836  if(@is_dir($import_dir))
837  {
838  return $import_dir;
839  }
840  else
841  {
842  return false;
843  }
844  }
845 
850  {
851  include_once "./Services/Utilities/classes/class.ilUtil.php";
852  $import_dir = ilUtil::getDataDir()."/qpl_data/qpl_import";
853  if(@is_dir($import_dir))
854  {
855  return $import_dir;
856  }
857  else
858  {
859  return false;
860  }
861  }
862 
868  function &getAllQuestions()
869  {
870  global $ilDB;
871 
872  $result = $ilDB->queryF("SELECT question_id FROM qpl_questions WHERE obj_fi = %s AND qpl_questions.tstamp > 0 AND original_id IS NULL",
873  array('integer'),
874  array($this->getId())
875  );
876  $questions = array();
877  while ($row = $ilDB->fetchAssoc($result))
878  {
879  array_push($questions, $row["question_id"]);
880  }
881  return $questions;
882  }
883 
884  function &getAllQuestionIds()
885  {
886  global $ilDB;
887 
888  $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",
889  array('integer','text'),
890  array($this->getId(), 1)
891  );
892  $questions = array();
893  if ($query_result->numRows())
894  {
895  while ($row = $ilDB->fetchAssoc($query_result))
896  {
897  if ($row["plugin"])
898  {
899  if ($this->isPluginActive($row["type_tag"]))
900  {
901  array_push($questions, $row["question_id"]);
902  }
903  }
904  else
905  {
906  array_push($questions, $row["question_id"]);
907  }
908  }
909  }
910  return $questions;
911  }
912 
917  function getImportMapping()
918  {
919  if (!is_array($this->import_mapping))
920  {
921  return array();
922  }
923  else
924  {
925  return $this->import_mapping;
926  }
927  }
928 
936  function toXML($questions)
937  {
938  $xml = "";
939  // export button was pressed
940  if (count($questions) > 0)
941  {
942  foreach ($questions as $key => $value)
943  {
944  $question =& $this->createQuestion("", $value);
945  $xml .= $question->object->toXML();
946  }
947  if (count($questions) > 1)
948  {
949  $xml = preg_replace("/<\/questestinterop>\s*<.xml.*?>\s*<questestinterop>/", "", $xml);
950  }
951  }
952  $xml = preg_replace("/(<\?xml[^>]*?>)/", "\\1" . "<!DOCTYPE questestinterop SYSTEM \"ims_qtiasiv1p2p1.dtd\">", $xml);
953  return $xml;
954  }
955 
964  function _getQuestionCount($questionpool_id, $complete_questions_only = FALSE)
965  {
966  global $ilDB;
967  if ($complete_questions_only)
968  {
969  $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",
970  array('integer', 'text'),
971  array($questionpool_id, 1)
972  );
973  }
974  else
975  {
976  $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",
977  array('integer'),
978  array($questionpool_id)
979  );
980  }
981  $row = $ilDB->fetchAssoc($result);
982  return $row["question_count"];
983  }
984 
992  function setOnline($a_online_status)
993  {
994  switch ($a_online_status)
995  {
996  case 0:
997  case 1:
998  $this->online = $a_online_status;
999  break;
1000  default:
1001  $this->online = 0;
1002  break;
1003  }
1004  }
1005 
1006  function getOnline()
1007  {
1008  if (strcmp($this->online, "") == 0) $this->online = "0";
1009  return $this->online;
1010  }
1011 
1012  function _lookupOnline($a_obj_id, $is_reference = FALSE)
1013  {
1014  global $ilDB;
1015 
1016  if ($is_reference)
1017  {
1018  $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",
1019  array('integer'),
1020  array($a_obj_id)
1021  );
1022  }
1023  else
1024  {
1025  $result = $ilDB->queryF("SELECT isonline FROM qpl_questionpool WHERE obj_fi = %s",
1026  array('integer'),
1027  array($a_obj_id)
1028  );
1029  }
1030  if ($result->numRows() == 1)
1031  {
1032  $row = $ilDB->fetchAssoc($result);
1033  return $row["isonline"];
1034  }
1035  return 0;
1036  }
1037 
1044  function _hasEqualPoints($a_obj_id, $is_reference = FALSE)
1045  {
1046  global $ilDB;
1047 
1048  if ($is_reference)
1049  {
1050  $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",
1051  array('integer'),
1052  array($a_obj_id)
1053  );
1054  }
1055  else
1056  {
1057  $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",
1058  array('integer'),
1059  array($a_obj_id)
1060  );
1061  }
1062  if ($result->numRows() == 1)
1063  {
1064  $row = $ilDB->fetchAssoc($result);
1065  if ($row["equal_points"] == 1)
1066  {
1067  return 1;
1068  }
1069  else
1070  {
1071  return 0;
1072  }
1073  }
1074  return 0;
1075  }
1076 
1083  {
1084  global $ilDB;
1085 
1086  if (array_key_exists("qpl_clipboard", $_SESSION))
1087  {
1088  foreach ($_SESSION["qpl_clipboard"] as $question_object)
1089  {
1090  if (strcmp($question_object["action"], "move") == 0)
1091  {
1092  $result = $ilDB->queryF("SELECT obj_fi FROM qpl_questions WHERE question_id = %s",
1093  array('integer'),
1094  array($question_object["question_id"])
1095  );
1096  if ($result->numRows() == 1)
1097  {
1098  $row = $ilDB->fetchAssoc($result);
1099  $source_questionpool = $row["obj_fi"];
1100  // change the questionpool id in the qpl_questions table
1101  $affectedRows = $ilDB->manipulateF("UPDATE qpl_questions SET obj_fi = %s WHERE question_id = %s",
1102  array('integer','integer'),
1103  array($this->getId(), $question_object["question_id"])
1104  );
1105 
1106  // move question data to the new target directory
1107  $source_path = CLIENT_WEB_DIR . "/assessment/" . $source_questionpool . "/" . $question_object["question_id"] . "/";
1108  if (@is_dir($source_path))
1109  {
1110  $target_path = CLIENT_WEB_DIR . "/assessment/" . $this->getId() . "/";
1111  if (!@is_dir($target_path))
1112  {
1113  include_once "./Services/Utilities/classes/class.ilUtil.php";
1114  ilUtil::makeDirParents($target_path);
1115  }
1116  @rename($source_path, $target_path . $question_object["question_id"]);
1117  }
1118  // update question count of source question pool
1119  ilObjQuestionPool::_updateQuestionCount($source_questionpool);
1120  }
1121  }
1122  else
1123  {
1124  $this->copyQuestion($question_object["question_id"], $this->getId());
1125  }
1126  }
1127  }
1128  // update question count of question pool
1130  unset($_SESSION["qpl_clipboard"]);
1131  }
1132 
1139  function copyToClipboard($question_id)
1140  {
1141  if (!array_key_exists("qpl_clipboard", $_SESSION))
1142  {
1143  $_SESSION["qpl_clipboard"] = array();
1144  }
1145  $_SESSION["qpl_clipboard"][$question_id] = array("question_id" => $question_id, "action" => "copy");
1146  }
1147 
1154  function moveToClipboard($question_id)
1155  {
1156  if (!array_key_exists("qpl_clipboard", $_SESSION))
1157  {
1158  $_SESSION["qpl_clipboard"] = array();
1159  }
1160  $_SESSION["qpl_clipboard"][$question_id] = array("question_id" => $question_id, "action" => "move");
1161  }
1162 
1170  function _isWriteable($object_id, $user_id)
1171  {
1172  global $rbacsystem;
1173 
1174  include_once "./classes/class.ilObject.php";
1175  $refs = ilObject::_getAllReferences($object_id);
1176  if (count($refs))
1177  {
1178  foreach ($refs as $ref_id)
1179  {
1180  if ($rbacsystem->checkAccess("write", $ref_id) && (ilObject::_hasUntrashedReference($object_id)))
1181  {
1182  return true;
1183  }
1184  }
1185  }
1186  return false;
1187  }
1188 
1196  function &getQuestionDetails($question_ids)
1197  {
1198  global $ilDB;
1199 
1200  $result = array();
1201  $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");
1202  if ($query_result->numRows())
1203  {
1204  while ($row = $ilDB->fetchAssoc($query_result))
1205  {
1206  array_push($result, $row);
1207  }
1208  }
1209  return $result;
1210  }
1211 
1220  function &getDeleteableQuestionDetails($question_ids)
1221  {
1222  global $ilDB, $ilLog;
1223 
1224  $result = array();
1225  $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");
1226  if ($query_result->numRows())
1227  {
1228  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
1229  while ($row = $ilDB->fetchAssoc($query_result))
1230  {
1231  if (!assQuestion::_isUsedInRandomTest($row["question_id"]))
1232  {
1233  array_push($result, $row);
1234  }
1235  else
1236  {
1237  // the question was used in a random test prior to ILIAS 3.7 so it was inserted
1238  // as a reference to the original question pool object and not as a copy. To allow
1239  // the deletion of the question pool object, a copy must be created and all database references
1240  // of the original question must changed with the reference of the copy
1241 
1242  // 1. Create a copy of the original question
1243  $question =& $this->createQuestion("", $row["question_id"]);
1244  $duplicate_id = $question->object->duplicate(true);
1245  if ($duplicate_id > 0)
1246  {
1247  // 2. replace the question id in the solutions
1248  $affectedRows = $ilDB->manipulateF("UPDATE tst_solutions SET question_fi = %s WHERE question_fi = %s",
1249  array('integer','integer'),
1250  array($duplicate_id, $row["question_id"])
1251  );
1252 
1253  // 3. replace the question id in the question list of random tests
1254  $affectedRows = $ilDB->manipulateF("UPDATE tst_test_rnd_qst SET question_fi = %s WHERE question_fi = %s",
1255  array('integer','integer'),
1256  array($duplicate_id, $row["question_id"])
1257  );
1258 
1259  // 4. replace the question id in the test results
1260  $affectedRows = $ilDB->manipulateF("UPDATE tst_test_result SET question_fi = %s WHERE question_fi = %s",
1261  array('integer','integer'),
1262  array($duplicate_id, $row["question_id"])
1263  );
1264 
1265  // 5. replace the question id in the test&assessment log
1266  $affectedRows = $ilDB->manipulateF("UPDATE ass_log SET question_fi = %s WHERE question_fi = %s",
1267  array('integer','integer'),
1268  array($duplicate_id, $row["question_id"])
1269  );
1270 
1271  // 6. The original question can be deleted, so add it to the list of questions
1272  array_push($result, $row);
1273  }
1274  }
1275  }
1276  }
1277  return $result;
1278  }
1279 
1287  {
1288  global $tree;
1289  $path = $tree->getPathFull($ref_id);
1290  $items = array();
1291  $counter = 0;
1292  foreach ($path as $item)
1293  {
1294  if (($counter > 0) && ($counter < count($path)-1))
1295  {
1296  array_push($items, $item["title"]);
1297  }
1298  $counter++;
1299  }
1300  $fullpath = join(" > ", $items);
1301  include_once "./Services/Utilities/classes/class.ilStr.php";
1302  if (strlen($fullpath) > 60)
1303  {
1304  $fullpath = ilStr::subStr($fullpath, 0, 30) . "..." . ilStr::subStr($fullpath, ilStr::strLen($fullpath)-30, 30);
1305  }
1306  return $fullpath;
1307  }
1308 
1315  function &_getAvailableQuestionpools($use_object_id = FALSE, $equal_points = FALSE, $could_be_offline = FALSE, $showPath = FALSE, $with_questioncount = FALSE, $permission = "read", $usr_id = "")
1316  {
1317  global $ilUser;
1318  global $ilDB;
1319 
1320  $result_array = array();
1321  $permission = (strlen($permission) == 0) ? "read" : $permission;
1322  $qpls = ilUtil::_getObjectsByOperations("qpl", $permission, (strlen($usr_id)) ? $usr_id : $ilUser->getId(), -1);
1323  $obj_ids = array();
1324  foreach ($qpls as $ref_id)
1325  {
1326  $obj_id = ilObject::_lookupObjId($ref_id);
1327  $obj_ids[$ref_id] = $obj_id;
1328  }
1329  $titles = ilObject::_prepareCloneSelection($qpls, "qpl");
1330  if (count($obj_ids))
1331  {
1332  $in = $ilDB->in('object_data.obj_id', $obj_ids, false, 'integer');
1333  if ($could_be_offline)
1334  {
1335  $result = $ilDB->query("SELECT qpl_questionpool.*, object_data.title FROM qpl_questionpool, object_data WHERE ".
1336  "qpl_questionpool.obj_fi = object_data.obj_id AND $in ORDER BY object_data.title");
1337  }
1338  else
1339  {
1340  $result = $ilDB->queryF("SELECT qpl_questionpool.*, object_data.title FROM qpl_questionpool, object_data WHERE ".
1341  "qpl_questionpool.obj_fi = object_data.obj_id AND $in AND qpl_questionpool.isonline = %s ".
1342  "ORDER BY object_data.title",
1343  array('text'),
1344  array(1)
1345  );
1346  }
1347  while ($row = $ilDB->fetchAssoc($result))
1348  {
1349  $add = TRUE;
1350  if ($equal_points)
1351  {
1352  if (!ilObjQuestionPool::_hasEqualPoints($row["obj_fi"]))
1353  {
1354  $add = FALSE;
1355  }
1356  }
1357  if ($add)
1358  {
1359  $ref_id = array_search($row["obj_fi"], $obj_ids);
1360  $title = (($showPath) ? $titles[$ref_id] : $row["title"]);
1361  if ($with_questioncount)
1362  {
1363  $title .= " [" . $row["questioncount"] . " " . ($row["questioncount"] == 1 ? $this->lng->txt("ass_question") : $this->lng->txt("assQuestions")) . "]";
1364  }
1365 
1366  if ($use_object_id)
1367  {
1368  $result_array[$row["obj_fi"]] = array("title" => $title, "count" => $row["questioncount"]);
1369  }
1370  else
1371  {
1372  $result_array[$ref_id] = array("title" => $title, "count" => $row["questioncount"]);
1373  }
1374  }
1375  }
1376  }
1377  return $result_array;
1378  }
1379 
1380  function &getQplQuestions()
1381  {
1382  global $ilDB;
1383 
1384  $questions = array();
1385  $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",
1386  array('integer'),
1387  array($this->getId())
1388  );
1389  while ($row = $ilDB->fetchAssoc($result))
1390  {
1391  array_push($questions, $row["question_id"]);
1392  }
1393  return $questions;
1394  }
1395 
1401  function cloneObject($a_target_id,$a_copy_id = 0)
1402  {
1403  global $ilLog;
1404  $newObj = parent::cloneObject($a_target_id,$a_copy_id);
1405  $newObj->setOnline($this->getOnline());
1406  $newObj->saveToDb();
1407  // clone the questions in the question pool
1408  $questions =& $this->getQplQuestions();
1409  foreach ($questions as $question_id)
1410  {
1411  $newObj->copyQuestion($question_id, $newObj->getId());
1412  }
1413 
1414  // clone meta data
1415  include_once "./Services/MetaData/classes/class.ilMD.php";
1416  $md = new ilMD($this->getId(),0,$this->getType());
1417  $new_md =& $md->cloneMD($newObj->getId(),0,$newObj->getType());
1418 
1419  // update the metadata with the new title of the question pool
1420  $newObj->updateMetaData();
1421  return $newObj;
1422  }
1423 
1424  function &getQuestionTypes($all_tags = FALSE)
1425  {
1426  return $this->_getQuestionTypes($all_tags);
1427  }
1428 
1429  function &_getQuestionTypes($all_tags = FALSE)
1430  {
1431  global $ilDB;
1432  global $lng;
1433 
1434  include_once "./Modules/Test/classes/class.ilObjAssessmentFolder.php";
1436  $lng->loadLanguageModule("assessment");
1437  $result = $ilDB->query("SELECT * FROM qpl_qst_type");
1438  $types = array();
1439  while ($row = $ilDB->fetchAssoc($result))
1440  {
1441  if ($all_tags || (!in_array($row["question_type_id"], $forbidden_types)))
1442  {
1443  global $ilLog;
1444 
1445  if ($row["plugin"] == 0)
1446  {
1447  $types[$lng->txt($row["type_tag"])] = $row;
1448  }
1449  else
1450  {
1451  global $ilPluginAdmin;
1452  $pl_names = $ilPluginAdmin->getActivePluginsForSlot(IL_COMP_MODULE, "TestQuestionPool", "qst");
1453  foreach ($pl_names as $pl_name)
1454  {
1455  $pl = ilPlugin::getPluginObject(IL_COMP_MODULE, "TestQuestionPool", "qst", $pl_name);
1456  if (strcmp($pl->getQuestionType(), $row["type_tag"]) == 0)
1457  {
1458  $types[$pl->getQuestionTypeTranslation()] = $row;
1459  }
1460  }
1461  }
1462  }
1463  }
1464  ksort($types);
1465  return $types;
1466  }
1467 
1468  public function &getQuestionTypeTranslations()
1469  {
1470  global $ilDB;
1471  global $lng;
1472  global $ilLog;
1473  global $ilPluginAdmin;
1474 
1475  $lng->loadLanguageModule("assessment");
1476  $result = $ilDB->query("SELECT * FROM qpl_qst_type");
1477  $types = array();
1478  while ($row = $ilDB->fetchAssoc($result))
1479  {
1480  if ($row["plugin"] == 0)
1481  {
1482  $types[$row['type_tag']] = $lng->txt($row["type_tag"]);
1483  }
1484  else
1485  {
1486  $pl_names = $ilPluginAdmin->getActivePluginsForSlot(IL_COMP_MODULE, "TestQuestionPool", "qst");
1487  foreach ($pl_names as $pl_name)
1488  {
1489  $pl = ilPlugin::getPluginObject(IL_COMP_MODULE, "TestQuestionPool", "qst", $pl_name);
1490  if (strcmp($pl->getQuestionType(), $row["type_tag"]) == 0)
1491  {
1492  $types[$row['type_tag']] = $pl->getQuestionTypeTranslation();
1493  }
1494  }
1495  }
1496  }
1497  ksort($types);
1498  return $types;
1499  }
1500 
1506  static function &_getSelfAssessmentQuestionTypes($all_tags = FALSE)
1507  {
1508  $allowed_types = array("assImagemapQuestion", "assMatchingQuestion",
1509  "assTextQuestion",
1510  "assClozeTest", "assMultipleChoice", "assSingleChoice", "assOrderingQuestion");
1511  $satypes = array();
1512  $qtypes = ilObjQuestionPool::_getQuestionTypes($all_tags);
1513  foreach($qtypes as $k => $t)
1514  {
1515  if (in_array($t["type_tag"], $allowed_types))
1516  {
1517  $satypes[$k] = $t;
1518  }
1519  }
1520  return $satypes;
1521  }
1522 
1523 
1524  function &getQuestionList()
1525  {
1526  global $ilDB;
1527 
1528  $questions = array();
1529  $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",
1530  array('integer'),
1531  array($this->getId())
1532  );
1533  while ($row = $ilDB->fetchAssoc($result))
1534  {
1535  array_push($questions, $row);
1536  }
1537  return $questions;
1538  }
1539 
1546  public static function _updateQuestionCount($object_id)
1547  {
1548  global $ilDB;
1549  $result = $ilDB->manipulateF("UPDATE qpl_questionpool SET questioncount = %s, tstamp = %s WHERE obj_fi = %s",
1550  array('integer','integer','integer'),
1551  array(ilObjQuestionPool::_getQuestionCount($object_id, TRUE), time(), $object_id)
1552  );
1553  }
1554 
1561  function isPluginActive($a_pname)
1562  {
1563  global $ilPluginAdmin;
1564  if ($ilPluginAdmin->isActive(IL_COMP_MODULE, "TestQuestionPool", "qst", $a_pname))
1565  {
1566  return TRUE;
1567  }
1568  else
1569  {
1570  return FALSE;
1571  }
1572  }
1573 
1574  /*
1575  * Remove all questions with owner = 0
1576  */
1577  public function purgeQuestions()
1578  {
1579  global $ilDB, $ilUser;
1580 
1581  $result = $ilDB->queryF("SELECT question_id FROM qpl_questions WHERE owner = %s AND tstamp = %s",
1582  array("integer", "integer"),
1583  array($ilUser->getId(), 0)
1584  );
1585  while ($data = $ilDB->fetchAssoc($result))
1586  {
1587  $this->deleteQuestion($data["question_id"]);
1588  }
1589  }
1590 } // END class.ilObjQuestionPool
1591 ?>