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
4require_once 'Modules/TestQuestionPool/classes/questions/class.ilAssOrderingElement.php';
5
12class ilAssOrderingElementList implements Iterator
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
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
400 {
401 return $this->getRegisteredIdentifiers(self::IDENTIFIER_TYPE_SOLUTION);
402 }
403
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) {
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) {
559 return self::isValidSolutionIdentifier($identifier);
560
562 return self::isValidRandomIdentifier($identifier);
563 }
564
565 $this->throwUnknownIdentifierTypeException($identifierType);
566 }
567
573 protected function buildIdentifier($identifierType)
574 {
575 switch ($identifierType) {
578 }
579
580 $this->throwUnknownIdentifierTypeException($identifierType);
581 }
582
587 protected function throwUnknownIdentifierTypeException($identifierType)
588 {
590 "unknown identifier type given (type: $identifierType)"
591 );
592 }
593
599 {
601 "could not build random identifier (max tries: $maxTries)"
602 );
603 }
604
609 protected function throwMissingReorderPositionException($randomIdentifier)
610 {
612 "cannot reorder element due to missing position (random identifier: $randomIdentifier)"
613 );
614 }
615
620 protected function throwUnknownRandomIdentifiersException($randomIdentifiers)
621 {
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
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
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(
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}
$result
An exception for terminatinating execution or to throw for unit testing.
isIdentifierRegistered(ilAssOrderingElement $element, $identifierType)
registerIdentifiers(ilAssOrderingElement $element)
elementExistBySolutionIdentifier($solutionIdentifier)
getDifferenceElementList(self $otherElementList)
getElementBySolutionIdentifier($solutionIdentifier)
registerIdentifier(ilAssOrderingElement $element, $identifierType)
loadFromDb()
load elements from database
__construct()
ilAssOrderingElementList constructor.
getDifferenceRandomIdentifierIndex(self $otherElementList)
throwMissingReorderPositionException($randomIdentifier)
populateIdentifier(ilAssOrderingElement $element, $identifierType, $identifier)
removeElement(ilAssOrderingElement $removeElement)
static buildInstance($questionId, $orderingElements=array())
clearElementContents()
clears the contents of all elements
isValidIdentifier($identifierType, $identifier)
hasValidIdentifiers(ilAssOrderingElement $element)
ensureValidIdentifiers(ilAssOrderingElement $element)
fetchIdentifier(ilAssOrderingElement $element, $identifierType)
moveElementByPositions($currentPosition, $targetPosition)
addElement(ilAssOrderingElement $element)
__clone()
clone list by additionally cloning the element objects
ensureValidIdentifier(ilAssOrderingElement $element, $identifierType)
throwUnknownRandomIdentifiersException($randomIdentifiers)
resetElementsIndentations()
resets the indentation to level 0 for all elements in list
setRandomIdentifier($randomIdentifier)
setSolutionIdentifier($solutionIdentifier)
$key
Definition: croninfo.php:18
$row
$GLOBALS['JPEG_Segment_Names']
Global Variable: XMP_tag_captions.
global $DIC
Definition: saml.php:7
global $ilDB