ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
class.ilAssOrderingElementList.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/questions/class.ilAssOrderingElement.php';
5 
13 {
14  public static $objectInstanceCounter = 0;
16 
20 
24 
28 
29  const IDENTIFIER_TYPE_SOLUTION = 'SolutionIds';
30  const IDENTIFIER_TYPE_RANDOM = 'RandomIds';
31 
35  protected static $identifierRegistry = array(
36  self::IDENTIFIER_TYPE_SOLUTION => array(),
37  self::IDENTIFIER_TYPE_RANDOM => array()
38  );
39 
43  protected $questionId;
44 
48  protected $elements;
49 
53  public function __construct()
54  {
55  $this->objectInstanceId = ++self::$objectInstanceCounter;
56 
57  $this->questionId = null;
58  $this->resetElements();
59  }
60 
64  public function __clone()
65  {
66  $this->objectInstanceId = ++self::$objectInstanceCounter;
67 
68  $elements = array();
69 
70  foreach ($this as $key => $element) {
71  $elements[$key] = clone $element;
72  }
73 
74  $this->elements = $elements;
75  }
76 
80  public function getClone()
81  {
82  $that = clone $this;
83  return $that;
84  }
85 
89  public function getQuestionId()
90  {
91  return $this->questionId;
92  }
93 
97  public function setQuestionId($questionId)
98  {
99  $this->questionId = $questionId;
100  }
101 
105  public function loadFromDb()
106  {
107  global $DIC; /* @var ILIAS\DI\Container $DIC */
108  $ilDB = $DIC['ilDB'];
109 
110  $result = $ilDB->queryF(
111  "SELECT * FROM qpl_a_ordering WHERE question_fi = %s ORDER BY position ASC",
112  array('integer'),
113  array($this->getQuestionId())
114  );
115 
116  while ($row = $ilDB->fetchAssoc($result)) {
117  $element = new ilAssOrderingElement();
118 
119  $element->setRandomIdentifier($row['random_id']);
120  $element->setSolutionIdentifier($row['solution_key']);
121 
122  $element->setPosition($row['position']);
123  $element->setIndentation($row["depth"]);
124 
125  $element->setContent($row['answertext']);
126 
127  $this->addElement($element);
128  $this->registerIdentifiers($element);
129  }
130  }
131 
135  public function saveToDb()
136  {
138  $ilDB = isset($GLOBALS['DIC']) ? $GLOBALS['DIC']['ilDB'] : $GLOBALS['DIC']['ilDB'];
139 
140  $ilDB->manipulateF(
141  "DELETE FROM qpl_a_ordering WHERE question_fi = %s",
142  array( 'integer' ),
143  array( $this->getQuestionId() )
144  );
145 
146  foreach ($this as $orderElement) {
147  $this->ensureValidIdentifiers($orderElement);
148 
149  $ilDB->insert('qpl_a_ordering', array(
150  'answer_id' => array( 'integer', $ilDB->nextId('qpl_a_ordering') ),
151  'question_fi' => array( 'integer', $this->getQuestionId() ),
152  'answertext' => array( 'text', $orderElement->getContent()),
153  'solution_key' => array( 'integer', $orderElement->getSolutionIdentifier() ),
154  'random_id' => array( 'integer', $orderElement->getRandomIdentifier() ),
155  'position' => array( 'integer', $orderElement->getPosition() ),
156  'depth' => array( 'integer', $orderElement->getIndentation() ),
157  'tstamp' => array( 'integer', time() )
158  ));
159  }
160  }
161 
165  public function clearElementContents()
166  {
167  foreach ($this as $orderingElement) {
168  $orderingElement->setContent('');
169  }
170  }
171 
172  public function countElements()
173  {
174  return count($this->elements);
175  }
176 
177  public function hasElements()
178  {
179  return (bool) $this->countElements();
180  }
181 
182  public function isFirstElementPosition($position)
183  {
184  return $position == 0;
185  }
186 
187  public function isLastElementPosition($position)
188  {
189  return $position == ($this->countElements() - 1);
190  }
191 
192  public function moveElementByPositions($currentPosition, $targetPosition)
193  {
194  $movingElement = $this->getElementByPosition($currentPosition);
195  $dodgingElement = $this->getElementByPosition($targetPosition);
196 
197  $elementList = new self();
198  $elementList->setQuestionId($this->getQuestionId());
199 
200  foreach ($this as $element) {
201  if ($element->getPosition() == $currentPosition) {
202  $elementList->addElement($dodgingElement);
203  continue;
204  }
205 
206  if ($element->getPosition() == $targetPosition) {
207  $elementList->addElement($movingElement);
208  continue;
209  }
210 
211  $elementList->addElement($element);
212  }
213 
214  $dodgingElement->setPosition($currentPosition);
215  $movingElement->setPosition($targetPosition);
216 
217  $this->setElements($elementList->getElements());
218  }
219 
220  public function removeElement(ilAssOrderingElement $removeElement)
221  {
222  $elementList = new self();
223  $elementList->setQuestionId($this->getQuestionId());
224 
225  $positionCounter = 0;
226 
227  foreach ($this as $element) {
228  if ($element->isSameElement($removeElement)) {
229  continue;
230  }
231 
232  $element->setPosition($positionCounter++);
233  $elementList->addElement($element);
234  }
235  }
236 
240  public function resetElements()
241  {
242  $this->elements = array();
243  }
244 
248  public function setElements($elements)
249  {
250  $this->resetElements();
251 
252  foreach ($elements as $element) {
253  $this->addElement($element);
254  }
255  }
256 
260  public function getElements()
261  {
262  return $this->elements;
263  }
264 
269  {
270  return $this->getIndexedElements(self::IDENTIFIER_TYPE_RANDOM);
271  }
272 
276  public function getRandomIdentifierIndex()
277  {
278  return array_keys($this->getRandomIdentifierIndexedElements());
279  }
280 
285  {
286  return $this->getIndexedElements(self::IDENTIFIER_TYPE_SOLUTION);
287  }
288 
292  public function getSolutionIdentifierIndex()
293  {
294  return array_keys($this->getSolutionIdentifierIndexedElements());
295  }
296 
300  protected function getIndexedElements($identifierType)
301  {
302  $elements = array();
303 
304  foreach ($this as $element) {
305  $elements[$this->fetchIdentifier($element, $identifierType)] = $element;
306  }
307 
308  return $elements;
309  }
310 
314  public function addElement(ilAssOrderingElement $element)
315  {
316  if ($this->hasValidIdentifiers($element)) {
317  $this->registerIdentifiers($element);
318  }
319 
320  $this->elements[] = $element;
321  }
322 
327  public function getElementByPosition($position)
328  {
329  if (isset($this->elements[$position])) {
330  return $this->elements[$position];
331  }
332 
333  return null;
334  }
335 
340  public function elementExistByPosition($position)
341  {
342  return ($this->getElementByPosition($position) !== null);
343  }
344 
349  public function getElementByRandomIdentifier($randomIdentifier)
350  {
351  foreach ($this as $element) {
352  if ($element->getRandomIdentifier() != $randomIdentifier) {
353  continue;
354  }
355 
356  return $element;
357  }
358 
359  return null;
360  }
361 
366  public function elementExistByRandomIdentifier($randomIdentifier)
367  {
368  return ($this->getElementByRandomIdentifier($randomIdentifier) !== null);
369  }
370 
375  public function getElementBySolutionIdentifier($solutionIdentifier)
376  {
377  foreach ($this as $element) {
378  if ($element->getSolutionIdentifier() != $solutionIdentifier) {
379  continue;
380  }
381 
382  return $element;
383  }
384  return null;
385  }
386 
391  public function elementExistBySolutionIdentifier($solutionIdentifier)
392  {
393  return ($this->getElementBySolutionIdentifier($solutionIdentifier) !== null);
394  }
395 
399  protected function getRegisteredSolutionIdentifiers()
400  {
401  return $this->getRegisteredIdentifiers(self::IDENTIFIER_TYPE_SOLUTION);
402  }
403 
407  protected function getRegisteredRandomIdentifiers()
408  {
409  return $this->getRegisteredIdentifiers(self::IDENTIFIER_TYPE_RANDOM);
410  }
411 
416  protected function getRegisteredIdentifiers($identifierType)
417  {
418  if (!isset(self::$identifierRegistry[$identifierType][$this->getQuestionId()])) {
419  return array();
420  }
421 
422  return self::$identifierRegistry[$identifierType][$this->getQuestionId()];
423  }
424 
429  protected function hasValidIdentifiers(ilAssOrderingElement $element)
430  {
431  $identifier = $this->fetchIdentifier($element, self::IDENTIFIER_TYPE_SOLUTION);
432 
433  if (!$this->isValidIdentifier(self::IDENTIFIER_TYPE_SOLUTION, $identifier)) {
434  return false;
435  }
436 
437  $identifier = $this->fetchIdentifier($element, self::IDENTIFIER_TYPE_RANDOM);
438 
439  if (!$this->isValidIdentifier(self::IDENTIFIER_TYPE_RANDOM, $identifier)) {
440  return false;
441  }
442 
443  return true;
444  }
445 
449  protected function ensureValidIdentifiers(ilAssOrderingElement $element)
450  {
451  $this->ensureValidIdentifier($element, self::IDENTIFIER_TYPE_SOLUTION);
452  $this->ensureValidIdentifier($element, self::IDENTIFIER_TYPE_RANDOM);
453  }
454 
459  protected function ensureValidIdentifier(ilAssOrderingElement $element, $identifierType)
460  {
461  $identifier = $this->fetchIdentifier($element, $identifierType);
462 
463  if (!$this->isValidIdentifier($identifierType, $identifier)) {
464  $identifier = $this->buildIdentifier($identifierType);
465  $this->populateIdentifier($element, $identifierType, $identifier);
466  $this->registerIdentifier($element, $identifierType);
467  }
468  }
469 
473  protected function registerIdentifiers(ilAssOrderingElement $element)
474  {
475  $this->registerIdentifier($element, self::IDENTIFIER_TYPE_SOLUTION);
476  $this->registerIdentifier($element, self::IDENTIFIER_TYPE_RANDOM);
477  }
478 
484  protected function registerIdentifier(ilAssOrderingElement $element, $identifierType)
485  {
486  if (!isset(self::$identifierRegistry[$identifierType][$this->getQuestionId()])) {
487  self::$identifierRegistry[$identifierType][$this->getQuestionId()] = array();
488  }
489 
490  $identifier = $this->fetchIdentifier($element, $identifierType);
491 
492  if (!in_array($identifier, self::$identifierRegistry[$identifierType][$this->getQuestionId()])) {
493  self::$identifierRegistry[$identifierType][$this->getQuestionId()][] = $identifier;
494  }
495  }
496 
503  protected function isIdentifierRegistered(ilAssOrderingElement $element, $identifierType)
504  {
505  if (!isset(self::$identifierRegistry[$identifierType][$this->getQuestionId()])) {
506  return false;
507  }
508 
509  $identifier = $this->fetchIdentifier($element, $identifierType);
510 
511  if (!in_array($identifier, self::$identifierRegistry[$identifierType][$this->getQuestionId()])) {
512  return false;
513  }
514 
515  return true;
516  }
517 
524  protected function fetchIdentifier(ilAssOrderingElement $element, $identifierType)
525  {
526  switch ($identifierType) {
527  case self::IDENTIFIER_TYPE_SOLUTION: return $element->getSolutionIdentifier();
528  case self::IDENTIFIER_TYPE_RANDOM: return $element->getRandomIdentifier();
529  }
530 
531  $this->throwUnknownIdentifierTypeException($identifierType);
532  }
533 
540  protected function populateIdentifier(ilAssOrderingElement $element, $identifierType, $identifier)
541  {
542  switch ($identifierType) {
543  case self::IDENTIFIER_TYPE_SOLUTION: $element->setSolutionIdentifier($identifier); break;
544  case self::IDENTIFIER_TYPE_RANDOM: $element->setRandomIdentifier($identifier); break;
545  default: $this->throwUnknownIdentifierTypeException($identifierType);
546  }
547  }
548 
555  protected function isValidIdentifier($identifierType, $identifier)
556  {
557  switch ($identifierType) {
558  case self::IDENTIFIER_TYPE_SOLUTION:
559  return self::isValidSolutionIdentifier($identifier);
560 
561  case self::IDENTIFIER_TYPE_RANDOM:
562  return self::isValidRandomIdentifier($identifier);
563  }
564 
565  $this->throwUnknownIdentifierTypeException($identifierType);
566  }
567 
573  protected function buildIdentifier($identifierType)
574  {
575  switch ($identifierType) {
576  case self::IDENTIFIER_TYPE_SOLUTION: return $this->buildSolutionIdentifier();
577  case self::IDENTIFIER_TYPE_RANDOM: return $this->buildRandomIdentifier();
578  }
579 
580  $this->throwUnknownIdentifierTypeException($identifierType);
581  }
582 
587  protected function throwUnknownIdentifierTypeException($identifierType)
588  {
589  throw new ilTestQuestionPoolException(
590  "unknown identifier type given (type: $identifierType)"
591  );
592  }
593 
598  protected function throwCouldNotBuildRandomIdentifierException($maxTries)
599  {
600  throw new ilTestQuestionPoolException(
601  "could not build random identifier (max tries: $maxTries)"
602  );
603  }
604 
609  protected function throwMissingReorderPositionException($randomIdentifier)
610  {
611  throw new ilTestQuestionPoolException(
612  "cannot reorder element due to missing position (random identifier: $randomIdentifier)"
613  );
614  }
615 
620  protected function throwUnknownRandomIdentifiersException($randomIdentifiers)
621  {
622  throw new ilTestQuestionPoolException(
623  'cannot reorder element due to one or more unknown random identifiers ' .
624  '(' . implode(', ', $randomIdentifiers) . ')'
625  );
626  }
627 
631  protected function getLastSolutionIdentifier()
632  {
633  $lastSolutionIdentifier = null;
634 
635  foreach ($this->getRegisteredSolutionIdentifiers() as $registeredIdentifier) {
636  if ($lastSolutionIdentifier > $registeredIdentifier) {
637  continue;
638  }
639 
640  $lastSolutionIdentifier = $registeredIdentifier;
641  }
642 
643  return $lastSolutionIdentifier;
644  }
645 
649  protected function buildSolutionIdentifier()
650  {
651  $lastSolutionIdentifier = $this->getLastSolutionIdentifier();
652 
653  if ($lastSolutionIdentifier === null) {
654  return 0;
655  }
656 
657  $nextSolutionIdentifier = $lastSolutionIdentifier + self::SOLUTION_IDENTIFIER_VALUE_INTERVAL;
658 
659  return $nextSolutionIdentifier;
660  }
661 
666  protected function buildRandomIdentifier()
667  {
668  $usedTriesCounter = 0;
669 
670  do {
671  if ($usedTriesCounter >= self::RANDOM_IDENTIFIER_BUILD_MAX_TRIES) {
672  $this->throwCouldNotBuildRandomIdentifierException(self::RANDOM_IDENTIFIER_BUILD_MAX_TRIES);
673  }
674 
675  $usedTriesCounter++;
676 
677  $lowerBound = self::RANDOM_IDENTIFIER_RANGE_LOWER_BOUND;
678  $upperBound = self::RANDOM_IDENTIFIER_RANGE_UPPER_BOUND;
679  $randomIdentifier = mt_rand($lowerBound, $upperBound);
680 
681  $testElement = new ilAssOrderingElement();
682  $testElement->setRandomIdentifier($randomIdentifier);
683  } while ($this->isIdentifierRegistered($testElement, self::IDENTIFIER_TYPE_RANDOM));
684 
685  return $randomIdentifier;
686  }
687 
688  public static function isValidSolutionIdentifier($identifier)
689  {
690  if (!is_numeric($identifier)) {
691  return false;
692  }
693 
694  if ($identifier != (int) $identifier) {
695  return false;
696  }
697 
698  if ($identifier < 0) {
699  return false;
700  }
701 
702  return true;
703  }
704 
705  public static function isValidRandomIdentifier($identifier)
706  {
707  if (!is_numeric($identifier)) {
708  return false;
709  }
710 
711  if ($identifier != (int) $identifier) {
712  return false;
713  }
714 
715  if ($identifier < self::RANDOM_IDENTIFIER_RANGE_LOWER_BOUND) {
716  return false;
717  }
718 
719  if ($identifier > self::RANDOM_IDENTIFIER_RANGE_UPPER_BOUND) {
720  return false;
721  }
722 
723  return true;
724  }
725 
726  public static function isValidPosition($position)
727  {
728  return self::isValidSolutionIdentifier($position); // this was the position earlier
729  }
730 
731  public static function isValidIndentation($indentation)
732  {
733  return self::isValidPosition($indentation); // horizontal position ^^
734  }
735 
740  {
741  foreach ($this as $element) {
742  $element->setRandomIdentifier($this->buildRandomIdentifier());
743  }
744  }
745 
750  public function hasSameElementSetByRandomIdentifiers(self $otherList)
751  {
752  $numIntersectingElements = count(array_intersect(
753  $otherList->getRandomIdentifierIndex(),
754  $this->getRandomIdentifierIndex()
755  ));
756 
757  if ($numIntersectingElements != $this->countElements()) {
758  return false;
759  }
760 
761  if ($numIntersectingElements != $otherList->countElements()) {
762  return false;
763  }
764 
765  return true; // faster ;-)
766 
767  $otherListRandomIdentifierIndex = $otherList->getRandomIdentifierIndex();
768 
769  foreach ($this as $orderingElement) {
770  if (!in_array($orderingElement->getRandomIdentifier(), $otherListRandomIdentifierIndex)) {
771  return false;
772  }
773 
774  $randomIdentifierIndexMatchingsCount = count(array_keys(
775  $otherListRandomIdentifierIndex,
776  $orderingElement->getRandomIdentifier(),
777  false
778  ));
779 
780  if ($randomIdentifierIndexMatchingsCount != 1) {
781  return false;
782  }
783  }
784 
785  return $this->countElements() == $otherList->countElements();
786  }
787 
788  public function getParityTrueElementList(self $otherList)
789  {
790  if (!$this->hasSameElementSetByRandomIdentifiers($otherList)) {
791  throw new ilTestQuestionPoolException('cannot compare lists having different element sets');
792  }
793 
794  $parityTrueElementList = new self();
795  $parityTrueElementList->setQuestionId($this->getQuestionId());
796 
797  foreach ($this as $thisElement) {
798  $otherElement = $otherList->getElementByRandomIdentifier(
799  $thisElement->getRandomIdentifier()
800  );
801 
802  if ($otherElement->getPosition() != $thisElement->getPosition()) {
803  continue;
804  }
805 
806  if ($otherElement->getIndentation() != $thisElement->getIndentation()) {
807  continue;
808  }
809 
810  $parityTrueElementList->addElement($thisElement);
811  }
812 
813  return $parityTrueElementList;
814  }
815 
821  public function reorderByRandomIdentifiers($randomIdentifiers)
822  {
823  $positionsMap = array_flip(array_values($randomIdentifiers));
824 
825  $orderedElements = array();
826 
827  foreach ($this as $element) {
828  if (!isset($positionsMap[$element->getRandomIdentifier()])) {
829  $this->throwMissingReorderPositionException($element->getRandomIdentifier());
830  }
831 
832  $position = $positionsMap[$element->getRandomIdentifier()];
833  unset($positionsMap[$element->getRandomIdentifier()]);
834 
835  $element->setPosition($position);
836  $orderedElements[$position] = $element;
837  }
838 
839  if (count($positionsMap)) {
840  $this->throwUnknownRandomIdentifiersException(array_keys($positionsMap));
841  }
842 
843  ksort($orderedElements);
844 
845  $this->setElements(array_values($orderedElements));
846  }
847 
851  public function resetElementsIndentations()
852  {
853  foreach ($this as $element) {
854  $element->setIndentation(0);
855  }
856  }
857 
862  public function getDifferenceElementList(self $otherElementList)
863  {
864  $differenceRandomIdentifierIndex = $this->getDifferenceRandomIdentifierIndex($otherElementList);
865 
866  $differenceElementList = new self();
867  $differenceElementList->setQuestionId($this->getQuestionId());
868 
869  foreach ($differenceRandomIdentifierIndex as $randomIdentifier) {
870  $element = $this->getElementByRandomIdentifier($randomIdentifier);
871  $differenceElementList->addElement($element);
872  }
873 
874  return $differenceElementList;
875  }
876 
881  protected function getDifferenceRandomIdentifierIndex(self $otherElementList)
882  {
883  $differenceRandomIdentifierIndex = array_diff(
884  $this->getRandomIdentifierIndex(),
885  $otherElementList->getRandomIdentifierIndex()
886  );
887 
888  return $differenceRandomIdentifierIndex;
889  }
890 
894  public function completeContentsFromElementList(self $otherList)
895  {
896  foreach ($this as $thisElement) {
897  if (!$otherList->elementExistByRandomIdentifier($thisElement->getRandomIdentifier())) {
898  continue;
899  }
900 
901  $otherElement = $otherList->getElementByRandomIdentifier(
902  $thisElement->getRandomIdentifier()
903  );
904 
905  $thisElement->setContent($otherElement->getContent());
906  }
907  }
908 
912  public function current()
913  {
914  return current($this->elements);
915  }
916 
920  public function next()
921  {
922  return next($this->elements);
923  }
924 
928  public function key()
929  {
930  return key($this->elements);
931  }
932 
936  public function valid()
937  {
938  return ($this->key() !== null);
939  }
940 
944  public function rewind()
945  {
946  return reset($this->elements);
947  }
948 
952  public static function getFallbackDefaultElement()
953  {
954  $element = new ilAssOrderingElement();
955  $element->setRandomIdentifier(self::FALLBACK_DEFAULT_ELEMENT_RANDOM_IDENTIFIER);
956 
957  return $element;
958  }
959 
965  public static function buildInstance($questionId, $orderingElements = array())
966  {
967  $elementList = new self();
968 
969  $elementList->setQuestionId($questionId);
970  $elementList->setElements($orderingElements);
971 
972  return $elementList;
973  }
974 
975  public function getHash()
976  {
977  $items = array();
978 
979  foreach ($this as $element) {
980  $items[] = implode(':', array(
981  $element->getSolutionIdentifier(),
982  $element->getRandomIdentifier(),
983  $element->getIndentation()
984  ));
985  }
986 
987  return md5(serialize($items));
988  }
989 }
__clone()
clone list by additionally cloning the element objects
registerIdentifiers(ilAssOrderingElement $element)
elementExistBySolutionIdentifier($solutionIdentifier)
isValidIdentifier($identifierType, $identifier)
$result
__construct()
ilAssOrderingElementList constructor.
populateIdentifier(ilAssOrderingElement $element, $identifierType, $identifier)
global $DIC
Definition: saml.php:7
removeElement(ilAssOrderingElement $removeElement)
setSolutionIdentifier($solutionIdentifier)
moveElementByPositions($currentPosition, $targetPosition)
static buildInstance($questionId, $orderingElements=array())
throwMissingReorderPositionException($randomIdentifier)
loadFromDb()
load elements from database
throwUnknownRandomIdentifiersException($randomIdentifiers)
getElementBySolutionIdentifier($solutionIdentifier)
ensureValidIdentifier(ilAssOrderingElement $element, $identifierType)
addElement(ilAssOrderingElement $element)
setRandomIdentifier($randomIdentifier)
getDifferenceRandomIdentifierIndex(self $otherElementList)
isIdentifierRegistered(ilAssOrderingElement $element, $identifierType)
$row
fetchIdentifier(ilAssOrderingElement $element, $identifierType)
resetElementsIndentations()
resets the indentation to level 0 for all elements in list
global $ilDB
$key
Definition: croninfo.php:18
hasValidIdentifiers(ilAssOrderingElement $element)
$GLOBALS['JPEG_Segment_Names']
Global Variable: XMP_tag_captions.
ensureValidIdentifiers(ilAssOrderingElement $element)
clearElementContents()
clears the contents of all elements
registerIdentifier(ilAssOrderingElement $element, $identifierType)
getDifferenceElementList(self $otherElementList)