ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
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
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 $ilDB = isset($GLOBALS['DIC']) ? $GLOBALS['DIC']['ilDB'] : $GLOBALS['ilDB'];
108
109 $result = $ilDB->queryF(
110 "SELECT * FROM qpl_a_ordering WHERE question_fi = %s ORDER BY position ASC",
111 array('integer'),
112 array($this->getQuestionId())
113 );
114
115 while ($row = $ilDB->fetchAssoc($result)) {
116 $element = new ilAssOrderingElement();
117
118 $element->setRandomIdentifier($row['random_id']);
119 $element->setSolutionIdentifier($row['solution_key']);
120
121 $element->setPosition($row['position']);
122 $element->setIndentation($row["depth"]);
123
124 $element->setContent($row['answertext']);
125
126 $this->addElement($element);
127 $this->registerIdentifiers($element);
128 }
129 }
130
134 public function saveToDb()
135 {
137 $ilDB = isset($GLOBALS['DIC']) ? $GLOBALS['DIC']['ilDB'] : $GLOBALS['DIC']['ilDB'];
138
139 $ilDB->manipulateF(
140 "DELETE FROM qpl_a_ordering WHERE question_fi = %s",
141 array( 'integer' ),
142 array( $this->getQuestionId() )
143 );
144
145 foreach ($this as $orderElement) {
146 $this->ensureValidIdentifiers($orderElement);
147
148 $ilDB->insert('qpl_a_ordering', array(
149 'answer_id' => array( 'integer', $ilDB->nextId('qpl_a_ordering') ),
150 'question_fi' => array( 'integer', $this->getQuestionId() ),
151 'answertext' => array( 'text', $orderElement->getContent()),
152 'solution_key' => array( 'integer', $orderElement->getSolutionIdentifier() ),
153 'random_id' => array( 'integer', $orderElement->getRandomIdentifier() ),
154 'position' => array( 'integer', $orderElement->getPosition() ),
155 'depth' => array( 'integer', $orderElement->getIndentation() ),
156 'tstamp' => array( 'integer', time() )
157 ));
158 }
159 }
160
164 public function clearElementContents()
165 {
166 foreach ($this as $orderingElement) {
167 $orderingElement->setContent('');
168 }
169 }
170
171 public function countElements()
172 {
173 return count($this->elements);
174 }
175
176 public function isFirstElementPosition($position)
177 {
178 return $position == 0;
179 }
180
181 public function isLastElementPosition($position)
182 {
183 return $position == ($this->countElements() - 1);
184 }
185
186 public function moveElementByPositions($currentPosition, $targetPosition)
187 {
188 $movingElement = $this->getElementByPosition($currentPosition);
189 $dodgingElement = $this->getElementByPosition($targetPosition);
190
191 $elementList = new self();
192 $elementList->setQuestionId($this->getQuestionId());
193
194 foreach ($this as $element) {
195 if ($element->getPosition() == $currentPosition) {
196 $elementList->addElement($dodgingElement);
197 continue;
198 }
199
200 if ($element->getPosition() == $targetPosition) {
201 $elementList->addElement($movingElement);
202 continue;
203 }
204
205 $elementList->addElement($element);
206 }
207
208 $dodgingElement->setPosition($currentPosition);
209 $movingElement->setPosition($targetPosition);
210
211 $this->setElements($elementList->getElements());
212 }
213
214 public function removeElement(ilAssOrderingElement $removeElement)
215 {
216 $elementList = new self();
217 $elementList->setQuestionId($this->getQuestionId());
218
219 $positionCounter = 0;
220
221 foreach ($this as $element) {
222 if ($element->isSameElement($removeElement)) {
223 continue;
224 }
225
226 $element->setPosition($positionCounter++);
227 $elementList->addElement($element);
228 }
229 }
230
234 public function resetElements()
235 {
236 $this->elements = array();
237 }
238
242 public function setElements($elements)
243 {
244 $this->resetElements();
245
246 foreach ($elements as $element) {
247 $this->addElement($element);
248 }
249 }
250
254 public function getElements()
255 {
256 return $this->elements;
257 }
258
263 {
264 return $this->getIndexedElements(self::IDENTIFIER_TYPE_RANDOM);
265 }
266
270 public function getRandomIdentifierIndex()
271 {
272 return array_keys($this->getRandomIdentifierIndexedElements());
273 }
274
279 {
280 return $this->getIndexedElements(self::IDENTIFIER_TYPE_SOLUTION);
281 }
282
287 {
288 return array_keys($this->getSolutionIdentifierIndexedElements());
289 }
290
294 protected function getIndexedElements($identifierType)
295 {
296 $elements = array();
297
298 foreach ($this as $element) {
299 $elements[$this->fetchIdentifier($element, $identifierType)] = $element;
300 }
301
302 return $elements;
303 }
304
308 public function addElement(ilAssOrderingElement $element)
309 {
310 if ($this->hasValidIdentifiers($element)) {
311 $this->registerIdentifiers($element);
312 }
313
314 $this->elements[] = $element;
315 }
316
321 public function getElementByPosition($position)
322 {
323 if (isset($this->elements[$position])) {
324 return $this->elements[$position];
325 }
326
327 return null;
328 }
329
334 public function elementExistByPosition($position)
335 {
336 return ($this->getElementByPosition($position) !== null);
337 }
338
343 public function getElementByRandomIdentifier($randomIdentifier)
344 {
345 foreach ($this as $element) {
346 if ($element->getRandomIdentifier() != $randomIdentifier) {
347 continue;
348 }
349
350 return $element;
351 }
352
353 return null;
354 }
355
360 public function elementExistByRandomIdentifier($randomIdentifier)
361 {
362 return ($this->getElementByRandomIdentifier($randomIdentifier) !== null);
363 }
364
369 public function getElementBySolutionIdentifier($solutionIdentifier)
370 {
371 foreach ($this as $element) {
372 if ($element->getSolutionIdentifier() != $solutionIdentifier) {
373 continue;
374 }
375
376 return $element;
377 }
378 return null;
379 }
380
385 public function elementExistBySolutionIdentifier($solutionIdentifier)
386 {
387 return ($this->getElementBySolutionIdentifier($solutionIdentifier) !== null);
388 }
389
394 {
395 return $this->getRegisteredIdentifiers(self::IDENTIFIER_TYPE_SOLUTION);
396 }
397
402 {
403 return $this->getRegisteredIdentifiers(self::IDENTIFIER_TYPE_RANDOM);
404 }
405
410 protected function getRegisteredIdentifiers($identifierType)
411 {
412 if (!isset(self::$identifierRegistry[$identifierType][$this->getQuestionId()])) {
413 return array();
414 }
415
416 return self::$identifierRegistry[$identifierType][$this->getQuestionId()];
417 }
418
423 protected function hasValidIdentifiers(ilAssOrderingElement $element)
424 {
425 $identifier = $this->fetchIdentifier($element, self::IDENTIFIER_TYPE_SOLUTION);
426
427 if (!$this->isValidIdentifier(self::IDENTIFIER_TYPE_SOLUTION, $identifier)) {
428 return false;
429 }
430
431 $identifier = $this->fetchIdentifier($element, self::IDENTIFIER_TYPE_RANDOM);
432
433 if (!$this->isValidIdentifier(self::IDENTIFIER_TYPE_RANDOM, $identifier)) {
434 return false;
435 }
436
437 return true;
438 }
439
443 protected function ensureValidIdentifiers(ilAssOrderingElement $element)
444 {
445 $this->ensureValidIdentifier($element, self::IDENTIFIER_TYPE_SOLUTION);
446 $this->ensureValidIdentifier($element, self::IDENTIFIER_TYPE_RANDOM);
447 }
448
453 protected function ensureValidIdentifier(ilAssOrderingElement $element, $identifierType)
454 {
455 $identifier = $this->fetchIdentifier($element, $identifierType);
456
457 if (!$this->isValidIdentifier($identifierType, $identifier)) {
458 $identifier = $this->buildIdentifier($identifierType);
459 $this->populateIdentifier($element, $identifierType, $identifier);
460 $this->registerIdentifier($element, $identifierType);
461 }
462 }
463
467 protected function registerIdentifiers(ilAssOrderingElement $element)
468 {
469 $this->registerIdentifier($element, self::IDENTIFIER_TYPE_SOLUTION);
470 $this->registerIdentifier($element, self::IDENTIFIER_TYPE_RANDOM);
471 }
472
478 protected function registerIdentifier(ilAssOrderingElement $element, $identifierType)
479 {
480 if (!isset(self::$identifierRegistry[$identifierType][$this->getQuestionId()])) {
481 self::$identifierRegistry[$identifierType][$this->getQuestionId()] = array();
482 }
483
484 $identifier = $this->fetchIdentifier($element, $identifierType);
485
486 if (!in_array($identifier, self::$identifierRegistry[$identifierType][$this->getQuestionId()])) {
487 self::$identifierRegistry[$identifierType][$this->getQuestionId()][] = $identifier;
488 }
489 }
490
497 protected function isIdentifierRegistered(ilAssOrderingElement $element, $identifierType)
498 {
499 if (!isset(self::$identifierRegistry[$identifierType][$this->getQuestionId()])) {
500 return false;
501 }
502
503 $identifier = $this->fetchIdentifier($element, $identifierType);
504
505 if (!in_array($identifier, self::$identifierRegistry[$identifierType][$this->getQuestionId()])) {
506 return false;
507 }
508
509 return true;
510 }
511
518 protected function fetchIdentifier(ilAssOrderingElement $element, $identifierType)
519 {
520 switch ($identifierType) {
522 case self::IDENTIFIER_TYPE_RANDOM: return $element->getRandomIdentifier();
523 }
524
525 $this->throwUnknownIdentifierTypeException($identifierType);
526 }
527
534 protected function populateIdentifier(ilAssOrderingElement $element, $identifierType, $identifier)
535 {
536 switch ($identifierType) {
537 case self::IDENTIFIER_TYPE_SOLUTION: $element->setSolutionIdentifier($identifier); break;
538 case self::IDENTIFIER_TYPE_RANDOM: $element->setRandomIdentifier($identifier); break;
539 default: $this->throwUnknownIdentifierTypeException($identifierType);
540 }
541 }
542
549 protected function isValidIdentifier($identifierType, $identifier)
550 {
551 switch ($identifierType) {
553 return self::isValidSolutionIdentifier($identifier);
554
556 return self::isValidRandomIdentifier($identifier);
557 }
558
559 $this->throwUnknownIdentifierTypeException($identifierType);
560 }
561
567 protected function buildIdentifier($identifierType)
568 {
569 switch ($identifierType) {
572 }
573
574 $this->throwUnknownIdentifierTypeException($identifierType);
575 }
576
581 protected function throwUnknownIdentifierTypeException($identifierType)
582 {
584 "unknown identifier type given (type: $identifierType)"
585 );
586 }
587
593 {
595 "could not build random identifier (max tries: $maxTries)"
596 );
597 }
598
603 protected function throwMissingReorderPositionException($randomIdentifier)
604 {
606 "cannot reorder element due to missing position (random identifier: $randomIdentifier)"
607 );
608 }
609
614 protected function throwUnknownRandomIdentifiersException($randomIdentifiers)
615 {
617 'cannot reorder element due to one or more unknown random identifiers ' .
618 '(' . implode(', ', $randomIdentifiers) . ')'
619 );
620 }
621
625 protected function getLastSolutionIdentifier()
626 {
627 $lastSolutionIdentifier = null;
628
629 foreach ($this->getRegisteredSolutionIdentifiers() as $registeredIdentifier) {
630 if ($lastSolutionIdentifier > $registeredIdentifier) {
631 continue;
632 }
633
634 $lastSolutionIdentifier = $registeredIdentifier;
635 }
636
637 return $lastSolutionIdentifier;
638 }
639
643 protected function buildSolutionIdentifier()
644 {
645 $lastSolutionIdentifier = $this->getLastSolutionIdentifier();
646
647 if ($lastSolutionIdentifier === null) {
648 return 0;
649 }
650
651 $nextSolutionIdentifier = $lastSolutionIdentifier + self::SOLUTION_IDENTIFIER_VALUE_INTERVAL;
652
653 return $nextSolutionIdentifier;
654 }
655
660 protected function buildRandomIdentifier()
661 {
662 $usedTriesCounter = 0;
663
664 do {
665 if ($usedTriesCounter >= self::RANDOM_IDENTIFIER_BUILD_MAX_TRIES) {
666 $this->throwCouldNotBuildRandomIdentifierException(self::RANDOM_IDENTIFIER_BUILD_MAX_TRIES);
667 }
668
669 $usedTriesCounter++;
670
673 $randomIdentifier = mt_rand($lowerBound, $upperBound);
674
675 $testElement = new ilAssOrderingElement();
676 $testElement->setRandomIdentifier($randomIdentifier);
677 } while ($this->isIdentifierRegistered($testElement, self::IDENTIFIER_TYPE_RANDOM));
678
679 return $randomIdentifier;
680 }
681
682 public static function isValidSolutionIdentifier($identifier)
683 {
684 if (!is_numeric($identifier)) {
685 return false;
686 }
687
688 if ($identifier != (int) $identifier) {
689 return false;
690 }
691
692 if ($identifier < 0) {
693 return false;
694 }
695
696 return true;
697 }
698
699 public static function isValidRandomIdentifier($identifier)
700 {
701 if (!is_numeric($identifier)) {
702 return false;
703 }
704
705 if ($identifier != (int) $identifier) {
706 return false;
707 }
708
709 if ($identifier < self::RANDOM_IDENTIFIER_RANGE_LOWER_BOUND) {
710 return false;
711 }
712
713 if ($identifier > self::RANDOM_IDENTIFIER_RANGE_UPPER_BOUND) {
714 return false;
715 }
716
717 return true;
718 }
719
720 public static function isValidPosition($position)
721 {
722 return self::isValidSolutionIdentifier($position); // this was the position earlier
723 }
724
725 public static function isValidIndentation($indentation)
726 {
727 return self::isValidPosition($indentation); // horizontal position ^^
728 }
729
734 {
735 foreach ($this as $element) {
736 $element->setRandomIdentifier($this->buildRandomIdentifier());
737 }
738 }
739
744 public function hasSameElementSetByRandomIdentifiers(self $otherList)
745 {
746 $numIntersectingElements = count(array_intersect(
747 $otherList->getRandomIdentifierIndex(),
748 $this->getRandomIdentifierIndex()
749 ));
750
751 if ($numIntersectingElements != $this->countElements()) {
752 return false;
753 }
754
755 if ($numIntersectingElements != $otherList->countElements()) {
756 return false;
757 }
758
759 return true; // faster ;-)
760
761 $otherListRandomIdentifierIndex = $otherList->getRandomIdentifierIndex();
762
763 foreach ($this as $orderingElement) {
764 if (!in_array($orderingElement->getRandomIdentifier(), $otherListRandomIdentifierIndex)) {
765 return false;
766 }
767
768 $randomIdentifierIndexMatchingsCount = count(array_keys(
769 $otherListRandomIdentifierIndex,
770 $orderingElement->getRandomIdentifier(),
771 false
772 ));
773
774 if ($randomIdentifierIndexMatchingsCount != 1) {
775 return false;
776 }
777 }
778
779 return $this->countElements() == $otherList->countElements();
780 }
781
782 public function getParityTrueElementList(self $otherList)
783 {
784 if (!$this->hasSameElementSetByRandomIdentifiers($otherList)) {
785 throw new ilTestQuestionPoolException('cannot compare lists having different element sets');
786 }
787
788 $parityTrueElementList = new self();
789 $parityTrueElementList->setQuestionId($this->getQuestionId());
790
791 foreach ($this as $thisElement) {
792 $otherElement = $otherList->getElementByRandomIdentifier(
793 $thisElement->getRandomIdentifier()
794 );
795
796 if ($otherElement->getPosition() != $thisElement->getPosition()) {
797 continue;
798 }
799
800 if ($otherElement->getIndentation() != $thisElement->getIndentation()) {
801 continue;
802 }
803
804 $parityTrueElementList->addElement($thisElement);
805 }
806
807 return $parityTrueElementList;
808 }
809
815 public function reorderByRandomIdentifiers($randomIdentifiers)
816 {
817 $positionsMap = array_flip(array_values($randomIdentifiers));
818
819 $orderedElements = array();
820
821 foreach ($this as $element) {
822 if (!isset($positionsMap[$element->getRandomIdentifier()])) {
823 $this->throwMissingReorderPositionException($element->getRandomIdentifier());
824 }
825
826 $position = $positionsMap[$element->getRandomIdentifier()];
827 unset($positionsMap[$element->getRandomIdentifier()]);
828
829 $element->setPosition($position);
830 $orderedElements[$position] = $element;
831 }
832
833 if (count($positionsMap)) {
834 $this->throwUnknownRandomIdentifiersException(array_keys($positionsMap));
835 }
836
837 ksort($orderedElements);
838
839 $this->setElements(array_values($orderedElements));
840 }
841
846 {
847 foreach ($this as $element) {
848 $element->setIndentation(0);
849 }
850 }
851
856 public function getDifferenceElementList(self $otherElementList)
857 {
858 $differenceRandomIdentifierIndex = $this->getDifferenceRandomIdentifierIndex($otherElementList);
859
860 $differenceElementList = new self();
861 $differenceElementList->setQuestionId($this->getQuestionId());
862
863 foreach ($differenceRandomIdentifierIndex as $randomIdentifier) {
864 $element = $this->getElementByRandomIdentifier($randomIdentifier);
865 $differenceElementList->addElement($element);
866 }
867
868 return $differenceElementList;
869 }
870
875 protected function getDifferenceRandomIdentifierIndex(self $otherElementList)
876 {
877 $differenceRandomIdentifierIndex = array_diff(
879 $otherElementList->getRandomIdentifierIndex()
880 );
881
882 return $differenceRandomIdentifierIndex;
883 }
884
888 public function completeContentsFromElementList(self $otherList)
889 {
890 foreach ($this as $thisElement) {
891 if (!$otherList->elementExistByRandomIdentifier($thisElement->getRandomIdentifier())) {
892 continue;
893 }
894
895 $otherElement = $otherList->getElementByRandomIdentifier(
896 $thisElement->getRandomIdentifier()
897 );
898
899 $thisElement->setContent($otherElement->getContent());
900 }
901 }
902
906 public function current()
907 {
908 return current($this->elements);
909 }
910
914 public function next()
915 {
916 return next($this->elements);
917 }
918
922 public function key()
923 {
924 return key($this->elements);
925 }
926
930 public function valid()
931 {
932 return ($this->key() !== null);
933 }
934
938 public function rewind()
939 {
940 return reset($this->elements);
941 }
942
946 public static function getFallbackDefaultElement()
947 {
948 $element = new ilAssOrderingElement();
949 $element->setRandomIdentifier(self::FALLBACK_DEFAULT_ELEMENT_RANDOM_IDENTIFIER);
950
951 return $element;
952 }
953
959 public static function buildInstance($questionId, $orderingElements = array())
960 {
961 $elementList = new self();
962
963 $elementList->setQuestionId($questionId);
964 $elementList->setElements($orderingElements);
965
966 return $elementList;
967 }
968}
$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
$GLOBALS['loaded']
Global hash that tracks already loaded includes.
global $ilDB