ILIAS  Release_4_1_x_branch Revision 61804
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.assImagemapQuestion.php
Go to the documentation of this file.
1 <?php
2  /*
3  +----------------------------------------------------------------------------+
4  | ILIAS open source |
5  +----------------------------------------------------------------------------+
6  | Copyright (c) 1998-2001 ILIAS open source, University of Cologne |
7  | |
8  | This program is free software; you can redistribute it and/or |
9  | modify it under the terms of the GNU General Public License |
10  | as published by the Free Software Foundation; either version 2 |
11  | of the License, or (at your option) any later version. |
12  | |
13  | This program is distributed in the hope that it will be useful, |
14  | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16  | GNU General Public License for more details. |
17  | |
18  | You should have received a copy of the GNU General Public License |
19  | along with this program; if not, write to the Free Software |
20  | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
21  +----------------------------------------------------------------------------+
22 */
23 
24 include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
25 include_once "./Modules/Test/classes/inc.AssessmentConstants.php";
26 
37 {
38 
46  var $answers;
47 
56 
65  var $coords;
66 
80  function __construct(
81  $title = "",
82  $comment = "",
83  $author = "",
84  $owner = -1,
85  $question = "",
86  $image_filename = ""
87  )
88  {
90  $this->image_filename = $image_filename;
91  $this->answers = array();
92  $this->coords = array();
93  }
94 
101  function isComplete()
102  {
103  if (($this->title) and ($this->author) and ($this->question) and ($this->image_filename) and (count($this->answers)) and ($this->getMaximumPoints() > 0))
104  {
105  return true;
106  }
107  else
108  {
109  return false;
110  }
111  }
112 
121  function saveToDb($original_id = "")
122  {
123  global $ilDB;
124 
126 
127  // save additional data
128  $affectedRows = $ilDB->manipulateF("DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
129  array("integer"),
130  array($this->getId())
131  );
132  $affectedRows = $ilDB->manipulateF("INSERT INTO " . $this->getAdditionalTableName() . " (question_fi, image_file) VALUES (%s, %s)",
133  array("integer", "text"),
134  array(
135  $this->getId(),
136  $this->image_filename
137  )
138  );
139 
140  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_a_imagemap WHERE question_fi = %s",
141  array("integer"),
142  array($this->getId())
143  );
144 
145  // Anworten wegschreiben
146  foreach ($this->answers as $key => $value)
147  {
148  $answer_obj = $this->answers[$key];
149  $next_id = $ilDB->nextId('qpl_a_imagemap');
150  $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)",
151  array("integer","integer","text","float","integer","text","text"),
152  array($next_id, $this->id, $answer_obj->getAnswertext(), $answer_obj->getPoints(), $answer_obj->getOrder(), $answer_obj->getCoords(), $answer_obj->getArea())
153  );
154  }
155 
157  }
158 
164  function duplicate($for_test = true, $title = "", $author = "", $owner = "")
165  {
166  if ($this->id <= 0)
167  {
168  // The question has not been saved. It cannot be duplicated
169  return;
170  }
171  // duplicate the question in database
172  $this_id = $this->getId();
173  $clone = $this;
174  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
176  $clone->id = -1;
177  if ($title)
178  {
179  $clone->setTitle($title);
180  }
181  if ($author)
182  {
183  $clone->setAuthor($author);
184  }
185  if ($owner)
186  {
187  $clone->setOwner($owner);
188  }
189  if ($for_test)
190  {
191  $clone->saveToDb($original_id);
192  }
193  else
194  {
195  $clone->saveToDb();
196  }
197 
198  // copy question page content
199  $clone->copyPageOfQuestion($this_id);
200  // copy XHTML media objects
201  $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
202  // duplicate the generic feedback
203  $clone->duplicateFeedbackGeneric($this_id);
204  // duplicate the answer specific feedback
205  $clone->duplicateFeedbackAnswer($this_id);
206 
207  // duplicate the image
208  $clone->duplicateImage($this_id);
209  $clone->onDuplicate($this_id);
210  return $clone->id;
211  }
212 
220  function copyObject($target_questionpool, $title = "")
221  {
222  if ($this->id <= 0)
223  {
224  // The question has not been saved. It cannot be duplicated
225  return;
226  }
227  // duplicate the question in database
228  $clone = $this;
229  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
231  $clone->id = -1;
232  $source_questionpool = $this->getObjId();
233  $clone->setObjId($target_questionpool);
234  if ($title)
235  {
236  $clone->setTitle($title);
237  }
238  $clone->saveToDb();
239 
240  // copy question page content
241  $clone->copyPageOfQuestion($original_id);
242  // copy XHTML media objects
243  $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
244  // duplicate the generic feedback
245  $clone->duplicateFeedbackGeneric($original_id);
246  // duplicate the answer specific feedback
247  $clone->duplicateFeedbackAnswer($original_id);
248 
249  // duplicate the image
250  $clone->copyImage($original_id, $source_questionpool);
251  $clone->onCopy($this->getObjId(), $this->getId());
252  return $clone->id;
253  }
254 
255  function duplicateImage($question_id)
256  {
257  $imagepath = $this->getImagePath();
258  $imagepath_original = str_replace("/$this->id/images", "/$question_id/images", $imagepath);
259  if (!file_exists($imagepath)) {
260  ilUtil::makeDirParents($imagepath);
261  }
262  $filename = $this->getImageFilename();
263  if (!copy($imagepath_original . $filename, $imagepath . $filename)) {
264  print "image could not be duplicated!!!! ";
265  }
266  }
267 
268  function copyImage($question_id, $source_questionpool)
269  {
270  $imagepath = $this->getImagePath();
271  $imagepath_original = str_replace("/$this->id/images", "/$question_id/images", $imagepath);
272  $imagepath_original = str_replace("/$this->obj_id/", "/$source_questionpool/", $imagepath_original);
273  if (!file_exists($imagepath))
274  {
275  ilUtil::makeDirParents($imagepath);
276  }
277  $filename = $this->getImageFilename();
278  if (!copy($imagepath_original . $filename, $imagepath . $filename))
279  {
280  print "image could not be copied!!!! ";
281  }
282  }
283 
293  function loadFromDb($question_id)
294  {
295  global $ilDB;
296 
297  $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",
298  array("integer"),
299  array($question_id)
300  );
301  if ($result->numRows() == 1)
302  {
303  $data = $ilDB->fetchAssoc($result);
304  $this->setId($question_id);
305  $this->setObjId($data["obj_fi"]);
306  $this->setTitle($data["title"]);
307  $this->setComment($data["description"]);
308  $this->setOriginalId($data["original_id"]);
309  $this->setNrOfTries($data['nr_of_tries']);
310  $this->setAuthor($data["author"]);
311  $this->setPoints($data["points"]);
312  $this->setOwner($data["owner"]);
313  include_once("./Services/RTE/classes/class.ilRTE.php");
314  $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc($data["question_text"], 1));
315  $this->setImageFilename($data["image_file"]);
316  $this->setEstimatedWorkingTime(substr($data["working_time"], 0, 2), substr($data["working_time"], 3, 2), substr($data["working_time"], 6, 2));
317 
318  $result = $ilDB->queryF("SELECT * FROM qpl_a_imagemap WHERE question_fi = %s ORDER BY aorder ASC",
319  array("integer"),
320  array($question_id)
321  );
322  include_once "./Modules/TestQuestionPool/classes/class.assAnswerImagemap.php";
323  if ($result->numRows() > 0)
324  {
325  while ($data = $ilDB->fetchAssoc($result))
326  {
327  array_push($this->answers, new ASS_AnswerImagemap($data["answertext"], $data["points"], $data["aorder"], $data["coords"], $data["area"]));
328  }
329  }
330  }
331  parent::loadFromDb($question_id);
332  }
333 
340  function uploadImagemap($imagemap_filename = "")
341  {
342  $added = 0;
343  if (!empty($imagemap_filename))
344  {
345  $fp = fopen($imagemap_filename, "r");
346  $contents = fread($fp, filesize($imagemap_filename));
347  fclose($fp);
348  if (preg_match_all("/<area(.+)>/siU", $contents, $matches))
349  {
350  for ($i=0; $i< count($matches[1]); $i++)
351  {
352  preg_match("/alt\s*=\s*\"(.+)\"\s*/siU", $matches[1][$i], $alt);
353  preg_match("/coords\s*=\s*\"(.+)\"\s*/siU", $matches[1][$i], $coords);
354  preg_match("/shape\s*=\s*\"(.+)\"\s*/siU", $matches[1][$i], $shape);
355  $this->addAnswer($alt[1], 0.0, count($this->answers), $coords[1], $shape[1]);
356  $added++;
357  }
358  }
359  }
360  return $added;
361  }
362 
363  function getImageFilename()
364  {
365  return $this->image_filename;
366  }
367 
375  function setImageFilename($image_filename, $image_tempfilename = "")
376  {
377  if (!empty($image_filename))
378  {
379  $image_filename = str_replace(" ", "_", $image_filename);
380  $this->image_filename = $image_filename;
381  }
382  if (!empty($image_tempfilename))
383  {
384  $imagepath = $this->getImagePath();
385  if (!file_exists($imagepath))
386  {
387  ilUtil::makeDirParents($imagepath);
388  }
389  if (!ilUtil::moveUploadedFile($image_tempfilename, $image_filename, $imagepath.$image_filename))
390  {
391  $this->ilias->raiseError("The image could not be uploaded!", $this->ilias->error_obj->MESSAGE);
392  }
393  global $ilLog; $ilLog->write("gespeichert: " . $imagepath.$image_filename);
394  }
395  }
396 
406  function get_imagemap_contents($href = "#") {
407  $imagemap_contents = "<map name=\"".$this->title."\"> ";
408  for ($i = 0; $i < count($this->answers); $i++) {
409  $imagemap_contents .= "<area alt=\"".$this->answers[$i]->getAnswertext()."\" ";
410  $imagemap_contents .= "shape=\"".$this->answers[$i]->getArea()."\" ";
411  $imagemap_contents .= "coords=\"".$this->answers[$i]->getCoords()."\" ";
412  $imagemap_contents .= "href=\"$href&selimage=" . $this->answers[$i]->getOrder() . "\" /> ";
413  }
414  $imagemap_contents .= "</map>";
415  return $imagemap_contents;
416  }
417 
432  function addAnswer(
433  $answertext = "",
434  $points = 0.0,
435  $order = 0,
436  $coords="",
437  $area=""
438  )
439  {
440  include_once "./Modules/TestQuestionPool/classes/class.assAnswerImagemap.php";
441  if (array_key_exists($order, $this->answers))
442  {
443  // Insert answer
444  $answer = new ASS_AnswerImagemap($answertext, $points, $order, $coords, $area);
445  for ($i = count($this->answers) - 1; $i >= $order; $i--)
446  {
447  $this->answers[$i+1] = $this->answers[$i];
448  $this->answers[$i+1]->setOrder($i+1);
449  }
450  $this->answers[$order] = $answer;
451  }
452  else
453  {
454  // Append answer
455  $answer = new ASS_AnswerImagemap($answertext, $points, count($this->answers), $coords, $area);
456  array_push($this->answers, $answer);
457  }
458  }
459 
469  function getAnswerCount() {
470  return count($this->answers);
471  }
472 
484  function getAnswer($index = 0) {
485  if ($index < 0) return NULL;
486  if (count($this->answers) < 1) return NULL;
487  if ($index >= count($this->answers)) return NULL;
488  return $this->answers[$index];
489  }
490 
500  function &getAnswers()
501  {
502  return $this->answers;
503  }
504 
515  function deleteArea($index = 0)
516  {
517  if ($index < 0) return;
518  if (count($this->answers) < 1) return;
519  if ($index >= count($this->answers)) return;
520  unset($this->answers[$index]);
521  $this->answers = array_values($this->answers);
522  for ($i = 0; $i < count($this->answers); $i++) {
523  if ($this->answers[$i]->getOrder() > $index) {
524  $this->answers[$i]->setOrder($i);
525  }
526  }
527  }
528 
537  function flushAnswers() {
538  $this->answers = array();
539  }
540 
549  function getMaximumPoints() {
550  $points = 0;
551  foreach ($this->answers as $key => $value) {
552  if ($value->getPoints() > $points)
553  {
554  $points = $value->getPoints();
555  }
556  }
557  return $points;
558  }
559 
571  function calculateReachedPoints($active_id, $pass = NULL)
572  {
573  global $ilDB;
574 
575  $found_values = array();
576  if (is_null($pass))
577  {
578  $pass = $this->getSolutionMaxPass($active_id);
579  }
580  $result = $ilDB->queryF("SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
581  array("integer","integer","integer"),
582  array($active_id, $this->getId(), $pass)
583  );
584  while ($data = $ilDB->fetchAssoc($result))
585  {
586  if (strcmp($data["value1"], "") != 0)
587  {
588  array_push($found_values, $data["value1"]);
589  }
590  }
591  $points = 0;
592  if (count($found_values) > 0)
593  {
594  foreach ($this->answers as $key => $answer)
595  {
596  if (in_array($key, $found_values))
597  {
598  $points += $answer->getPoints();
599  }
600  }
601  }
602 
603  $points = parent::calculateReachedPoints($active_id, $pass = NULL, $points);
604  return $points;
605  }
606 
617  function saveWorkingData($active_id, $pass = NULL)
618  {
619  global $ilDB;
620  global $ilUser;
621 
622  if (is_null($pass))
623  {
624  include_once "./Modules/Test/classes/class.ilObjTest.php";
625  $pass = ilObjTest::_getPass($active_id);
626  }
627 
628  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
629  array("integer","integer","integer"),
630  array($active_id, $this->getId(), $pass)
631  );
632 
633  if (strlen($_GET["selImage"]))
634  {
635  $next_id = $ilDB->nextId('tst_solutions');
636  $affectedRows = $ilDB->insert("tst_solutions", array(
637  "solution_id" => array("integer", $next_id),
638  "active_fi" => array("integer", $active_id),
639  "question_fi" => array("integer", $this->getId()),
640  "value1" => array("clob", $_GET['selImage']),
641  "value2" => array("clob", null),
642  "pass" => array("integer", $pass),
643  "tstamp" => array("integer", time())
644  ));
645 
646  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
648  {
649  $this->logAction($this->lng->txtlng("assessment", "log_user_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
650  }
651  }
652  else
653  {
654  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
656  {
657  $this->logAction($this->lng->txtlng("assessment", "log_user_not_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
658  }
659  }
660 
661  parent::saveWorkingData($active_id, $pass);
662  return true;
663  }
664 
665  function syncWithOriginal()
666  {
667  if ($this->getOriginalId())
668  {
670  $this->syncFeedbackSingleAnswers();
671  }
672  }
673 
682  function getQuestionType()
683  {
684  return "assImagemapQuestion";
685  }
686 
696  {
697  return "qpl_qst_imagemap";
698  }
699 
709  {
710  return "qpl_a_imagemap";
711  }
712 
720  function saveFeedbackSingleAnswer($answer_index, $feedback)
721  {
722  global $ilDB;
723 
724  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_fb_imap WHERE question_fi = %s AND answer = %s",
725  array("integer","integer"),
726  array($this->getId(), $answer_index)
727  );
728  if (strlen($feedback))
729  {
730  include_once("./Services/RTE/classes/class.ilRTE.php");
731  $next_id = $ilDB->nextId('qpl_fb_imap');
732  $affectedRows = $ilDB->manipulateF("INSERT INTO qpl_fb_imap (feedback_id, question_fi, answer, feedback, tstamp) VALUES (%s, %s, %s, %s, %s)",
733  array("integer","integer","integer","text","integer"),
734  array($next_id, $this->getId(), $answer_index, ilRTE::_replaceMediaObjectImageSrc($feedback, 0), time())
735  );
736  }
737  }
738 
745  {
746  global $ilDB;
747 
748  $feedback = "";
749 
750  // delete generic feedback of the original
751  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_fb_imap WHERE question_fi = %s",
752  array('integer'),
753  array($this->original_id)
754  );
755 
756  // get generic feedback of the actual question
757  $result = $ilDB->queryF("SELECT * FROM qpl_fb_imap WHERE question_fi = %s",
758  array("integer"),
759  array($this->getId())
760  );
761 
762  // save generic feedback to the original
763  if ($result->numRows())
764  {
765  while ($row = $ilDB->fetchAssoc($result))
766  {
767  $next_id = $ilDB->nextId('qpl_fb_imap');
768  $affectedRows = $ilDB->manipulateF("INSERT INTO qpl_fb_imap (feedback_id, question_fi, answer, feedback, tstamp) VALUES (%s, %s, %s, %s, %s)",
769  array("integer","integer","integer","text","integer"),
770  array($next_id, $this->original_id, $row["answer"], $row["feedback"], time())
771  );
772  }
773  }
774  }
775 
783  function getFeedbackSingleAnswer($answer_index)
784  {
785  global $ilDB;
786 
787  $feedback = "";
788  $result = $ilDB->queryF("SELECT * FROM qpl_fb_imap WHERE question_fi = %s AND answer = %s",
789  array('integer','integer'),
790  array($this->getId(), $answer_index)
791  );
792  if ($result->numRows())
793  {
794  $row = $ilDB->fetchAssoc($result);
795  include_once("./Services/RTE/classes/class.ilRTE.php");
796  $feedback = ilRTE::_replaceMediaObjectImageSrc($row["feedback"], 1);
797  }
798  return $feedback;
799  }
800 
808  {
809  global $ilDB;
810 
811  $feedback = "";
812  $result = $ilDB->queryF("SELECT * FROM qpl_fb_imap WHERE question_fi = %s",
813  array('integer'),
814  array($original_id)
815  );
816  if ($result->numRows())
817  {
818  while ($row = $ilDB->fetchAssoc($result))
819  {
820  $next_id = $ilDB->nextId('qpl_fb_imap');
821  $affectedRows = $ilDB->manipulateF("INSERT INTO qpl_fb_imap (feedback_id, question_fi, answer, feedback, tstamp) VALUES (%s, %s, %s, %s, %s)",
822  array("integer","integer","integer","text","integer"),
823  array($next_id, $this->getId(), $row["answer"], $row["feedback"], time())
824  );
825  }
826  }
827  }
828 
834  {
836  foreach ($this->answers as $index => $answer)
837  {
838  $text .= $this->getFeedbackSingleAnswer($index);
839  }
840  return $text;
841  }
842 
855  public function setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
856  {
857  include_once ("./Services/Excel/classes/class.ilExcelUtils.php");
858  $solution = $this->getSolutionValues($active_id, $pass);
859  $worksheet->writeString($startrow, 0, ilExcelUtils::_convert_text($this->lng->txt($this->getQuestionType())), $format_title);
860  $worksheet->writeString($startrow, 1, ilExcelUtils::_convert_text($this->getTitle()), $format_title);
861  $i = 1;
862  foreach ($this->getAnswers() as $id => $answer)
863  {
864  $worksheet->writeString($startrow + $i, 0, ilExcelUtils::_convert_text($answer->getArea() . ": " . $answer->getCoords()), $format_bold);
865  if ($id == $solution[0]["value1"])
866  {
867  $worksheet->write($startrow + $i, 1, 1);
868  }
869  else
870  {
871  $worksheet->write($startrow + $i, 1, 0);
872  }
873  $i++;
874  }
875  return $startrow + $i + 1;
876  }
877 
881  public function deleteImage()
882  {
883  $file = $this->getImagePath() . $this->getImageFilename();
884  @unlink($file);
885  $this->flushAnswers();
886  $this->image_filename = "";
887  }
888 
892  public function toJSON()
893  {
894  include_once("./Services/RTE/classes/class.ilRTE.php");
895  $result = array();
896  $result['id'] = (int) $this->getId();
897  $result['type'] = (string) $this->getQuestionType();
898  $result['title'] = (string) $this->getTitle();
899  $result['question'] = (string) ilRTE::_replaceMediaObjectImageSrc($this->getQuestion(), 0);
900  $result['nr_of_tries'] = (int) $this->getNrOfTries();
901  $result['shuffle'] = (bool) $this->getShuffle();
902  $result['feedback'] = array(
903  "onenotcorrect" => nl2br(ilRTE::_replaceMediaObjectImageSrc($this->getFeedbackGeneric(0), 0)),
904  "allcorrect" => nl2br(ilRTE::_replaceMediaObjectImageSrc($this->getFeedbackGeneric(1), 0))
905  );
906  $result['image'] = (string) $this->getImagePathWeb() . $this->getImageFilename();
907 
908  $answers = array();
909  foreach ($this->getAnswers() as $key => $answer_obj)
910  {
911  array_push($answers, array(
912  "answertext" => (string) $answer_obj->getAnswertext(),
913  "points" => (float) $answer_obj->getPoints(),
914  "order" => (int) $answer_obj->getOrder(),
915  "coords" => $answer_obj->getCoords(),
916  "state" => $answer_obj->getState(),
917  "area" => $answer_obj->getArea(),
918  "feedback" => ilRTE::_replaceMediaObjectImageSrc($this->getFeedbackSingleAnswer($key), 0)
919  ));
920  }
921  $result['answers'] = $answers;
922  $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $this->getId());
923  $result['mobs'] = $mobs;
924  return json_encode($result);
925  }
926 
927 }
928 
929 ?>