ILIAS  Release_4_4_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.assImagemapQuestion.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 require_once './Modules/TestQuestionPool/classes/class.assQuestion.php';
5 require_once './Modules/Test/classes/inc.AssessmentConstants.php';
6 require_once './Modules/TestQuestionPool/interfaces/interface.ilObjQuestionScoringAdjustable.php';
7 require_once './Modules/TestQuestionPool/interfaces/interface.ilObjAnswerScoringAdjustable.php';
8 
22 class assImagemapQuestion extends assQuestion //implements ilObjQuestionScoringAdjustable, ilObjAnswerScoringAdjustable
23 {
24  const MODE_SINGLE_CHOICE = 0;
26 
28  var $answers;
29 
32 
35 
37  var $coords;
38 
40  protected $is_multiple_choice = false;
41 
56  public function __construct(
57  $title = "",
58  $comment = "",
59  $author = "",
60  $owner = -1,
61  $question = "",
62  $image_filename = ""
63  )
64  {
66  $this->image_filename = $image_filename;
67  $this->answers = array();
68  $this->coords = array();
69  }
70 
77  {
78  $this->is_multiple_choice = $is_multiple_choice;
79  }
80 
86  public function getIsMultipleChoice()
87  {
89  }
90 
97  function isComplete()
98  {
99  if (strlen($this->title)
100  && ($this->author)
101  && ($this->question)
102  && ($this->image_filename)
103  && (count($this->answers))
104  && ($this->getMaximumPoints() > 0)
105  )
106  {
107  return true;
108  }
109  return false;
110  }
111 
121  public function saveToDb($original_id = "")
122  {
127  }
128 
129  public function saveAnswerSpecificDataToDb()
130  {
131  global $ilDB;
132  $ilDB->manipulateF( "DELETE FROM qpl_a_imagemap WHERE question_fi = %s",
133  array( "integer" ),
134  array( $this->getId() )
135  );
136 
137  // Anworten wegschreiben
138  foreach ($this->answers as $key => $value)
139  {
140  $answer_obj = $this->answers[$key];
141  $next_id = $ilDB->nextId( 'qpl_a_imagemap' );
142  $ilDB->manipulateF( "INSERT INTO qpl_a_imagemap (answer_id, question_fi, answertext, points, aorder, coords, area, points_unchecked) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)",
143  array( "integer", "integer", "text", "float", "integer", "text", "text", "float" ),
144  array( $next_id, $this->id, $answer_obj->getAnswertext(
145  ), $answer_obj->getPoints(), $answer_obj->getOrder(
146  ), $answer_obj->getCoords(), $answer_obj->getArea(
147  ), $answer_obj->getPointsUnchecked() )
148  );
149  }
150  }
151 
153  {
154  global $ilDB;
155 
156  $ilDB->manipulateF( "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
157  array( "integer" ),
158  array( $this->getId() )
159  );
160 
161  $ilDB->manipulateF( "INSERT INTO " . $this->getAdditionalTableName(
162  ) . " (question_fi, image_file, is_multiple_choice) VALUES (%s, %s, %s)",
163  array( "integer", "text", 'integer' ),
164  array(
165  $this->getId(),
166  $this->image_filename,
167  (int)$this->is_multiple_choice
168  )
169  );
170  }
171 
177  function duplicate($for_test = true, $title = "", $author = "", $owner = "", $testObjId = null)
178  {
179  if ($this->id <= 0)
180  {
181  // The question has not been saved. It cannot be duplicated
182  return;
183  }
184  // duplicate the question in database
185  $this_id = $this->getId();
186  $thisObjId = $this->getObjId();
187 
188  $clone = $this;
189  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
191  $clone->id = -1;
192 
193  if( (int)$testObjId > 0 )
194  {
195  $clone->setObjId($testObjId);
196  }
197 
198  if ($title)
199  {
200  $clone->setTitle($title);
201  }
202  if ($author)
203  {
204  $clone->setAuthor($author);
205  }
206  if ($owner)
207  {
208  $clone->setOwner($owner);
209  }
210  if ($for_test)
211  {
212  $clone->saveToDb($original_id);
213  }
214  else
215  {
216  $clone->saveToDb();
217  }
218 
219  // copy question page content
220  $clone->copyPageOfQuestion($this_id);
221  // copy XHTML media objects
222  $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
223  // duplicate the image
224  $clone->duplicateImage($this_id, $thisObjId);
225 
226  $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
227 
228  return $clone->id;
229  }
230 
238  function copyObject($target_questionpool_id, $title = "")
239  {
240  if ($this->id <= 0)
241  {
242  // The question has not been saved. It cannot be duplicated
243  return;
244  }
245  // duplicate the question in database
246  $clone = $this;
247  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
249  $clone->id = -1;
250  $source_questionpool_id = $this->getObjId();
251  $clone->setObjId($target_questionpool_id);
252  if ($title)
253  {
254  $clone->setTitle($title);
255  }
256  $clone->saveToDb();
257 
258  // copy question page content
259  $clone->copyPageOfQuestion($original_id);
260  // copy XHTML media objects
261  $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
262  // duplicate the image
263  $clone->copyImage($original_id, $source_questionpool_id);
264 
265  $clone->onCopy($source_questionpool_id, $original_id, $clone->getObjId(), $clone->getId());
266 
267  return $clone->id;
268  }
269 
270  public function createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle = "")
271  {
272  if ($this->id <= 0)
273  {
274  // The question has not been saved. It cannot be duplicated
275  return;
276  }
277 
278  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
279 
280  $sourceQuestionId = $this->id;
281  $sourceParentId = $this->getObjId();
282 
283  // duplicate the question in database
284  $clone = $this;
285  $clone->id = -1;
286 
287  $clone->setObjId($targetParentId);
288 
289  if ($targetQuestionTitle)
290  {
291  $clone->setTitle($targetQuestionTitle);
292  }
293 
294  $clone->saveToDb();
295  // copy question page content
296  $clone->copyPageOfQuestion($sourceQuestionId);
297  // copy XHTML media objects
298  $clone->copyXHTMLMediaObjectsOfQuestion($sourceQuestionId);
299  // duplicate the image
300  $clone->copyImage($sourceQuestionId, $sourceParentId);
301 
302  $clone->onCopy($sourceParentId, $sourceQuestionId, $clone->getObjId(), $clone->getId());
303 
304  return $clone->id;
305  }
306 
307  function duplicateImage($question_id, $objectId = null)
308  {
309  $imagepath = $this->getImagePath();
310  $imagepath_original = str_replace("/$this->id/images", "/$question_id/images", $imagepath);
311 
312  if( (int)$objectId > 0 )
313  {
314  $imagepath_original = str_replace("/$this->obj_id/", "/$objectId/", $imagepath_original);
315  }
316 
317  if (!file_exists($imagepath)) {
318  ilUtil::makeDirParents($imagepath);
319  }
320  $filename = $this->getImageFilename();
321  if (!copy($imagepath_original . $filename, $imagepath . $filename)) {
322  print "image could not be duplicated!!!! ";
323  }
324  }
325 
326  function copyImage($question_id, $source_questionpool)
327  {
328  $imagepath = $this->getImagePath();
329  $imagepath_original = str_replace("/$this->id/images", "/$question_id/images", $imagepath);
330  $imagepath_original = str_replace("/$this->obj_id/", "/$source_questionpool/", $imagepath_original);
331  if (!file_exists($imagepath))
332  {
333  ilUtil::makeDirParents($imagepath);
334  }
335  $filename = $this->getImageFilename();
336  if (!copy($imagepath_original . $filename, $imagepath . $filename))
337  {
338  print "image could not be copied!!!! ";
339  }
340  }
341 
351  function loadFromDb($question_id)
352  {
353  global $ilDB;
354 
355  $result = $ilDB->queryF("SELECT qpl_questions.*, " . $this->getAdditionalTableName() . ".* FROM qpl_questions LEFT JOIN " . $this->getAdditionalTableName() . " ON " . $this->getAdditionalTableName() . ".question_fi = qpl_questions.question_id WHERE qpl_questions.question_id = %s",
356  array("integer"),
357  array($question_id)
358  );
359  if ($result->numRows() == 1)
360  {
361  $data = $ilDB->fetchAssoc($result);
362  $this->setId($question_id);
363  $this->setObjId($data["obj_fi"]);
364  $this->setTitle($data["title"]);
365  $this->setComment($data["description"]);
366  $this->setOriginalId($data["original_id"]);
367  $this->setNrOfTries($data['nr_of_tries']);
368  $this->setAuthor($data["author"]);
369  $this->setPoints($data["points"]);
370  $this->setOwner($data["owner"]);
371  $this->setIsMultipleChoice($data["is_multiple_choice"] == self::MODE_MULTIPLE_CHOICE);
372  include_once("./Services/RTE/classes/class.ilRTE.php");
373  $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc($data["question_text"], 1));
374  $this->setImageFilename($data["image_file"]);
375  $this->setEstimatedWorkingTime(substr($data["working_time"], 0, 2), substr($data["working_time"], 3, 2), substr($data["working_time"], 6, 2));
376 
377  try
378  {
379  $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
380  }
382  {
383  }
384 
385  $result = $ilDB->queryF("SELECT * FROM qpl_a_imagemap WHERE question_fi = %s ORDER BY aorder ASC",
386  array("integer"),
387  array($question_id)
388  );
389  include_once "./Modules/TestQuestionPool/classes/class.assAnswerImagemap.php";
390  if ($result->numRows() > 0)
391  {
392  while ($data = $ilDB->fetchAssoc($result))
393  {
394  array_push($this->answers, new ASS_AnswerImagemap($data["answertext"], $data["points"], $data["aorder"], $data["coords"], $data["area"], $data['question_fi'], $data['points_unchecked']));
395  }
396  }
397  }
398  parent::loadFromDb($question_id);
399  }
400 
407  function uploadImagemap($imagemap_filename = "")
408  {
409  $added = 0;
410  if (!empty($imagemap_filename))
411  {
412  $fp = fopen($imagemap_filename, "r");
413  $contents = fread($fp, filesize($imagemap_filename));
414  fclose($fp);
415  if (preg_match_all("/<area(.+)>/siU", $contents, $matches))
416  {
417  for ($i=0; $i< count($matches[1]); $i++)
418  {
419  preg_match("/alt\s*=\s*\"(.+)\"\s*/siU", $matches[1][$i], $alt);
420  preg_match("/coords\s*=\s*\"(.+)\"\s*/siU", $matches[1][$i], $coords);
421  preg_match("/shape\s*=\s*\"(.+)\"\s*/siU", $matches[1][$i], $shape);
422  $this->addAnswer($alt[1], 0.0, count($this->answers), $coords[1], $shape[1]);
423  $added++;
424  }
425  }
426  }
427  return $added;
428  }
429 
430  function getImageFilename()
431  {
432  return $this->image_filename;
433  }
434 
442  function setImageFilename($image_filename, $image_tempfilename = "")
443  {
444  if (!empty($image_filename))
445  {
446  $image_filename = str_replace(" ", "_", $image_filename);
447  $this->image_filename = $image_filename;
448  }
449  if (!empty($image_tempfilename))
450  {
451  $imagepath = $this->getImagePath();
452  if (!file_exists($imagepath))
453  {
454  ilUtil::makeDirParents($imagepath);
455  }
456  if (!ilUtil::moveUploadedFile($image_tempfilename, $image_filename, $imagepath.$image_filename))
457  {
458  $this->ilias->raiseError("The image could not be uploaded!", $this->ilias->error_obj->MESSAGE);
459  }
460  global $ilLog; $ilLog->write("gespeichert: " . $imagepath.$image_filename);
461  }
462  }
463 
473  function get_imagemap_contents($href = "#") {
474  $imagemap_contents = "<map name=\"".$this->title."\"> ";
475  for ($i = 0; $i < count($this->answers); $i++) {
476  $imagemap_contents .= "<area alt=\"".$this->answers[$i]->getAnswertext()."\" ";
477  $imagemap_contents .= "shape=\"".$this->answers[$i]->getArea()."\" ";
478  $imagemap_contents .= "coords=\"".$this->answers[$i]->getCoords()."\" ";
479  $imagemap_contents .= "href=\"$href&selimage=" . $this->answers[$i]->getOrder() . "\" /> ";
480  }
481  $imagemap_contents .= "</map>";
482  return $imagemap_contents;
483  }
484 
499  function addAnswer(
500  $answertext = "",
501  $points = 0.0,
502  $order = 0,
503  $coords="",
504  $area="",
505  $points_unchecked = 0.0
506  )
507  {
508  include_once "./Modules/TestQuestionPool/classes/class.assAnswerImagemap.php";
509  if (array_key_exists($order, $this->answers))
510  {
511  // Insert answer
512  $answer = new ASS_AnswerImagemap($answertext, $points, $order, $coords, $area, -1, $points_unchecked);
513  for ($i = count($this->answers) - 1; $i >= $order; $i--)
514  {
515  $this->answers[$i+1] = $this->answers[$i];
516  $this->answers[$i+1]->setOrder($i+1);
517  }
518  $this->answers[$order] = $answer;
519  }
520  else
521  {
522  // Append answer
523  $answer = new ASS_AnswerImagemap($answertext, $points, count($this->answers), $coords, $area, -1, $points_unchecked);
524  array_push($this->answers, $answer);
525  }
526  }
527 
537  function getAnswerCount() {
538  return count($this->answers);
539  }
540 
552  function getAnswer($index = 0) {
553  if ($index < 0) return NULL;
554  if (count($this->answers) < 1) return NULL;
555  if ($index >= count($this->answers)) return NULL;
556  return $this->answers[$index];
557  }
558 
568  function &getAnswers()
569  {
570  return $this->answers;
571  }
572 
583  function deleteArea($index = 0)
584  {
585  if ($index < 0) return;
586  if (count($this->answers) < 1) return;
587  if ($index >= count($this->answers)) return;
588  unset($this->answers[$index]);
589  $this->answers = array_values($this->answers);
590  for ($i = 0; $i < count($this->answers); $i++) {
591  if ($this->answers[$i]->getOrder() > $index) {
592  $this->answers[$i]->setOrder($i);
593  }
594  }
595  }
596 
605  function flushAnswers() {
606  $this->answers = array();
607  }
608 
617  function getMaximumPoints() {
618  $points = 0;
619  foreach ($this->answers as $key => $value) {
620  if($this->is_multiple_choice)
621  {
622  if($value->getPoints() > $value->getPointsUnchecked())
623  {
624  $points += $value->getPoints();
625  }
626  else
627  {
628  $points += $value->getPointsUnchecked();
629  }
630  }
631  else
632  {
633  if($value->getPoints() > $points)
634  {
635  $points = $value->getPoints();
636  }
637  }
638  }
639  return $points;
640  }
641 
652  public function calculateReachedPoints($active_id, $pass = NULL, $returndetails = FALSE)
653  {
654  if( $returndetails )
655  {
656  throw new ilTestException('return details not implemented for '.__METHOD__);
657  }
658 
659  global $ilDB;
660 
661  $found_values = array();
662  if (is_null($pass))
663  {
664  $pass = $this->getSolutionMaxPass($active_id);
665  }
666  $result = $ilDB->queryF("SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
667  array("integer","integer","integer"),
668  array($active_id, $this->getId(), $pass)
669  );
670  while ($data = $ilDB->fetchAssoc($result))
671  {
672  if (strcmp($data["value1"], "") != 0)
673  {
674  array_push($found_values, $data["value1"]);
675  }
676  }
677  $points = 0;
678  if (count($found_values) > 0)
679  {
680  foreach ($this->answers as $key => $answer)
681  {
682  if (in_array($key, $found_values))
683  {
684  $points += $answer->getPoints();
685  }
686  elseif( $this->getIsMultipleChoice() )
687  {
688  $points += $answer->getPointsUnchecked();
689  }
690  }
691  }
692 
693  return $points;
694  }
695 
704  public function saveWorkingData($active_id, $pass = NULL)
705  {
706  global $ilDB;
707  global $ilUser;
708 
709  if (is_null($pass))
710  {
711  include_once "./Modules/Test/classes/class.ilObjTest.php";
712  $pass = ilObjTest::_getPass($active_id);
713  }
714 
715  $this->getProcessLocker()->requestUserSolutionUpdateLock();
716 
717  if($this->is_multiple_choice && strlen($_GET['remImage']))
718  {
719  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s AND value1 = %s",
720  array("integer", "integer", "integer", "integer"),
721  array($active_id, $this->getId(), $pass, $_GET['remImage'])
722  );
723  }
724  elseif(!$this->is_multiple_choice)
725  {
726  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
727  array("integer", "integer", "integer"),
728  array($active_id, $this->getId(), $pass)
729  );
730  }
731 
732  if (strlen($_GET["selImage"]))
733  {
734  $imageWasSelected = true;
735 
736  $types = array('integer', 'integer', 'integer', 'integer');
737  $values = array($active_id, $this->getId(), $pass, (int)$_GET['selImage']);
738  $query = 'DELETE FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s AND value1 = %s';
739 
740  $ilDB->manipulateF($query, $types, $values);
741 
742  $next_id = $ilDB->nextId('tst_solutions');
743  $affectedRows = $ilDB->insert("tst_solutions", array(
744  "solution_id" => array("integer", $next_id),
745  "active_fi" => array("integer", $active_id),
746  "question_fi" => array("integer", $this->getId()),
747  "value1" => array("clob", $_GET['selImage']),
748  "value2" => array("clob", null),
749  "pass" => array("integer", $pass),
750  "tstamp" => array("integer", time())
751  ));
752  }
753  else
754  {
755  $imageWasSelected = false;
756  }
757 
758  $this->getProcessLocker()->releaseUserSolutionUpdateLock();
759 
760  require_once 'Modules/Test/classes/class.ilObjAssessmentFolder.php';
762  {
763  if( $imageWasSelected )
764  {
765  $this->logAction($this->lng->txtlng("assessment", "log_user_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
766  }
767  else
768  {
769  $this->logAction($this->lng->txtlng("assessment", "log_user_not_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
770  }
771  }
772 
773  return true;
774  }
775 
784  protected function reworkWorkingData($active_id, $pass, $obligationsAnswered)
785  {
786  // nothing to rework!
787  }
788 
789  function syncWithOriginal()
790  {
791  if ($this->getOriginalId())
792  {
794  }
795  }
796 
805  function getQuestionType()
806  {
807  return "assImagemapQuestion";
808  }
809 
819  {
820  return "qpl_qst_imagemap";
821  }
822 
832  {
833  return "qpl_a_imagemap";
834  }
835 
841  {
843  foreach ($this->answers as $index => $answer)
844  {
845  $text .= $this->feedbackOBJ->getSpecificAnswerFeedbackContent($this->getId(), $index);
846  }
847  return $text;
848  }
849 
862  public function setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
863  {
864  include_once ("./Services/Excel/classes/class.ilExcelUtils.php");
865  $solution = $this->getSolutionValues($active_id, $pass);
866  $worksheet->writeString($startrow, 0, ilExcelUtils::_convert_text($this->lng->txt($this->getQuestionType())), $format_title);
867  $worksheet->writeString($startrow, 1, ilExcelUtils::_convert_text($this->getTitle()), $format_title);
868  $i = 1;
869  foreach ($this->getAnswers() as $id => $answer)
870  {
871  $worksheet->writeString($startrow + $i, 0, ilExcelUtils::_convert_text($answer->getArea() . ": " . $answer->getCoords()), $format_bold);
872  if ($id == $solution[0]["value1"])
873  {
874  $worksheet->write($startrow + $i, 1, 1);
875  }
876  else
877  {
878  $worksheet->write($startrow + $i, 1, 0);
879  }
880  $i++;
881  }
882  return $startrow + $i + 1;
883  }
884 
888  public function deleteImage()
889  {
890  $file = $this->getImagePath() . $this->getImageFilename();
891  @unlink($file);
892  $this->flushAnswers();
893  $this->image_filename = "";
894  }
895 
899  public function toJSON()
900  {
901  include_once("./Services/RTE/classes/class.ilRTE.php");
902  $result = array();
903  $result['id'] = (int) $this->getId();
904  $result['type'] = (string) $this->getQuestionType();
905  $result['title'] = (string) $this->getTitle();
906  $result['question'] = $this->formatSAQuestion($this->getQuestion());
907  $result['nr_of_tries'] = (int) $this->getNrOfTries();
908  $result['shuffle'] = (bool) $this->getShuffle();
909  $result['is_multiple'] = (bool) $this->getIsMultipleChoice();
910  $result['feedback'] = array(
911  "onenotcorrect" => $this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), false),
912  "allcorrect" => $this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), true)
913  );
914  $result['image'] = (string) $this->getImagePathWeb() . $this->getImageFilename();
915 
916  $answers = array();
917  $order = 0;
918  foreach ($this->getAnswers() as $key => $answer_obj)
919  {
920  array_push($answers, array(
921  "answertext" => (string)$answer_obj->getAnswertext(),
922  "points" => (float)$answer_obj->getPoints(),
923  "points_unchecked" => (float)$answer_obj->getPointsUnchecked(),
924  "order" => (int)$order,
925  "coords" => $answer_obj->getCoords(),
926  "state" => $answer_obj->getState(),
927  "area" => $answer_obj->getArea(),
929  $this->feedbackOBJ->getSpecificAnswerFeedbackExportPresentation($this->getId(), $key), 0
930  )
931  ));
932  $order++;
933  }
934  $result['answers'] = $answers;
935 
936  $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $this->getId());
937  $result['mobs'] = $mobs;
938 
939  return json_encode($result);
940  }
941 }