ILIAS  release_4-3 Revision
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.assImagemapQuestion.php
Go to the documentation of this file.
1 <?php
2 
3 /* Copyright (c) 1998-2010 ILIAS open source, Extended GPL, see docs/LICENSE */
4 
5 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
6 include_once "./Modules/Test/classes/inc.AssessmentConstants.php";
7 
22 {
23 
31  var $answers;
32 
41 
50  var $coords;
51 
65  function __construct(
66  $title = "",
67  $comment = "",
68  $author = "",
69  $owner = -1,
70  $question = "",
71  $image_filename = ""
72  )
73  {
75  $this->image_filename = $image_filename;
76  $this->answers = array();
77  $this->coords = array();
78  }
79 
86  function isComplete()
87  {
88  if (strlen($this->title) and ($this->author) and ($this->question) and ($this->image_filename) and (count($this->answers)) and ($this->getMaximumPoints() > 0))
89  {
90  return true;
91  }
92  else
93  {
94  return false;
95  }
96  }
97 
106  function saveToDb($original_id = "")
107  {
108  global $ilDB;
109 
111 
112  // save additional data
113  $affectedRows = $ilDB->manipulateF("DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
114  array("integer"),
115  array($this->getId())
116  );
117  $affectedRows = $ilDB->manipulateF("INSERT INTO " . $this->getAdditionalTableName() . " (question_fi, image_file) VALUES (%s, %s)",
118  array("integer", "text"),
119  array(
120  $this->getId(),
121  $this->image_filename
122  )
123  );
124 
125  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_a_imagemap WHERE question_fi = %s",
126  array("integer"),
127  array($this->getId())
128  );
129 
130  // Anworten wegschreiben
131  foreach ($this->answers as $key => $value)
132  {
133  $answer_obj = $this->answers[$key];
134  $next_id = $ilDB->nextId('qpl_a_imagemap');
135  $affectedRows = $ilDB->manipulateF("INSERT INTO qpl_a_imagemap (answer_id, question_fi, answertext, points, aorder, coords, area) VALUES (%s, %s, %s, %s, %s, %s, %s)",
136  array("integer","integer","text","float","integer","text","text"),
137  array($next_id, $this->id, $answer_obj->getAnswertext(), $answer_obj->getPoints(), $answer_obj->getOrder(), $answer_obj->getCoords(), $answer_obj->getArea())
138  );
139  }
140 
142  }
143 
149  function duplicate($for_test = true, $title = "", $author = "", $owner = "", $testObjId = null)
150  {
151  if ($this->id <= 0)
152  {
153  // The question has not been saved. It cannot be duplicated
154  return;
155  }
156  // duplicate the question in database
157  $this_id = $this->getId();
158 
159  if( (int)$testObjId > 0 )
160  {
161  $thisObjId = $this->getObjId();
162  }
163 
164  $clone = $this;
165  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
167  $clone->id = -1;
168 
169  if( (int)$testObjId > 0 )
170  {
171  $clone->setObjId($testObjId);
172  }
173 
174  if ($title)
175  {
176  $clone->setTitle($title);
177  }
178  if ($author)
179  {
180  $clone->setAuthor($author);
181  }
182  if ($owner)
183  {
184  $clone->setOwner($owner);
185  }
186  if ($for_test)
187  {
188  $clone->saveToDb($original_id);
189  }
190  else
191  {
192  $clone->saveToDb();
193  }
194 
195  // copy question page content
196  $clone->copyPageOfQuestion($this_id);
197  // copy XHTML media objects
198  $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
199  // duplicate the generic feedback
200  $clone->duplicateGenericFeedback($this_id);
201  // duplicate the answer specific feedback
202  $clone->duplicateFeedbackAnswer($this_id);
203 
204  // duplicate the image
205  $clone->duplicateImage($this_id, $thisObjId);
206 
207  $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
208 
209  return $clone->id;
210  }
211 
219  function copyObject($target_questionpool, $title = "")
220  {
221  if ($this->id <= 0)
222  {
223  // The question has not been saved. It cannot be duplicated
224  return;
225  }
226  // duplicate the question in database
227  $clone = $this;
228  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
230  $clone->id = -1;
231  $source_questionpool = $this->getObjId();
232  $clone->setObjId($target_questionpool);
233  if ($title)
234  {
235  $clone->setTitle($title);
236  }
237  $clone->saveToDb();
238 
239  // copy question page content
240  $clone->copyPageOfQuestion($original_id);
241  // copy XHTML media objects
242  $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
243  // duplicate the generic feedback
244  $clone->duplicateGenericFeedback($original_id);
245  // duplicate the answer specific feedback
246  $clone->duplicateFeedbackAnswer($original_id);
247 
248  // duplicate the image
249  $clone->copyImage($original_id, $source_questionpool);
250  $clone->onCopy($this->getObjId(), $this->getId());
251  return $clone->id;
252  }
253 
254  function duplicateImage($question_id, $objectId = null)
255  {
256  $imagepath = $this->getImagePath();
257  $imagepath_original = str_replace("/$this->id/images", "/$question_id/images", $imagepath);
258 
259  if( (int)$objectId > 0 )
260  {
261  $imagepath_original = str_replace("/$this->obj_id/", "/$objectId/", $imagepath_original);
262  }
263 
264  if (!file_exists($imagepath)) {
265  ilUtil::makeDirParents($imagepath);
266  }
267  $filename = $this->getImageFilename();
268  if (!copy($imagepath_original . $filename, $imagepath . $filename)) {
269  print "image could not be duplicated!!!! ";
270  }
271  }
272 
273  function copyImage($question_id, $source_questionpool)
274  {
275  $imagepath = $this->getImagePath();
276  $imagepath_original = str_replace("/$this->id/images", "/$question_id/images", $imagepath);
277  $imagepath_original = str_replace("/$this->obj_id/", "/$source_questionpool/", $imagepath_original);
278  if (!file_exists($imagepath))
279  {
280  ilUtil::makeDirParents($imagepath);
281  }
282  $filename = $this->getImageFilename();
283  if (!copy($imagepath_original . $filename, $imagepath . $filename))
284  {
285  print "image could not be copied!!!! ";
286  }
287  }
288 
298  function loadFromDb($question_id)
299  {
300  global $ilDB;
301 
302  $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",
303  array("integer"),
304  array($question_id)
305  );
306  if ($result->numRows() == 1)
307  {
308  $data = $ilDB->fetchAssoc($result);
309  $this->setId($question_id);
310  $this->setObjId($data["obj_fi"]);
311  $this->setTitle($data["title"]);
312  $this->setComment($data["description"]);
313  $this->setOriginalId($data["original_id"]);
314  $this->setNrOfTries($data['nr_of_tries']);
315  $this->setAuthor($data["author"]);
316  $this->setPoints($data["points"]);
317  $this->setOwner($data["owner"]);
318  include_once("./Services/RTE/classes/class.ilRTE.php");
319  $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc($data["question_text"], 1));
320  $this->setImageFilename($data["image_file"]);
321  $this->setEstimatedWorkingTime(substr($data["working_time"], 0, 2), substr($data["working_time"], 3, 2), substr($data["working_time"], 6, 2));
322 
323  $result = $ilDB->queryF("SELECT * FROM qpl_a_imagemap WHERE question_fi = %s ORDER BY aorder ASC",
324  array("integer"),
325  array($question_id)
326  );
327  include_once "./Modules/TestQuestionPool/classes/class.assAnswerImagemap.php";
328  if ($result->numRows() > 0)
329  {
330  while ($data = $ilDB->fetchAssoc($result))
331  {
332  array_push($this->answers, new ASS_AnswerImagemap($data["answertext"], $data["points"], $data["aorder"], $data["coords"], $data["area"]));
333  }
334  }
335  }
336  parent::loadFromDb($question_id);
337  }
338 
345  function uploadImagemap($imagemap_filename = "")
346  {
347  $added = 0;
348  if (!empty($imagemap_filename))
349  {
350  $fp = fopen($imagemap_filename, "r");
351  $contents = fread($fp, filesize($imagemap_filename));
352  fclose($fp);
353  if (preg_match_all("/<area(.+)>/siU", $contents, $matches))
354  {
355  for ($i=0; $i< count($matches[1]); $i++)
356  {
357  preg_match("/alt\s*=\s*\"(.+)\"\s*/siU", $matches[1][$i], $alt);
358  preg_match("/coords\s*=\s*\"(.+)\"\s*/siU", $matches[1][$i], $coords);
359  preg_match("/shape\s*=\s*\"(.+)\"\s*/siU", $matches[1][$i], $shape);
360  $this->addAnswer($alt[1], 0.0, count($this->answers), $coords[1], $shape[1]);
361  $added++;
362  }
363  }
364  }
365  return $added;
366  }
367 
368  function getImageFilename()
369  {
370  return $this->image_filename;
371  }
372 
380  function setImageFilename($image_filename, $image_tempfilename = "")
381  {
382  if (!empty($image_filename))
383  {
384  $image_filename = str_replace(" ", "_", $image_filename);
385  $this->image_filename = $image_filename;
386  }
387  if (!empty($image_tempfilename))
388  {
389  $imagepath = $this->getImagePath();
390  if (!file_exists($imagepath))
391  {
392  ilUtil::makeDirParents($imagepath);
393  }
394  if (!ilUtil::moveUploadedFile($image_tempfilename, $image_filename, $imagepath.$image_filename))
395  {
396  $this->ilias->raiseError("The image could not be uploaded!", $this->ilias->error_obj->MESSAGE);
397  }
398  global $ilLog; $ilLog->write("gespeichert: " . $imagepath.$image_filename);
399  }
400  }
401 
411  function get_imagemap_contents($href = "#") {
412  $imagemap_contents = "<map name=\"".$this->title."\"> ";
413  for ($i = 0; $i < count($this->answers); $i++) {
414  $imagemap_contents .= "<area alt=\"".$this->answers[$i]->getAnswertext()."\" ";
415  $imagemap_contents .= "shape=\"".$this->answers[$i]->getArea()."\" ";
416  $imagemap_contents .= "coords=\"".$this->answers[$i]->getCoords()."\" ";
417  $imagemap_contents .= "href=\"$href&selimage=" . $this->answers[$i]->getOrder() . "\" /> ";
418  }
419  $imagemap_contents .= "</map>";
420  return $imagemap_contents;
421  }
422 
437  function addAnswer(
438  $answertext = "",
439  $points = 0.0,
440  $order = 0,
441  $coords="",
442  $area=""
443  )
444  {
445  include_once "./Modules/TestQuestionPool/classes/class.assAnswerImagemap.php";
446  if (array_key_exists($order, $this->answers))
447  {
448  // Insert answer
449  $answer = new ASS_AnswerImagemap($answertext, $points, $order, $coords, $area);
450  for ($i = count($this->answers) - 1; $i >= $order; $i--)
451  {
452  $this->answers[$i+1] = $this->answers[$i];
453  $this->answers[$i+1]->setOrder($i+1);
454  }
455  $this->answers[$order] = $answer;
456  }
457  else
458  {
459  // Append answer
460  $answer = new ASS_AnswerImagemap($answertext, $points, count($this->answers), $coords, $area);
461  array_push($this->answers, $answer);
462  }
463  }
464 
474  function getAnswerCount() {
475  return count($this->answers);
476  }
477 
489  function getAnswer($index = 0) {
490  if ($index < 0) return NULL;
491  if (count($this->answers) < 1) return NULL;
492  if ($index >= count($this->answers)) return NULL;
493  return $this->answers[$index];
494  }
495 
505  function &getAnswers()
506  {
507  return $this->answers;
508  }
509 
520  function deleteArea($index = 0)
521  {
522  if ($index < 0) return;
523  if (count($this->answers) < 1) return;
524  if ($index >= count($this->answers)) return;
525  unset($this->answers[$index]);
526  $this->answers = array_values($this->answers);
527  for ($i = 0; $i < count($this->answers); $i++) {
528  if ($this->answers[$i]->getOrder() > $index) {
529  $this->answers[$i]->setOrder($i);
530  }
531  }
532  }
533 
542  function flushAnswers() {
543  $this->answers = array();
544  }
545 
554  function getMaximumPoints() {
555  $points = 0;
556  foreach ($this->answers as $key => $value) {
557  if ($value->getPoints() > $points)
558  {
559  $points = $value->getPoints();
560  }
561  }
562  return $points;
563  }
564 
575  public function calculateReachedPoints($active_id, $pass = NULL, $returndetails = FALSE)
576  {
577  if( $returndetails )
578  {
579  throw new ilTestException('return details not implemented for '.__METHOD__);
580  }
581 
582  global $ilDB;
583 
584  $found_values = array();
585  if (is_null($pass))
586  {
587  $pass = $this->getSolutionMaxPass($active_id);
588  }
589  $result = $ilDB->queryF("SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
590  array("integer","integer","integer"),
591  array($active_id, $this->getId(), $pass)
592  );
593  while ($data = $ilDB->fetchAssoc($result))
594  {
595  if (strcmp($data["value1"], "") != 0)
596  {
597  array_push($found_values, $data["value1"]);
598  }
599  }
600  $points = 0;
601  if (count($found_values) > 0)
602  {
603  foreach ($this->answers as $key => $answer)
604  {
605  if (in_array($key, $found_values))
606  {
607  $points += $answer->getPoints();
608  }
609  }
610  }
611 
612  return $points;
613  }
614 
623  public function saveWorkingData($active_id, $pass = NULL)
624  {
625  global $ilDB;
626  global $ilUser;
627 
628  if (is_null($pass))
629  {
630  include_once "./Modules/Test/classes/class.ilObjTest.php";
631  $pass = ilObjTest::_getPass($active_id);
632  }
633 
634  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
635  array("integer","integer","integer"),
636  array($active_id, $this->getId(), $pass)
637  );
638 
639  if (strlen($_GET["selImage"]))
640  {
641  $next_id = $ilDB->nextId('tst_solutions');
642  $affectedRows = $ilDB->insert("tst_solutions", array(
643  "solution_id" => array("integer", $next_id),
644  "active_fi" => array("integer", $active_id),
645  "question_fi" => array("integer", $this->getId()),
646  "value1" => array("clob", $_GET['selImage']),
647  "value2" => array("clob", null),
648  "pass" => array("integer", $pass),
649  "tstamp" => array("integer", time())
650  ));
651 
652  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
654  {
655  $this->logAction($this->lng->txtlng("assessment", "log_user_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
656  }
657  }
658  else
659  {
660  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
662  {
663  $this->logAction($this->lng->txtlng("assessment", "log_user_not_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
664  }
665  }
666 
667  return true;
668  }
669 
678  protected function reworkWorkingData($active_id, $pass, $obligationsAnswered)
679  {
680  // nothing to rework!
681  }
682 
683  function syncWithOriginal()
684  {
685  if ($this->getOriginalId())
686  {
688  $this->syncFeedbackSingleAnswers();
689  }
690  }
691 
700  function getQuestionType()
701  {
702  return "assImagemapQuestion";
703  }
704 
714  {
715  return "qpl_qst_imagemap";
716  }
717 
727  {
728  return "qpl_a_imagemap";
729  }
730 
738  function saveFeedbackSingleAnswer($answer_index, $feedback)
739  {
740  global $ilDB;
741 
742  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_fb_imap WHERE question_fi = %s AND answer = %s",
743  array("integer","integer"),
744  array($this->getId(), $answer_index)
745  );
746  if (strlen($feedback))
747  {
748  include_once("./Services/RTE/classes/class.ilRTE.php");
749  $next_id = $ilDB->nextId('qpl_fb_imap');
750 
752  $ilDB->insert('qpl_fb_imap', array(
753  'feedback_id' => array( 'integer', $next_id ),
754  'question_fi' => array( 'integer', $this->getId() ),
755  'answer' => array( 'integer', $answer_index ),
756  'feedback' => array( 'clob', ilRTE::_replaceMediaObjectImageSrc($feedback, 0) ),
757  'tstamp' => array( 'integer', time() ),
758  )
759  );
760  }
761  }
762 
768  function syncFeedbackSingleAnswers()
769  {
770  global $ilDB;
771 
772  $feedback = "";
773 
774  // delete generic feedback of the original
775  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_fb_imap WHERE question_fi = %s",
776  array('integer'),
777  array($this->original_id)
778  );
779 
780  // get generic feedback of the actual question
781  $result = $ilDB->queryF("SELECT * FROM qpl_fb_imap WHERE question_fi = %s",
782  array("integer"),
783  array($this->getId())
784  );
785 
786  // save generic feedback to the original
787  if ($result->numRows())
788  {
789  while ($row = $ilDB->fetchAssoc($result))
790  {
791  $next_id = $ilDB->nextId('qpl_fb_imap');
793  $ilDB->insert('qpl_fb_imap', array(
794  'feedback_id' => array( 'integer', $next_id ),
795  'question_fi' => array( 'integer', $this->original_id ),
796  'answer' => array( 'integer', $row["answer"] ),
797  'feedback' => array( 'clob', $row["feedback"] ),
798  'tstamp' => array( 'integer', time() ),
799  )
800  );
801  }
802  }
803  }
804 
812  function getFeedbackSingleAnswer($answer_index)
813  {
814  global $ilDB;
815 
816  $feedback = "";
817  $result = $ilDB->queryF("SELECT * FROM qpl_fb_imap WHERE question_fi = %s AND answer = %s",
818  array('integer','integer'),
819  array($this->getId(), $answer_index)
820  );
821  if ($result->numRows())
822  {
823  $row = $ilDB->fetchAssoc($result);
824  include_once("./Services/RTE/classes/class.ilRTE.php");
825  $feedback = ilRTE::_replaceMediaObjectImageSrc($row["feedback"], 1);
826  }
827  return $feedback;
828  }
829 
836  function duplicateFeedbackAnswer($original_id)
837  {
838  global $ilDB;
839 
840  $feedback = "";
841  $result = $ilDB->queryF("SELECT * FROM qpl_fb_imap WHERE question_fi = %s",
842  array('integer'),
843  array($original_id)
844  );
845  if ($result->numRows())
846  {
847  while ($row = $ilDB->fetchAssoc($result))
848  {
849  $next_id = $ilDB->nextId('qpl_fb_imap');
851  $ilDB->insert('qpl_fb_imap', array(
852  'feedback_id' => array( 'integer', $next_id ),
853  'question_fi' => array( 'integer', $this->getId() ),
854  'answer' => array( 'integer', $row["answer"] ),
855  'feedback' => array( 'clob', $row["feedback"] ),
856  'tstamp' => array( 'integer', time() ),
857  )
858  );
859  }
860  }
861  }
862 
868  {
870  foreach ($this->answers as $index => $answer)
871  {
872  $text .= $this->getFeedbackSingleAnswer($index);
873  }
874  return $text;
875  }
876 
889  public function setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
890  {
891  include_once ("./Services/Excel/classes/class.ilExcelUtils.php");
892  $solution = $this->getSolutionValues($active_id, $pass);
893  $worksheet->writeString($startrow, 0, ilExcelUtils::_convert_text($this->lng->txt($this->getQuestionType())), $format_title);
894  $worksheet->writeString($startrow, 1, ilExcelUtils::_convert_text($this->getTitle()), $format_title);
895  $i = 1;
896  foreach ($this->getAnswers() as $id => $answer)
897  {
898  $worksheet->writeString($startrow + $i, 0, ilExcelUtils::_convert_text($answer->getArea() . ": " . $answer->getCoords()), $format_bold);
899  if ($id == $solution[0]["value1"])
900  {
901  $worksheet->write($startrow + $i, 1, 1);
902  }
903  else
904  {
905  $worksheet->write($startrow + $i, 1, 0);
906  }
907  $i++;
908  }
909  return $startrow + $i + 1;
910  }
911 
915  public function deleteImage()
916  {
917  $file = $this->getImagePath() . $this->getImageFilename();
918  @unlink($file);
919  $this->flushAnswers();
920  $this->image_filename = "";
921  }
922 
926  public function toJSON()
927  {
928  include_once("./Services/RTE/classes/class.ilRTE.php");
929  $result = array();
930  $result['id'] = (int) $this->getId();
931  $result['type'] = (string) $this->getQuestionType();
932  $result['title'] = (string) $this->getTitle();
933  $result['question'] = $this->formatSAQuestion($this->getQuestion());
934  $result['nr_of_tries'] = (int) $this->getNrOfTries();
935  $result['shuffle'] = (bool) $this->getShuffle();
936  $result['feedback'] = array(
937  "onenotcorrect" => nl2br(ilRTE::_replaceMediaObjectImageSrc($this->getFeedbackGeneric(0), 0)),
938  "allcorrect" => nl2br(ilRTE::_replaceMediaObjectImageSrc($this->getFeedbackGeneric(1), 0))
939  );
940  $result['image'] = (string) $this->getImagePathWeb() . $this->getImageFilename();
941 
942  $answers = array();
943  foreach ($this->getAnswers() as $key => $answer_obj)
944  {
945  array_push($answers, array(
946  "answertext" => (string) $answer_obj->getAnswertext(),
947  "points" => (float) $answer_obj->getPoints(),
948  "order" => (int) $answer_obj->getOrder(),
949  "coords" => $answer_obj->getCoords(),
950  "state" => $answer_obj->getState(),
951  "area" => $answer_obj->getArea(),
952  "feedback" => ilRTE::_replaceMediaObjectImageSrc($this->getFeedbackSingleAnswer($key), 0)
953  ));
954  }
955  $result['answers'] = $answers;
956 
957  $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $this->getId());
958  $result['mobs'] = $mobs;
959 
960  return json_encode($result);
961  }
962 
963 }
964 
965 ?>