ILIAS  release_4-4 Revision
All Data Structures Namespaces Files Functions Variables Modules Pages
class.assMatchingQuestion.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 
23 {
32 
42 
48  protected $terms;
49  protected $definitions;
50 
56  var $thumb_geometry = 100;
57 
64 
79  public function __construct(
80  $title = "",
81  $comment = "",
82  $author = "",
83  $owner = -1,
84  $question = "",
85  $matching_type = MT_TERMS_DEFINITIONS
86  )
87  {
88  parent::__construct($title, $comment, $author, $owner, $question);
89  $this->matchingpairs = array();
90  $this->matching_type = $matching_type;
91  $this->terms = array();
92  $this->definitions = array();
93  }
94 
100  public function isComplete()
101  {
102  if (strlen($this->title)
103  && $this->author
104  && $this->question
105  && count($this->matchingpairs)
106  && $this->getMaximumPoints() > 0
107  )
108  {
109  return true;
110  }
111  return false;
112  }
113 
120  public function saveToDb($original_id = "")
121  {
122  global $ilDB;
123 
126  $this->saveAnswerSpecificDataToDb( $ilDB );
127 
128 
129  parent::saveToDb($original_id);
130  }
131 
132  public function saveAnswerSpecificDataToDb()
133  {
134  global $ilDB;
135  // delete old terms
136  $ilDB->manipulateF( "DELETE FROM qpl_a_mterm WHERE question_fi = %s",
137  array( 'integer' ),
138  array( $this->getId() )
139  );
140 
141  // delete old definitions
142  $ilDB->manipulateF( "DELETE FROM qpl_a_mdef WHERE question_fi = %s",
143  array( 'integer' ),
144  array( $this->getId() )
145  );
146 
147  $termids = array();
148  // write terms
149  foreach ($this->terms as $key => $term)
150  {
151  $next_id = $ilDB->nextId( 'qpl_a_mterm' );
152  $ilDB->manipulateF( "INSERT INTO qpl_a_mterm (term_id, question_fi, picture, term) VALUES (%s, %s, %s, %s)",
153  array( 'integer', 'integer', 'text', 'text' ),
154  array( $next_id, $this->getId(), $term->picture, $term->text )
155  );
156  $termids[$term->identifier] = $next_id;
157  }
158 
159  $definitionids = array();
160  // write definitions
161  foreach ($this->definitions as $key => $definition)
162  {
163  $next_id = $ilDB->nextId( 'qpl_a_mdef' );
164  $ilDB->manipulateF( "INSERT INTO qpl_a_mdef (def_id, question_fi, picture, definition, morder) VALUES (%s, %s, %s, %s, %s)",
165  array( 'integer', 'integer', 'text', 'text', 'integer' ),
166  array( $next_id, $this->getId(
167  ), $definition->picture, $definition->text, $definition->identifier )
168  );
169  $definitionids[$definition->identifier] = $next_id;
170  }
171 
172  $ilDB->manipulateF( "DELETE FROM qpl_a_matching WHERE question_fi = %s",
173  array( 'integer' ),
174  array( $this->getId() )
175  );
176  $matchingpairs = $this->getMatchingPairs();
177  foreach ($matchingpairs as $key => $pair)
178  {
179  $next_id = $ilDB->nextId( 'qpl_a_matching' );
180  $ilDB->manipulateF( "INSERT INTO qpl_a_matching (answer_id, question_fi, points, term_fi, definition_fi) VALUES (%s, %s, %s, %s, %s)",
181  array( 'integer', 'integer', 'float', 'integer', 'integer' ),
182  array(
183  $next_id,
184  $this->getId(),
185  $pair->points,
186  $termids[$pair->term->identifier],
187  $definitionids[$pair->definition->identifier]
188  )
189  );
190  }
191 
192  $this->rebuildThumbnails();
193  }
194 
196  {
197  global $ilDB;
198  // save additional data
199  $ilDB->manipulateF( "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
200  array( "integer" ),
201  array( $this->getId() )
202  );
203  $ilDB->manipulateF( "INSERT INTO " . $this->getAdditionalTableName(
204  ) . " (question_fi, shuffle, matching_type, thumb_geometry, element_height) VALUES (%s, %s, %s, %s, %s)",
205  array( "integer", "text", "text", "integer", "integer" ),
206  array(
207  $this->getId(),
208  $this->shuffle,
209  $this->matching_type,
210  $this->getThumbGeometry(),
211  ($this->getElementHeight() >= 20) ? $this->getElementHeight() : NULL
212  )
213  );
214  }
215 
222  public function loadFromDb($question_id)
223  {
224  global $ilDB;
225 
226  $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",
227  array("integer"),
228  array($question_id)
229  );
230  if ($result->numRows() == 1)
231  {
232  $data = $ilDB->fetchAssoc($result);
233  $this->setId($question_id);
234  $this->setObjId($data["obj_fi"]);
235  $this->setTitle($data["title"]);
236  $this->setComment($data["description"]);
237  $this->setOriginalId($data["original_id"]);
238  $this->setNrOfTries($data['nr_of_tries']);
239  $this->setAuthor($data["author"]);
240  $this->setPoints($data["points"]);
241  $this->setOwner($data["owner"]);
242  include_once("./Services/RTE/classes/class.ilRTE.php");
243  $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc($data["question_text"], 1));
244  $this->setThumbGeometry($data["thumb_geometry"]);
245  $this->setElementHeight($data["element_height"]);
246  $this->setShuffle($data["shuffle"]);
247  $this->setEstimatedWorkingTime(substr($data["working_time"], 0, 2), substr($data["working_time"], 3, 2), substr($data["working_time"], 6, 2));
248 
249  try
250  {
251  $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
252  }
254  {
255  }
256  }
257 
258  $termids = array();
259  $result = $ilDB->queryF("SELECT * FROM qpl_a_mterm WHERE question_fi = %s ORDER BY term_id ASC",
260  array('integer'),
261  array($question_id)
262  );
263  include_once "./Modules/TestQuestionPool/classes/class.assAnswerMatchingTerm.php";
264  $this->terms = array();
265  if ($result->numRows() > 0)
266  {
267  while ($data = $ilDB->fetchAssoc($result))
268  {
269  $term = new assAnswerMatchingTerm($data['term'], $data['picture'], $data['term_id']);
270  array_push($this->terms, $term);
271  $termids[$data['term_id']] = $term;
272  }
273  }
274 
275  $definitionids = array();
276  $result = $ilDB->queryF("SELECT * FROM qpl_a_mdef WHERE question_fi = %s ORDER BY def_id ASC",
277  array('integer'),
278  array($question_id)
279  );
280  include_once "./Modules/TestQuestionPool/classes/class.assAnswerMatchingDefinition.php";
281  $this->definitions = array();
282  if ($result->numRows() > 0)
283  {
284  while ($data = $ilDB->fetchAssoc($result))
285  {
286  $definition = new assAnswerMatchingDefinition($data['definition'], $data['picture'], $data['morder']);
287  array_push($this->definitions, $definition);
288  $definitionids[$data['def_id']] = $definition;
289  }
290  }
291 
292  $this->matchingpairs = array();
293  $result = $ilDB->queryF("SELECT * FROM qpl_a_matching WHERE question_fi = %s ORDER BY answer_id",
294  array('integer'),
295  array($question_id)
296  );
297  include_once "./Modules/TestQuestionPool/classes/class.assAnswerMatchingPair.php";
298  if ($result->numRows() > 0)
299  {
300  while ($data = $ilDB->fetchAssoc($result))
301  {
302  array_push($this->matchingpairs, new assAnswerMatchingPair($termids[$data['term_fi']], $definitionids[$data['definition_fi']], $data['points']));
303  }
304  }
305  parent::loadFromDb($question_id);
306  }
307 
308 
312  public function duplicate($for_test = true, $title = "", $author = "", $owner = "", $testObjId = null)
313  {
314  if ($this->id <= 0)
315  {
316  // The question has not been saved. It cannot be duplicated
317  return;
318  }
319  // duplicate the question in database
320  $this_id = $this->getId();
321  $thisObjId = $this->getObjId();
322 
323  $clone = $this;
324  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
326  $clone->id = -1;
327 
328  if( (int)$testObjId > 0 )
329  {
330  $clone->setObjId($testObjId);
331  }
332 
333  if ($title)
334  {
335  $clone->setTitle($title);
336  }
337  if ($author)
338  {
339  $clone->setAuthor($author);
340  }
341  if ($owner)
342  {
343  $clone->setOwner($owner);
344  }
345  if ($for_test)
346  {
347  $clone->saveToDb($original_id);
348  }
349  else
350  {
351  $clone->saveToDb();
352  }
353 
354  // copy question page content
355  $clone->copyPageOfQuestion($this_id);
356  // copy XHTML media objects
357  $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
358  // duplicate the image
359  $clone->duplicateImages($this_id, $thisObjId);
360 
361  $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
362 
363  return $clone->id;
364  }
365 
369  public function copyObject($target_questionpool_id, $title = "")
370  {
371  if ($this->id <= 0)
372  {
373  // The question has not been saved. It cannot be duplicated
374  return;
375  }
376  // duplicate the question in database
377  $clone = $this;
378  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
380  $clone->id = -1;
381  $source_questionpool_id = $this->getObjId();
382  $clone->setObjId($target_questionpool_id);
383  if ($title)
384  {
385  $clone->setTitle($title);
386  }
387  $clone->saveToDb();
388  // copy question page content
389  $clone->copyPageOfQuestion($original_id);
390  // copy XHTML media objects
391  $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
392  // duplicate the image
393  $clone->copyImages($original_id, $source_questionpool_id);
394 
395  $clone->onCopy($source_questionpool_id, $original_id, $clone->getObjId(), $clone->getId());
396 
397  return $clone->id;
398  }
399 
400  public function createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle = "")
401  {
402  if ($this->id <= 0)
403  {
404  // The question has not been saved. It cannot be duplicated
405  return;
406  }
407 
408  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
409 
410  $sourceQuestionId = $this->id;
411  $sourceParentId = $this->getObjId();
412 
413  // duplicate the question in database
414  $clone = $this;
415  $clone->id = -1;
416 
417  $clone->setObjId($targetParentId);
418 
419  if ($targetQuestionTitle)
420  {
421  $clone->setTitle($targetQuestionTitle);
422  }
423 
424  $clone->saveToDb();
425  // copy question page content
426  $clone->copyPageOfQuestion($sourceQuestionId);
427  // copy XHTML media objects
428  $clone->copyXHTMLMediaObjectsOfQuestion($sourceQuestionId);
429  // duplicate the image
430  $clone->copyImages($sourceQuestionId, $sourceParentId);
431 
432  $clone->onCopy($sourceParentId, $sourceQuestionId, $clone->getObjId(), $clone->getId());
433 
434  return $clone->id;
435  }
436 
437  public function duplicateImages($question_id, $objectId = null)
438  {
439  global $ilLog;
440  $imagepath = $this->getImagePath();
441  $imagepath_original = str_replace("/$this->id/images", "/$question_id/images", $imagepath);
442 
443  if( (int)$objectId > 0 )
444  {
445  $imagepath_original = str_replace("/$this->obj_id/", "/$objectId/", $imagepath_original);
446  }
447 
448  foreach ($this->terms as $term)
449  {
450  if (strlen($term->picture))
451  {
452  $filename = $term->picture;
453  if (!file_exists($imagepath))
454  {
455  ilUtil::makeDirParents($imagepath);
456  }
457  if (!@copy($imagepath_original . $filename, $imagepath . $filename))
458  {
459  $ilLog->write("matching question image could not be duplicated: $imagepath_original$filename");
460  }
461  if (@file_exists($imagepath_original . $this->getThumbPrefix() . $filename))
462  {
463  if (!@copy($imagepath_original . $this->getThumbPrefix() . $filename, $imagepath . $this->getThumbPrefix() . $filename))
464  {
465  $ilLog->write("matching question image thumbnail could not be duplicated: $imagepath_original" . $this->getThumbPrefix() . $filename);
466  }
467  }
468  }
469  }
470  foreach ($this->definitions as $definition)
471  {
472  if (strlen($definition->picture))
473  {
474  $filename = $definition->picture;
475  if (!file_exists($imagepath))
476  {
477  ilUtil::makeDirParents($imagepath);
478  }
479  if (!@copy($imagepath_original . $filename, $imagepath . $filename))
480  {
481  $ilLog->write("matching question image could not be duplicated: $imagepath_original$filename");
482  }
483  if (@file_exists($imagepath_original . $this->getThumbPrefix() . $filename))
484  {
485  if (!@copy($imagepath_original . $this->getThumbPrefix() . $filename, $imagepath . $this->getThumbPrefix() . $filename))
486  {
487  $ilLog->write("matching question image thumbnail could not be duplicated: $imagepath_original" . $this->getThumbPrefix() . $filename);
488  }
489  }
490  }
491  }
492  }
493 
494  public function copyImages($question_id, $source_questionpool)
495  {
496  global $ilLog;
497 
498  $imagepath = $this->getImagePath();
499  $imagepath_original = str_replace("/$this->id/images", "/$question_id/images", $imagepath);
500  $imagepath_original = str_replace("/$this->obj_id/", "/$source_questionpool/", $imagepath_original);
501  foreach ($this->terms as $term)
502  {
503  if (strlen($term->picture))
504  {
505  if (!file_exists($imagepath))
506  {
507  ilUtil::makeDirParents($imagepath);
508  }
509  $filename = $term->picture;
510  if (!@copy($imagepath_original . $filename, $imagepath . $filename))
511  {
512  $ilLog->write("matching question image could not be copied: $imagepath_original$filename");
513  }
514  if (!@copy($imagepath_original . $this->getThumbPrefix() . $filename, $imagepath . $this->getThumbPrefix() . $filename))
515  {
516  $ilLog->write("matching question image thumbnail could not be copied: $imagepath_original" . $this->getThumbPrefix() . $filename);
517  }
518  }
519  }
520  foreach ($this->definitions as $definition)
521  {
522  if (strlen($definition->picture))
523  {
524  $filename = $definition->picture;
525  if (!file_exists($imagepath))
526  {
527  ilUtil::makeDirParents($imagepath);
528  }
529  if (!copy($imagepath_original . $filename, $imagepath . $filename))
530  {
531  $ilLog->write("matching question image could not be copied: $imagepath_original$filename");
532  }
533  if (!copy($imagepath_original . $this->getThumbPrefix() . $filename, $imagepath . $this->getThumbPrefix() . $filename))
534  {
535  $ilLog->write("matching question image thumbnail could not be copied: $imagepath_original" . $this->getThumbPrefix() . $filename);
536  }
537  }
538  }
539  }
540 
551  public function insertMatchingPair($position, $term = null, $definition = null, $points = 0.0)
552  {
553  include_once "./Modules/TestQuestionPool/classes/class.assAnswerMatchingPair.php";
554  include_once "./Modules/TestQuestionPool/classes/class.assAnswerMatchingTerm.php";
555  include_once "./Modules/TestQuestionPool/classes/class.assAnswerMatchingDefinition.php";
556  if (is_null($term)) $term = new assAnswerMatchingTerm();
557  if (is_null($definition)) $definition = new assAnswerMatchingDefinition();
558  $pair = new assAnswerMatchingPair($term, $definition, $points);
559  if ($position < count($this->matchingpairs))
560  {
561  $part1 = array_slice($this->matchingpairs, 0, $position);
562  $part2 = array_slice($this->matchingpairs, $position);
563  $this->matchingpairs = array_merge($part1, array($pair), $part2);
564  }
565  else
566  {
567  array_push($this->matchingpairs, $pair);
568  }
569  }
570 
582  public function addMatchingPair($term = null, $definition = null, $points = 0.0)
583  {
584  require_once './Modules/TestQuestionPool/classes/class.assAnswerMatchingPair.php';
585  require_once './Modules/TestQuestionPool/classes/class.assAnswerMatchingTerm.php';
586  require_once './Modules/TestQuestionPool/classes/class.assAnswerMatchingDefinition.php';
587  if (is_null($term))
588  {
589  $term = new assAnswerMatchingTerm();
590  }
591  if (is_null($definition))
592  {
593  $definition = new assAnswerMatchingDefinition();
594  }
595  $pair = new assAnswerMatchingPair($term, $definition, $points);
596  array_push($this->matchingpairs, $pair);
597  }
598 
602  public function getTermWithIdentifier($a_identifier)
603  {
604  foreach ($this->terms as $term)
605  {
606  if ($term->identifier == $a_identifier) return $term;
607  }
608  return null;
609  }
610 
614  public function getDefinitionWithIdentifier($a_identifier)
615  {
616  foreach ($this->definitions as $definition)
617  {
618  if ($definition->identifier == $a_identifier) return $definition;
619  }
620  return null;
621  }
622 
631  public function getMatchingPair($index = 0)
632  {
633  if ($index < 0)
634  {
635  return NULL;
636  }
637  if (count($this->matchingpairs) < 1)
638  {
639  return NULL;
640  }
641  if ($index >= count($this->matchingpairs))
642  {
643  return NULL;
644  }
645  return $this->matchingpairs[$index];
646  }
647 
655  public function deleteMatchingPair($index = 0)
656  {
657  if ($index < 0)
658  {
659  return;
660  }
661  if (count($this->matchingpairs) < 1)
662  {
663  return;
664  }
665  if ($index >= count($this->matchingpairs))
666  {
667  return;
668  }
669  unset($this->matchingpairs[$index]);
670  $this->matchingpairs = array_values($this->matchingpairs);
671  }
672 
677  public function flushMatchingPairs()
678  {
679  $this->matchingpairs = array();
680  }
681 
688  public function getMatchingPairCount()
689  {
690  return count($this->matchingpairs);
691  }
692 
699  public function getTerms()
700  {
701  return $this->terms;
702  }
703 
710  public function getDefinitions()
711  {
712  return $this->definitions;
713  }
714 
721  public function getTermCount()
722  {
723  return count($this->terms);
724  }
725 
732  public function getDefinitionCount()
733  {
734  return count($this->definitions);
735  }
736 
743  public function addTerm($term)
744  {
745  array_push($this->terms, $term);
746  }
747 
754  public function addDefinition($definition)
755  {
756  array_push($this->definitions, $definition);
757  }
758 
765  public function insertTerm($position, $term = null)
766  {
767  if (is_null($term))
768  {
769  include_once "./Modules/TestQuestionPool/classes/class.assAnswerMatchingTerm.php";
770  $term = new assAnswerMatchingTerm();
771  }
772  if ($position < count($this->terms))
773  {
774  $part1 = array_slice($this->terms, 0, $position);
775  $part2 = array_slice($this->terms, $position);
776  $this->terms = array_merge($part1, array($term), $part2);
777  }
778  else
779  {
780  array_push($this->terms, $term);
781  }
782  }
783 
790  public function insertDefinition($position, $definition = null)
791  {
792  if (is_null($definition))
793  {
794  include_once "./Modules/TestQuestionPool/classes/class.assAnswerMatchingDefinition.php";
795  $definition = new assAnswerMatchingDefinition();
796  }
797  if ($position < count($this->definitions))
798  {
799  $part1 = array_slice($this->definitions, 0, $position);
800  $part2 = array_slice($this->definitions, $position);
801  $this->definitions = array_merge($part1, array($definition), $part2);
802  }
803  else
804  {
805  array_push($this->definitions, $definition);
806  }
807  }
808 
813  public function flushTerms()
814  {
815  $this->terms = array();
816  }
817 
822  public function flushDefinitions()
823  {
824  $this->definitions = array();
825  }
826 
833  public function deleteTerm($position)
834  {
835  unset($this->terms[$position]);
836  $this->terms = array_values($this->terms);
837  }
838 
845  public function deleteDefinition($position)
846  {
847  unset($this->definitions[$position]);
848  $this->definitions = array_values($this->definitions);
849  }
850 
858  public function setTerm($term, $index)
859  {
860  $this->terms[$index] = $term;
861  }
862 
873  public function calculateReachedPoints($active_id, $pass = NULL, $returndetails = FALSE)
874  {
875  if( $returndetails )
876  {
877  throw new ilTestException('return details not implemented for '.__METHOD__);
878  }
879 
880  global $ilDB;
881 
882  $found_value1 = array();
883  $found_value2 = array();
884  if (is_null($pass))
885  {
886  $pass = $this->getSolutionMaxPass($active_id);
887  }
888  $result = $ilDB->queryF("SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
889  array('integer','integer','integer'),
890  array($active_id, $this->getId(), $pass)
891  );
892  while ($data = $ilDB->fetchAssoc($result))
893  {
894  if (strcmp($data["value1"], "") != 0)
895  {
896  array_push($found_value1, $data["value1"]);
897  array_push($found_value2, $data["value2"]);
898  }
899  }
900  $points = 0;
901  foreach ($found_value2 as $key => $value)
902  {
903  foreach ($this->matchingpairs as $pair)
904  {
905  if (($pair->definition->identifier == $value) && ($pair->term->identifier == $found_value1[$key]))
906  {
907  $points += $pair->points;
908  }
909  }
910  }
911 
912  return $points;
913  }
914 
918  function getMaximumPoints()
919  {
920  $points = 0;
921  foreach ($this->matchingpairs as $key => $pair)
922  {
923  if ($pair->points > 0)
924  {
925  $points += $pair->points;
926  }
927  }
928  return $points;
929  }
930 
940  {
941  $extension = "";
942  if (preg_match("/.*\\.(\\w+)$/", $filename, $matches))
943  {
944  $extension = $matches[1];
945  }
946  return md5($filename) . "." . $extension;
947  }
948 
949  public function removeTermImage($index)
950  {
951  $term = $this->terms[$index];
952  if (is_object($term))
953  {
954  $this->deleteImagefile($term->picture);
955  $term->picture = null;
956  }
957  }
958 
959  public function removeDefinitionImage($index)
960  {
961  $definition = $this->definitions[$index];
962  if (is_object($definition))
963  {
964  $this->deleteImagefile($definition->picture);
965  $definition->picture = null;
966  }
967  }
968 
969 
976  public function deleteImagefile($filename)
977  {
978  $deletename = $filename;
979  $result = @unlink($this->getImagePath().$deletename);
980  $result = $result & @unlink($this->getImagePath().$this->getThumbPrefix() . $deletename);
981  return $result;
982  }
983 
992  function setImageFile($image_tempfilename, $image_filename, $previous_filename = '')
993  {
994  $result = TRUE;
995  if (strlen($image_tempfilename))
996  {
997  $image_filename = str_replace(" ", "_", $image_filename);
998  $imagepath = $this->getImagePath();
999  if (!file_exists($imagepath))
1000  {
1001  ilUtil::makeDirParents($imagepath);
1002  }
1003  $savename = $image_filename;
1004  if (!ilUtil::moveUploadedFile($image_tempfilename, $savename, $imagepath.$savename))
1005  {
1006  $result = FALSE;
1007  }
1008  else
1009  {
1010  // create thumbnail file
1011  $thumbpath = $imagepath . $this->getThumbPrefix() . $savename;
1012  ilUtil::convertImage($imagepath.$savename, $thumbpath, "JPEG", $this->getThumbGeometry());
1013  }
1014  if ($result && (strcmp($image_filename, $previous_filename) != 0) && (strlen($previous_filename)))
1015  {
1016  $this->deleteImagefile($previous_filename);
1017  }
1018  }
1019  return $result;
1020  }
1021 
1028  function checkSaveData()
1029  {
1030  $result = true;
1031  $matching_values = array();
1032  foreach ($_POST['matching'][$this->getId()] as $definition => $term)
1033  {
1034  if ($term > 0)
1035  {
1036  array_push($matching_values, $term);
1037  }
1038  }
1039 
1040  $check_matching = array_flip($matching_values);
1041  if (count($check_matching) != count($matching_values))
1042  {
1043  $result = false;
1044  ilUtil::sendFailure($this->lng->txt("duplicate_matching_values_selected"), true);
1045  }
1046  return $result;
1047  }
1048 
1057  public function saveWorkingData($active_id, $pass = NULL)
1058  {
1059  global $ilDB;
1060  global $ilUser;
1061  $saveWorkingDataResult = $this->checkSaveData();
1062  $entered_values = 0;
1063  if ($saveWorkingDataResult)
1064  {
1065  if (is_null($pass))
1066  {
1067  include_once "./Modules/Test/classes/class.ilObjTest.php";
1068  $pass = ilObjTest::_getPass($active_id);
1069  }
1070 
1071  $this->getProcessLocker()->requestUserSolutionUpdateLock();
1072 
1073  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
1074  array('integer','integer','integer'),
1075  array($active_id, $this->getId(), $pass)
1076  );
1077 
1078  foreach ($_POST['matching'][$this->getId()] as $definition => $term)
1079  {
1080  $entered_values++;
1081  $next_id = $ilDB->nextId('tst_solutions');
1082  $affectedRows = $ilDB->insert("tst_solutions", array(
1083  "solution_id" => array("integer", $next_id),
1084  "active_fi" => array("integer", $active_id),
1085  "question_fi" => array("integer", $this->getId()),
1086  "value1" => array("clob", $term),
1087  "value2" => array("clob", $definition),
1088  "pass" => array("integer", $pass),
1089  "tstamp" => array("integer", time())
1090  ));
1091  }
1092 
1093  $this->getProcessLocker()->releaseUserSolutionUpdateLock();
1094 
1095  $saveWorkingDataResult = true;
1096  }
1097  if ($entered_values)
1098  {
1099  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1101  {
1102  $this->logAction($this->lng->txtlng("assessment", "log_user_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
1103  }
1104  }
1105  else
1106  {
1107  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1109  {
1110  $this->logAction($this->lng->txtlng("assessment", "log_user_not_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
1111  }
1112  }
1113 
1114  return $saveWorkingDataResult;
1115  }
1116 
1125  protected function reworkWorkingData($active_id, $pass, $obligationsAnswered)
1126  {
1127  // nothing to rework!
1128  }
1129 
1130  public function getRandomId()
1131  {
1132  mt_srand((double)microtime()*1000000);
1133  $random_number = mt_rand(1, 100000);
1134  $found = FALSE;
1135  while ($found)
1136  {
1137  $found = FALSE;
1138  foreach ($this->matchingpairs as $key => $pair)
1139  {
1140  if (($pair->term->identifier == $random_number) || ($pair->definition->identifier == $random_number))
1141  {
1142  $found = TRUE;
1143  $random_number++;
1144  }
1145  }
1146  }
1147  return $random_number;
1148  }
1149 
1156  public function setShuffle($shuffle)
1157  {
1158  switch ($shuffle)
1159  {
1160  case 0:
1161  case 1:
1162  case 2:
1163  case 3:
1164  $this->shuffle = $shuffle;
1165  break;
1166  default:
1167  $this->shuffle = 1;
1168  break;
1169  }
1170  }
1171 
1177  public function getQuestionType()
1178  {
1179  return "assMatchingQuestion";
1180  }
1181 
1187  public function getAdditionalTableName()
1188  {
1189  return "qpl_qst_matching";
1190  }
1191 
1197  public function getAnswerTableName()
1198  {
1199  return array("qpl_a_matching", "qpl_a_mterm");
1200  }
1201 
1206  public function getRTETextWithMediaObjects()
1207  {
1208  return parent::getRTETextWithMediaObjects();
1209  }
1210 
1214  public function &getMatchingPairs()
1215  {
1216  return $this->matchingpairs;
1217  }
1218 
1224  public function supportsJavascriptOutput()
1225  {
1226  return TRUE;
1227  }
1228 
1241  public function setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
1242  {
1243  include_once ("./Services/Excel/classes/class.ilExcelUtils.php");
1244  $solutions = $this->getSolutionValues($active_id, $pass);
1245  $worksheet->writeString($startrow, 0, ilExcelUtils::_convert_text($this->lng->txt($this->getQuestionType())), $format_title);
1246  $worksheet->writeString($startrow, 1, ilExcelUtils::_convert_text($this->getTitle()), $format_title);
1247  $imagepath = $this->getImagePath();
1248  $i = 1;
1249  foreach ($solutions as $solution)
1250  {
1251  $matches_written = FALSE;
1252  foreach ($this->getMatchingPairs() as $idx => $pair)
1253  {
1254  if (!$matches_written) $worksheet->writeString($startrow + $i, 1, ilExcelUtils::_convert_text($this->lng->txt("matches")));
1255  $matches_written = TRUE;
1256  if ($pair->definition->identifier == $solution["value2"])
1257  {
1258  if (strlen($pair->definition->text))
1259  {
1260  $worksheet->writeString($startrow + $i, 0, ilExcelUtils::_convert_text($pair->definition->text));
1261  }
1262  else
1263  {
1264  $worksheet->writeString($startrow + $i, 0, ilExcelUtils::_convert_text($pair->definition->picture));
1265  }
1266  }
1267  if ($pair->term->identifier == $solution["value1"])
1268  {
1269  if (strlen($pair->term->text))
1270  {
1271  $worksheet->writeString($startrow + $i, 2, ilExcelUtils::_convert_text($pair->term->text));
1272  }
1273  else
1274  {
1275  $worksheet->writeString($startrow + $i, 2, ilExcelUtils::_convert_text($pair->term->picture));
1276  }
1277  }
1278  }
1279  $i++;
1280  }
1281  return $startrow + $i + 1;
1282  }
1283 
1289  public function getThumbGeometry()
1290  {
1291  return $this->thumb_geometry;
1292  }
1293 
1299  public function getThumbSize()
1300  {
1301  return $this->getThumbGeometry();
1302  }
1303 
1309  public function setThumbGeometry($a_geometry)
1310  {
1311  $this->thumb_geometry = ($a_geometry < 1) ? 100 : $a_geometry;
1312  }
1313 
1319  public function getElementHeight()
1320  {
1321  return $this->element_height;
1322  }
1323 
1329  public function setElementHeight($a_height)
1330  {
1331  $this->element_height = ($a_height < 20) ? "" : $a_height;
1332  }
1333 
1337  public function rebuildThumbnails()
1338  {
1339  foreach ($this->terms as $term)
1340  {
1341  if (strlen($term->picture)) $this->generateThumbForFile($this->getImagePath(), $term->picture);
1342  }
1343  foreach ($this->definitions as $definition)
1344  {
1345  if (strlen($definition->picture)) $this->generateThumbForFile($this->getImagePath(), $definition->picture);
1346  }
1347  }
1348 
1349  public function getThumbPrefix()
1350  {
1351  return "thumb.";
1352  }
1353 
1354  protected function generateThumbForFile($path, $file)
1355  {
1356  $filename = $path . $file;
1357  if (@file_exists($filename))
1358  {
1359  $thumbpath = $path . $this->getThumbPrefix() . $file;
1360  $path_info = @pathinfo($filename);
1361  $ext = "";
1362  switch (strtoupper($path_info['extension']))
1363  {
1364  case 'PNG':
1365  $ext = 'PNG';
1366  break;
1367  case 'GIF':
1368  $ext = 'GIF';
1369  break;
1370  default:
1371  $ext = 'JPEG';
1372  break;
1373  }
1374  ilUtil::convertImage($filename, $thumbpath, $ext, $this->getThumbGeometry());
1375  }
1376  }
1377 
1378  public function getEstimatedElementHeight()
1379  {
1380  $hasImages = false;
1381  foreach ($this->terms as $term)
1382  {
1383  if (strlen($term->picture))
1384  {
1385  $hasImages = true;
1386  }
1387  }
1388  foreach ($this->definitions as $definition)
1389  {
1390  if (strlen($definition->picture))
1391  {
1392  $hasImages = true;
1393  }
1394  }
1395  if ($hasImages)
1396  { // 40 is approx. the height of the preview image
1397  return max($this->getElementHeight(), $this->getThumbSize() + 40);
1398  }
1399  else
1400  {
1401  return ($this->getElementHeight()) ? $this->getElementHeight() : 0;
1402  }
1403  }
1404 
1409  public function toJSON()
1410  {
1411  include_once("./Services/RTE/classes/class.ilRTE.php");
1412  $result = array();
1413  $result['id'] = (int) $this->getId();
1414  $result['type'] = (string) $this->getQuestionType();
1415  $result['title'] = (string) $this->getTitle();
1416  $result['question'] = $this->formatSAQuestion($this->getQuestion());
1417  $result['nr_of_tries'] = (int) $this->getNrOfTries();
1418  $result['shuffle'] = true;
1419  $result['feedback'] = array(
1420  "onenotcorrect" => $this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), false),
1421  "allcorrect" => $this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), true)
1422  );
1423 
1424  $terms = array("" => array("id"=>"-1",
1425  "term"=>$this->lng->txt("please_select")));
1426  foreach ($this->getTerms() as $term)
1427  {
1428  $terms[(int)$term->identifier] = array(
1429  "term" => $term->text,
1430  "id" =>(int)$term->identifier
1431  );
1432  }
1433  // $terms = $this->pcArrayShuffle($terms);
1434 
1435  // alex 9.9.2010 as a fix for bug 6513 I added the question id
1436  // to the "def_id" in the array. The $pair->definition->identifier is not
1437  // unique, since it gets it value from the morder table field
1438  // this value is not changed, when a question is copied.
1439  // thus copying the same question on a page results in problems
1440  // when the second one (the copy) is answered.
1441 
1442  $pairs = array();
1443  foreach ($this->getDefinitions() as $def)
1444  {
1445  array_push($pairs, array(
1446  "definition" => (string) $def->text,
1447  "def_id" => (int) $this->getId().$def->identifier,
1448  "terms" => $terms
1449  ));
1450  }
1451  $result['pairs'] = $pairs;
1452 
1453  // #10353
1454  $match = $points = array();
1455  foreach ($this->getMatchingPairs() as $pair)
1456  {
1457  $pid = $pair->definition->identifier;
1458 
1459  // we only need pairs with max. points for def-id
1460  if(!isset($match[$pid]) || $match[$pid]["points"] < $pair->points)
1461  {
1462  $match[$pid] = array(
1463  "term_id" => (int) $pair->term->identifier,
1464  "def_id" => (int) $this->getId().$pair->definition->identifier,
1465  "points" => (int) $pair->points
1466  );
1467  }
1468  }
1469  $result['match'] = array_values($match);
1470 
1471  $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $this->getId());
1472  $result['mobs'] = $mobs;
1473 
1474  return json_encode($result);
1475  }
1476 }
getThumbGeometry()
Get the thumbnail geometry.
Class for matching question terms.
supportsJavascriptOutput()
Returns true if the question type supports JavaScript output.
static makeDirParents($a_dir)
Create a new directory and all parent directories.
getId()
Gets the id of the assQuestion object.
duplicate($for_test=true, $title="", $author="", $owner="", $testObjId=null)
Duplicates an assMatchingQuestion.
getMaximumPoints()
Returns the maximum points, a learner can reach answering the question.
print $file
static _getOriginalId($question_id)
Returns the original id of a question.
formatSAQuestion($a_q)
Format self assessment question.
Class for matching question pairs.
getElementHeight()
Get the minimum element height.
$_POST['username']
Definition: cron.php:12
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
$result
getTermCount()
Returns the number of terms.
setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
Creates an Excel worksheet for the detailed cumulated results of this question.
copyObject($target_questionpool_id, $title="")
Copies an assMatchingQuestion.
& getSolutionValues($active_id, $pass=NULL)
Loads solutions of a given user from the database an returns it.
deleteMatchingPair($index=0)
Deletes a matching pair with a given index.
Abstract basic class which is to be extended by the concrete assessment question type classes...
_getPass($active_id)
Retrieves the actual pass of a given user for a given test.
_convert_text($a_text, $a_target="has been removed")
getDefinitionCount()
Returns the number of definitions.
getQuestionType()
Returns the question type of the question.
setId($id=-1)
Sets the id of the assQuestion object.
saveWorkingData($active_id, $pass=NULL)
Saves the learners input of the question to the database.
flushMatchingPairs()
Deletes all matching pairs.
setImageFile($image_tempfilename, $image_filename, $previous_filename='')
Sets the image file and uploads the image to the object&#39;s image directory.
getEncryptedFilename($filename)
Returns the encrypted save filename of a matching picture Images are saved with an encrypted filename...
flushTerms()
Deletes all terms.
deleteImagefile($filename)
Deletes an imagefile from the system if the file is deleted manually.
getSolutionMaxPass($active_id)
Returns the maximum pass a users question solution.
const MT_TERMS_DEFINITIONS
createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle="")
setEstimatedWorkingTime($hour=0, $min=0, $sec=0)
Sets the estimated working time of a question.
getRTETextWithMediaObjects()
Collects all text in the question which could contain media objects which were created with the Rich ...
getAdditionalTableName()
Returns the name of the additional question data table in the database.
calculateReachedPoints($active_id, $pass=NULL, $returndetails=FALSE)
Returns the points, a learner has reached answering the question.
setNrOfTries($a_nr_of_tries)
_enabledAssessmentLogging()
check wether assessment logging is enabled or not
deleteTerm($position)
Deletes a term.
setAdditionalContentEditingMode($additinalContentEditingMode)
setter for additional content editing mode for this question
rebuildThumbnails()
Rebuild the thumbnail images with a new thumbnail size.
getObjId()
Get the object id of the container object.
getDefinitions()
Returns the definitions of the matching question.
loadFromDb($question_id)
Loads a assMatchingQuestion object from a database.
getMatchingPair($index=0)
Returns a matching pair with a given index.
Base Exception for all Exceptions relating to Modules/Test.
Class for matching questions.
checkSaveData()
Checks the data to be saved for consistency.
$mobs
duplicateImages($question_id, $objectId=null)
fetchAssoc($a_set)
Fetch row as associative array from result set.
getTermWithIdentifier($a_identifier)
Returns a term with a given identifier.
insertMatchingPair($position, $term=null, $definition=null, $points=0.0)
Inserts a matching pair for an matching choice question.
setAuthor($author="")
Sets the authors name of the assQuestion object.
getImagePath($question_id=null, $object_id=null)
Returns the image path for web accessable images of a question.
insertDefinition($position, $definition=null)
Inserts a definition.
setTerm($term, $index)
Sets a specific term.
getMatchingPairCount()
Returns the number of matching pairs.
static moveUploadedFile($a_file, $a_name, $a_target, $a_raise_errors=true, $a_mode="move_uploaded")
move uploaded file
Interface ilObjAnswerScoringAdjustable.
getQuestion()
Gets the question string of the question object.
addDefinition($definition)
Adds a definition.
setElementHeight($a_height)
Set the minimum element height.
flushDefinitions()
Deletes all definitions.
insertTerm($position, $term=null)
Inserts a term.
saveAnswerSpecificDataToDb()
Saves the answer specific records into a question types answer table.
_getLogLanguage()
retrieve the log language for assessment logging
static sendFailure($a_info="", $a_keep=false)
Send Failure Message to Screen.
$filename
Definition: buildRTE.php:89
setShuffle($shuffle)
Sets the shuffle flag.
_getMobsOfObject($a_type, $a_id, $a_usage_hist_nr=0, $a_lang="-")
get mobs of object
__construct( $title="", $comment="", $author="", $owner=-1, $question="", $matching_type=MT_TERMS_DEFINITIONS)
assMatchingQuestion constructor
toJSON()
Returns a JSON representation of the question TODO.
setPoints($a_points)
Sets the maximum available points for the question.
saveQuestionDataToDb($original_id="")
deleteDefinition($position)
Deletes a definition.
static _replaceMediaObjectImageSrc($a_text, $a_direction=0)
replaces image source from mob image urls with the mob id or replaces mob id with the correct image s...
while($lm_rec=$ilDB->fetchAssoc($lm_set)) $data
getTerms()
Returns the terms of the matching question.
global $ilUser
Definition: imgupload.php:15
getDefinitionWithIdentifier($a_identifier)
Returns a definition with a given identifier.
setQuestion($question="")
Sets the question string of the question object.
static convertImage($a_from, $a_to, $a_target_format="", $a_geometry="", $a_background_color="")
convert image
Interface ilObjQuestionScoringAdjustable.
$path
Definition: index.php:22
setThumbGeometry($a_geometry)
Set the thumbnail geometry.
setOriginalId($original_id)
Class for matching question definitions.
addMatchingPair($term=null, $definition=null, $points=0.0)
Adds an matching pair for an matching choice question.
getAnswerTableName()
Returns the name of the answer table in the database.
logAction($logtext="", $active_id="", $question_id="")
Logs an action into the Test&Assessment log.
getTitle()
Gets the title string of the assQuestion object.
saveToDb($original_id="")
Saves a assMatchingQuestion object to a database.
& getMatchingPairs()
Returns the matchingpairs array.
copyImages($question_id, $source_questionpool)
setTitle($title="")
Sets the title string of the assQuestion object.
reworkWorkingData($active_id, $pass, $obligationsAnswered)
Reworks the allready saved working data if neccessary.
setObjId($obj_id=0)
Set the object id of the container object.
setComment($comment="")
Sets the comment string of the assQuestion object.
isComplete()
Returns true, if a matching question is complete for use.
getThumbSize()
Get the thumbnail geometry.
setOwner($owner="")
Sets the creator/owner ID of the assQuestion object.