ILIAS  Release_4_2_x_branch Revision 61807
 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 (strlen($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 = "", $testObjId = null)
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 
174  if( (int)$testObjId > 0 )
175  {
176  $thisObjId = $this->getObjId();
177  }
178 
179  $clone = $this;
180  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
182  $clone->id = -1;
183 
184  if( (int)$testObjId > 0 )
185  {
186  $clone->setObjId($testObjId);
187  }
188 
189  if ($title)
190  {
191  $clone->setTitle($title);
192  }
193  if ($author)
194  {
195  $clone->setAuthor($author);
196  }
197  if ($owner)
198  {
199  $clone->setOwner($owner);
200  }
201  if ($for_test)
202  {
203  $clone->saveToDb($original_id);
204  }
205  else
206  {
207  $clone->saveToDb();
208  }
209 
210  // copy question page content
211  $clone->copyPageOfQuestion($this_id);
212  // copy XHTML media objects
213  $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
214  // duplicate the generic feedback
215  $clone->duplicateFeedbackGeneric($this_id);
216  // duplicate the answer specific feedback
217  $clone->duplicateFeedbackAnswer($this_id);
218 
219  // duplicate the image
220  $clone->duplicateImage($this_id, $thisObjId);
221 
222  $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
223 
224  return $clone->id;
225  }
226 
234  function copyObject($target_questionpool, $title = "")
235  {
236  if ($this->id <= 0)
237  {
238  // The question has not been saved. It cannot be duplicated
239  return;
240  }
241  // duplicate the question in database
242  $clone = $this;
243  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
245  $clone->id = -1;
246  $source_questionpool = $this->getObjId();
247  $clone->setObjId($target_questionpool);
248  if ($title)
249  {
250  $clone->setTitle($title);
251  }
252  $clone->saveToDb();
253 
254  // copy question page content
255  $clone->copyPageOfQuestion($original_id);
256  // copy XHTML media objects
257  $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
258  // duplicate the generic feedback
259  $clone->duplicateFeedbackGeneric($original_id);
260  // duplicate the answer specific feedback
261  $clone->duplicateFeedbackAnswer($original_id);
262 
263  // duplicate the image
264  $clone->copyImage($original_id, $source_questionpool);
265  $clone->onCopy($this->getObjId(), $this->getId());
266  return $clone->id;
267  }
268 
269  function duplicateImage($question_id, $objectId = null)
270  {
271  $imagepath = $this->getImagePath();
272  $imagepath_original = str_replace("/$this->id/images", "/$question_id/images", $imagepath);
273 
274  if( (int)$objectId > 0 )
275  {
276  $imagepath_original = str_replace("/$this->obj_id/", "/$objectId/", $imagepath_original);
277  }
278 
279  if (!file_exists($imagepath)) {
280  ilUtil::makeDirParents($imagepath);
281  }
282  $filename = $this->getImageFilename();
283  if (!copy($imagepath_original . $filename, $imagepath . $filename)) {
284  print "image could not be duplicated!!!! ";
285  }
286  }
287 
288  function copyImage($question_id, $source_questionpool)
289  {
290  $imagepath = $this->getImagePath();
291  $imagepath_original = str_replace("/$this->id/images", "/$question_id/images", $imagepath);
292  $imagepath_original = str_replace("/$this->obj_id/", "/$source_questionpool/", $imagepath_original);
293  if (!file_exists($imagepath))
294  {
295  ilUtil::makeDirParents($imagepath);
296  }
297  $filename = $this->getImageFilename();
298  if (!copy($imagepath_original . $filename, $imagepath . $filename))
299  {
300  print "image could not be copied!!!! ";
301  }
302  }
303 
313  function loadFromDb($question_id)
314  {
315  global $ilDB;
316 
317  $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",
318  array("integer"),
319  array($question_id)
320  );
321  if ($result->numRows() == 1)
322  {
323  $data = $ilDB->fetchAssoc($result);
324  $this->setId($question_id);
325  $this->setObjId($data["obj_fi"]);
326  $this->setTitle($data["title"]);
327  $this->setComment($data["description"]);
328  $this->setOriginalId($data["original_id"]);
329  $this->setNrOfTries($data['nr_of_tries']);
330  $this->setAuthor($data["author"]);
331  $this->setPoints($data["points"]);
332  $this->setOwner($data["owner"]);
333  include_once("./Services/RTE/classes/class.ilRTE.php");
334  $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc($data["question_text"], 1));
335  $this->setImageFilename($data["image_file"]);
336  $this->setEstimatedWorkingTime(substr($data["working_time"], 0, 2), substr($data["working_time"], 3, 2), substr($data["working_time"], 6, 2));
337 
338  $result = $ilDB->queryF("SELECT * FROM qpl_a_imagemap WHERE question_fi = %s ORDER BY aorder ASC",
339  array("integer"),
340  array($question_id)
341  );
342  include_once "./Modules/TestQuestionPool/classes/class.assAnswerImagemap.php";
343  if ($result->numRows() > 0)
344  {
345  while ($data = $ilDB->fetchAssoc($result))
346  {
347  array_push($this->answers, new ASS_AnswerImagemap($data["answertext"], $data["points"], $data["aorder"], $data["coords"], $data["area"]));
348  }
349  }
350  }
351  parent::loadFromDb($question_id);
352  }
353 
360  function uploadImagemap($imagemap_filename = "")
361  {
362  $added = 0;
363  if (!empty($imagemap_filename))
364  {
365  $fp = fopen($imagemap_filename, "r");
366  $contents = fread($fp, filesize($imagemap_filename));
367  fclose($fp);
368  if (preg_match_all("/<area(.+)>/siU", $contents, $matches))
369  {
370  for ($i=0; $i< count($matches[1]); $i++)
371  {
372  preg_match("/alt\s*=\s*\"(.+)\"\s*/siU", $matches[1][$i], $alt);
373  preg_match("/coords\s*=\s*\"(.+)\"\s*/siU", $matches[1][$i], $coords);
374  preg_match("/shape\s*=\s*\"(.+)\"\s*/siU", $matches[1][$i], $shape);
375  $this->addAnswer($alt[1], 0.0, count($this->answers), $coords[1], $shape[1]);
376  $added++;
377  }
378  }
379  }
380  return $added;
381  }
382 
383  function getImageFilename()
384  {
385  return $this->image_filename;
386  }
387 
395  function setImageFilename($image_filename, $image_tempfilename = "")
396  {
397  if (!empty($image_filename))
398  {
399  $image_filename = str_replace(" ", "_", $image_filename);
400  $this->image_filename = $image_filename;
401  }
402  if (!empty($image_tempfilename))
403  {
404  $imagepath = $this->getImagePath();
405  if (!file_exists($imagepath))
406  {
407  ilUtil::makeDirParents($imagepath);
408  }
409  if (!ilUtil::moveUploadedFile($image_tempfilename, $image_filename, $imagepath.$image_filename))
410  {
411  $this->ilias->raiseError("The image could not be uploaded!", $this->ilias->error_obj->MESSAGE);
412  }
413  global $ilLog; $ilLog->write("gespeichert: " . $imagepath.$image_filename);
414  }
415  }
416 
426  function get_imagemap_contents($href = "#") {
427  $imagemap_contents = "<map name=\"".$this->title."\"> ";
428  for ($i = 0; $i < count($this->answers); $i++) {
429  $imagemap_contents .= "<area alt=\"".$this->answers[$i]->getAnswertext()."\" ";
430  $imagemap_contents .= "shape=\"".$this->answers[$i]->getArea()."\" ";
431  $imagemap_contents .= "coords=\"".$this->answers[$i]->getCoords()."\" ";
432  $imagemap_contents .= "href=\"$href&selimage=" . $this->answers[$i]->getOrder() . "\" /> ";
433  }
434  $imagemap_contents .= "</map>";
435  return $imagemap_contents;
436  }
437 
452  function addAnswer(
453  $answertext = "",
454  $points = 0.0,
455  $order = 0,
456  $coords="",
457  $area=""
458  )
459  {
460  include_once "./Modules/TestQuestionPool/classes/class.assAnswerImagemap.php";
461  if (array_key_exists($order, $this->answers))
462  {
463  // Insert answer
464  $answer = new ASS_AnswerImagemap($answertext, $points, $order, $coords, $area);
465  for ($i = count($this->answers) - 1; $i >= $order; $i--)
466  {
467  $this->answers[$i+1] = $this->answers[$i];
468  $this->answers[$i+1]->setOrder($i+1);
469  }
470  $this->answers[$order] = $answer;
471  }
472  else
473  {
474  // Append answer
475  $answer = new ASS_AnswerImagemap($answertext, $points, count($this->answers), $coords, $area);
476  array_push($this->answers, $answer);
477  }
478  }
479 
489  function getAnswerCount() {
490  return count($this->answers);
491  }
492 
504  function getAnswer($index = 0) {
505  if ($index < 0) return NULL;
506  if (count($this->answers) < 1) return NULL;
507  if ($index >= count($this->answers)) return NULL;
508  return $this->answers[$index];
509  }
510 
520  function &getAnswers()
521  {
522  return $this->answers;
523  }
524 
535  function deleteArea($index = 0)
536  {
537  if ($index < 0) return;
538  if (count($this->answers) < 1) return;
539  if ($index >= count($this->answers)) return;
540  unset($this->answers[$index]);
541  $this->answers = array_values($this->answers);
542  for ($i = 0; $i < count($this->answers); $i++) {
543  if ($this->answers[$i]->getOrder() > $index) {
544  $this->answers[$i]->setOrder($i);
545  }
546  }
547  }
548 
557  function flushAnswers() {
558  $this->answers = array();
559  }
560 
569  function getMaximumPoints() {
570  $points = 0;
571  foreach ($this->answers as $key => $value) {
572  if ($value->getPoints() > $points)
573  {
574  $points = $value->getPoints();
575  }
576  }
577  return $points;
578  }
579 
591  function calculateReachedPoints($active_id, $pass = NULL)
592  {
593  global $ilDB;
594 
595  $found_values = array();
596  if (is_null($pass))
597  {
598  $pass = $this->getSolutionMaxPass($active_id);
599  }
600  $result = $ilDB->queryF("SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
601  array("integer","integer","integer"),
602  array($active_id, $this->getId(), $pass)
603  );
604  while ($data = $ilDB->fetchAssoc($result))
605  {
606  if (strcmp($data["value1"], "") != 0)
607  {
608  array_push($found_values, $data["value1"]);
609  }
610  }
611  $points = 0;
612  if (count($found_values) > 0)
613  {
614  foreach ($this->answers as $key => $answer)
615  {
616  if (in_array($key, $found_values))
617  {
618  $points += $answer->getPoints();
619  }
620  }
621  }
622 
623  $points = parent::calculateReachedPoints($active_id, $pass = NULL, $points);
624  return $points;
625  }
626 
637  function saveWorkingData($active_id, $pass = NULL)
638  {
639  global $ilDB;
640  global $ilUser;
641 
642  if (is_null($pass))
643  {
644  include_once "./Modules/Test/classes/class.ilObjTest.php";
645  $pass = ilObjTest::_getPass($active_id);
646  }
647 
648  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
649  array("integer","integer","integer"),
650  array($active_id, $this->getId(), $pass)
651  );
652 
653  if (strlen($_GET["selImage"]))
654  {
655  $next_id = $ilDB->nextId('tst_solutions');
656  $affectedRows = $ilDB->insert("tst_solutions", array(
657  "solution_id" => array("integer", $next_id),
658  "active_fi" => array("integer", $active_id),
659  "question_fi" => array("integer", $this->getId()),
660  "value1" => array("clob", $_GET['selImage']),
661  "value2" => array("clob", null),
662  "pass" => array("integer", $pass),
663  "tstamp" => array("integer", time())
664  ));
665 
666  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
668  {
669  $this->logAction($this->lng->txtlng("assessment", "log_user_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
670  }
671  }
672  else
673  {
674  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
676  {
677  $this->logAction($this->lng->txtlng("assessment", "log_user_not_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
678  }
679  }
680 
681  parent::saveWorkingData($active_id, $pass);
682  return true;
683  }
684 
685  function syncWithOriginal()
686  {
687  if ($this->getOriginalId())
688  {
690  $this->syncFeedbackSingleAnswers();
691  }
692  }
693 
702  function getQuestionType()
703  {
704  return "assImagemapQuestion";
705  }
706 
716  {
717  return "qpl_qst_imagemap";
718  }
719 
729  {
730  return "qpl_a_imagemap";
731  }
732 
740  function saveFeedbackSingleAnswer($answer_index, $feedback)
741  {
742  global $ilDB;
743 
744  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_fb_imap WHERE question_fi = %s AND answer = %s",
745  array("integer","integer"),
746  array($this->getId(), $answer_index)
747  );
748  if (strlen($feedback))
749  {
750  include_once("./Services/RTE/classes/class.ilRTE.php");
751  $next_id = $ilDB->nextId('qpl_fb_imap');
752 
754  $ilDB->insert('qpl_fb_imap', array(
755  'feedback_id' => array( 'integer', $next_id ),
756  'question_fi' => array( 'integer', $this->getId() ),
757  'answer' => array( 'integer', $answer_index ),
758  'feedback' => array( 'clob', ilRTE::_replaceMediaObjectImageSrc($feedback, 0) ),
759  'tstamp' => array( 'integer', time() ),
760  )
761  );
762 
763  }
764  }
765 
771  function syncFeedbackSingleAnswers()
772  {
773  global $ilDB;
774 
775  $feedback = "";
776 
777  // delete generic feedback of the original
778  $affectedRows = $ilDB->manipulateF("DELETE FROM qpl_fb_imap WHERE question_fi = %s",
779  array('integer'),
780  array($this->original_id)
781  );
782 
783  // get generic feedback of the actual question
784  $result = $ilDB->queryF("SELECT * FROM qpl_fb_imap WHERE question_fi = %s",
785  array("integer"),
786  array($this->getId())
787  );
788 
789  // save generic feedback to the original
790  if ($result->numRows())
791  {
792  while ($row = $ilDB->fetchAssoc($result))
793  {
794  $next_id = $ilDB->nextId('qpl_fb_imap');
795 
797  $ilDB->insert('qpl_fb_imap', array(
798  'feedback_id' => array( 'integer', $next_id ),
799  'question_fi' => array( 'integer', $this->original_id ),
800  'answer' => array( 'integer', $row["answer"] ),
801  'feedback' => array( 'clob', $row["feedback"] ),
802  'tstamp' => array( 'integer', time() ),
803  )
804  );
805  }
806  }
807  }
808 
816  function getFeedbackSingleAnswer($answer_index)
817  {
818  global $ilDB;
819 
820  $feedback = "";
821  $result = $ilDB->queryF("SELECT * FROM qpl_fb_imap WHERE question_fi = %s AND answer = %s",
822  array('integer','integer'),
823  array($this->getId(), $answer_index)
824  );
825  if ($result->numRows())
826  {
827  $row = $ilDB->fetchAssoc($result);
828  include_once("./Services/RTE/classes/class.ilRTE.php");
829  $feedback = ilRTE::_replaceMediaObjectImageSrc($row["feedback"], 1);
830  }
831  return $feedback;
832  }
833 
840  function duplicateFeedbackAnswer($original_id)
841  {
842  global $ilDB;
843 
844  $feedback = "";
845  $result = $ilDB->queryF("SELECT * FROM qpl_fb_imap WHERE question_fi = %s",
846  array('integer'),
847  array($original_id)
848  );
849  if ($result->numRows())
850  {
851  while ($row = $ilDB->fetchAssoc($result))
852  {
853  $next_id = $ilDB->nextId('qpl_fb_imap');
854 
856  $ilDB->insert('qpl_fb_imap', array(
857  'feedback_id' => array( 'integer', $next_id ),
858  'question_fi' => array( 'integer', $this->getId() ),
859  'answer' => array( 'integer', $row["answer"] ),
860  'feedback' => array( 'clob', $row["feedback"] ),
861  'tstamp' => array( 'integer', time() ),
862  )
863  );
864 
865  }
866  }
867  }
868 
874  {
876  foreach ($this->answers as $index => $answer)
877  {
878  $text .= $this->getFeedbackSingleAnswer($index);
879  }
880  return $text;
881  }
882 
895  public function setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
896  {
897  include_once ("./Services/Excel/classes/class.ilExcelUtils.php");
898  $solution = $this->getSolutionValues($active_id, $pass);
899  $worksheet->writeString($startrow, 0, ilExcelUtils::_convert_text($this->lng->txt($this->getQuestionType())), $format_title);
900  $worksheet->writeString($startrow, 1, ilExcelUtils::_convert_text($this->getTitle()), $format_title);
901  $i = 1;
902  foreach ($this->getAnswers() as $id => $answer)
903  {
904  $worksheet->writeString($startrow + $i, 0, ilExcelUtils::_convert_text($answer->getArea() . ": " . $answer->getCoords()), $format_bold);
905  if ($id == $solution[0]["value1"])
906  {
907  $worksheet->write($startrow + $i, 1, 1);
908  }
909  else
910  {
911  $worksheet->write($startrow + $i, 1, 0);
912  }
913  $i++;
914  }
915  return $startrow + $i + 1;
916  }
917 
921  public function deleteImage()
922  {
923  $file = $this->getImagePath() . $this->getImageFilename();
924  @unlink($file);
925  $this->flushAnswers();
926  $this->image_filename = "";
927  }
928 
932  public function toJSON()
933  {
934  include_once("./Services/RTE/classes/class.ilRTE.php");
935  $result = array();
936  $result['id'] = (int) $this->getId();
937  $result['type'] = (string) $this->getQuestionType();
938  $result['title'] = (string) $this->getTitle();
939  $result['question'] = $this->formatSAQuestion($this->getQuestion());
940  $result['nr_of_tries'] = (int) $this->getNrOfTries();
941  $result['shuffle'] = (bool) $this->getShuffle();
942  $result['feedback'] = array(
943  "onenotcorrect" => nl2br(ilRTE::_replaceMediaObjectImageSrc($this->getFeedbackGeneric(0), 0)),
944  "allcorrect" => nl2br(ilRTE::_replaceMediaObjectImageSrc($this->getFeedbackGeneric(1), 0))
945  );
946  $result['image'] = (string) $this->getImagePathWeb() . $this->getImageFilename();
947 
948  $answers = array();
949  foreach ($this->getAnswers() as $key => $answer_obj)
950  {
951  array_push($answers, array(
952  "answertext" => (string) $answer_obj->getAnswertext(),
953  "points" => (float) $answer_obj->getPoints(),
954  "order" => (int) $answer_obj->getOrder(),
955  "coords" => $answer_obj->getCoords(),
956  "state" => $answer_obj->getState(),
957  "area" => $answer_obj->getArea(),
958  "feedback" => ilRTE::_replaceMediaObjectImageSrc($this->getFeedbackSingleAnswer($key), 0)
959  ));
960  }
961  $result['answers'] = $answers;
962 
963  $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $this->getId());
964  $result['mobs'] = $mobs;
965 
966  return json_encode($result);
967  }
968 
969 }
970 
971 ?>