ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
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 {
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  {
72  $elements[$key] = clone $element;
73  }
74 
75  $this->elements = $elements;
76  }
77 
81  public function getClone()
82  {
83  $that = clone $this;
84  return $that;
85  }
86 
90  public function getQuestionId()
91  {
92  return $this->questionId;
93  }
94 
98  public function setQuestionId($questionId)
99  {
100  $this->questionId = $questionId;
101  }
102 
106  public function loadFromDb()
107  {
108  $ilDB = isset($GLOBALS['DIC']) ? $GLOBALS['DIC']['ilDB'] : $GLOBALS['ilDB'];
109 
110  $result = $ilDB->queryF(
111  "SELECT * FROM qpl_a_ordering WHERE question_fi = %s ORDER BY position ASC",
112  array('integer'), array($this->getQuestionId())
113  );
114 
115  while( $row = $ilDB->fetchAssoc($result) )
116  {
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' ), array( $this->getQuestionId() )
143  );
144 
145  foreach($this as $orderElement)
146  {
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  {
169  $orderingElement->setContent('');
170  }
171  }
172 
173  public function countElements()
174  {
175  return count($this->elements);
176  }
177 
178  public function isFirstElementPosition($position)
179  {
180  return $position == 0;
181  }
182 
183  public function isLastElementPosition($position)
184  {
185  return $position == ($this->countElements() - 1);
186  }
187 
188  public function moveElementByPositions($currentPosition, $targetPosition)
189  {
190  $movingElement = $this->getElementByPosition($currentPosition);
191  $dodgingElement = $this->getElementByPosition($targetPosition);
192 
193  $elementList = new self();
194  $elementList->setQuestionId($this->getQuestionId());
195 
196  foreach($this as $element)
197  {
198  if( $element->getPosition() == $currentPosition )
199  {
200  $elementList->addElement($dodgingElement);
201  continue;
202  }
203 
204  if( $element->getPosition() == $targetPosition )
205  {
206  $elementList->addElement($movingElement);
207  continue;
208  }
209 
210  $elementList->addElement($element);
211  }
212 
213  $dodgingElement->setPosition($currentPosition);
214  $movingElement->setPosition($targetPosition);
215 
216  $this->setElements( $elementList->getElements() );
217  }
218 
219  public function removeElement(ilAssOrderingElement $removeElement)
220  {
221  $elementList = new self();
222  $elementList->setQuestionId($this->getQuestionId());
223 
224  $positionCounter = 0;
225 
226  foreach($this as $element)
227  {
228  if( $element->isSameElement($removeElement) )
229  {
230  continue;
231  }
232 
233  $element->setPosition($positionCounter++);
234  $elementList->addElement($element);
235  }
236  }
237 
241  public function resetElements()
242  {
243  $this->elements = array();
244  }
245 
249  public function setElements($elements)
250  {
251  $this->resetElements();
252 
253  foreach($elements as $element)
254  {
255  $this->addElement($element);
256  }
257  }
258 
262  public function getElements()
263  {
264  return $this->elements;
265  }
266 
271  {
272  return $this->getIndexedElements(self::IDENTIFIER_TYPE_RANDOM);
273  }
274 
278  public function getRandomIdentifierIndex()
279  {
280  return array_keys($this->getRandomIdentifierIndexedElements());
281  }
282 
287  {
288  return $this->getIndexedElements(self::IDENTIFIER_TYPE_SOLUTION);
289  }
290 
294  public function getSolutionIdentifierIndex()
295  {
296  return array_keys($this->getSolutionIdentifierIndexedElements());
297  }
298 
302  protected function getIndexedElements($identifierType)
303  {
304  $elements = array();
305 
306  foreach($this as $element)
307  {
308  $elements[$this->fetchIdentifier($element, $identifierType)] = $element;
309  }
310 
311  return $elements;
312  }
313 
317  public function addElement(ilAssOrderingElement $element)
318  {
319  if( $this->hasValidIdentifiers($element) )
320  {
321  $this->registerIdentifiers($element);
322  }
323 
324  $this->elements[] = $element;
325  }
326 
331  public function getElementByPosition($position)
332  {
333  if( isset($this->elements[$position]) )
334  {
335  return $this->elements[$position];
336  }
337 
338  return null;
339  }
340 
345  public function elementExistByPosition($position)
346  {
347  return ( $this->getElementByPosition($position) !== null );
348  }
349 
354  public function getElementByRandomIdentifier($randomIdentifier)
355  {
356  foreach($this as $element)
357  {
358  if( $element->getRandomIdentifier() != $randomIdentifier )
359  {
360  continue;
361  }
362 
363  return $element;
364  }
365 
366  return null;
367  }
368 
373  public function elementExistByRandomIdentifier($randomIdentifier)
374  {
375  return ( $this->getElementByRandomIdentifier($randomIdentifier) !== null );
376  }
377 
382  public function getElementBySolutionIdentifier($solutionIdentifier)
383  {
384  foreach($this as $element)
385  {
386  if( $element->getSolutionIdentifier() != $solutionIdentifier )
387  {
388  continue;
389  }
390 
391  return $element;
392  }
393  return null;
394  }
395 
400  public function elementExistBySolutionIdentifier($solutionIdentifier)
401  {
402  return ( $this->getElementBySolutionIdentifier($solutionIdentifier) !== null );
403  }
404 
408  protected function getRegisteredSolutionIdentifiers()
409  {
410  return $this->getRegisteredIdentifiers(self::IDENTIFIER_TYPE_SOLUTION);
411  }
412 
416  protected function getRegisteredRandomIdentifiers()
417  {
418  return $this->getRegisteredIdentifiers(self::IDENTIFIER_TYPE_RANDOM);
419  }
420 
425  protected function getRegisteredIdentifiers($identifierType)
426  {
427  if( !isset(self::$identifierRegistry[$identifierType][$this->getQuestionId()]) )
428  {
429  return array();
430  }
431 
432  return self::$identifierRegistry[$identifierType][$this->getQuestionId()];
433  }
434 
439  protected function hasValidIdentifiers(ilAssOrderingElement $element)
440  {
441  $identifier = $this->fetchIdentifier($element, self::IDENTIFIER_TYPE_SOLUTION);
442 
443  if( !$this->isValidIdentifier(self::IDENTIFIER_TYPE_SOLUTION, $identifier) )
444  {
445  return false;
446  }
447 
448  $identifier = $this->fetchIdentifier($element, self::IDENTIFIER_TYPE_RANDOM);
449 
450  if( !$this->isValidIdentifier(self::IDENTIFIER_TYPE_RANDOM, $identifier) )
451  {
452  return false;
453  }
454 
455  return true;
456  }
457 
461  protected function ensureValidIdentifiers(ilAssOrderingElement $element)
462  {
463  $this->ensureValidIdentifier($element, self::IDENTIFIER_TYPE_SOLUTION);
464  $this->ensureValidIdentifier($element, self::IDENTIFIER_TYPE_RANDOM);
465  }
466 
471  protected function ensureValidIdentifier(ilAssOrderingElement $element, $identifierType)
472  {
473  $identifier = $this->fetchIdentifier($element, $identifierType);
474 
475  if( !$this->isValidIdentifier($identifierType, $identifier) )
476  {
477  $identifier = $this->buildIdentifier($identifierType);
478  $this->populateIdentifier($element, $identifierType, $identifier);
479  $this->registerIdentifier($element, $identifierType);
480  }
481  }
482 
486  protected function registerIdentifiers(ilAssOrderingElement $element)
487  {
488  $this->registerIdentifier($element, self::IDENTIFIER_TYPE_SOLUTION);
489  $this->registerIdentifier($element, self::IDENTIFIER_TYPE_RANDOM);
490  }
491 
497  protected function registerIdentifier(ilAssOrderingElement $element, $identifierType)
498  {
499  if( !isset(self::$identifierRegistry[$identifierType][$this->getQuestionId()]) )
500  {
501  self::$identifierRegistry[$identifierType][$this->getQuestionId()] = array();
502  }
503 
504  $identifier = $this->fetchIdentifier($element, $identifierType);
505 
506  if( !in_array($identifier, self::$identifierRegistry[$identifierType][$this->getQuestionId()]) )
507  {
508  self::$identifierRegistry[$identifierType][$this->getQuestionId()][] = $identifier;
509  }
510  }
511 
518  protected function isIdentifierRegistered(ilAssOrderingElement $element, $identifierType)
519  {
520  if( !isset(self::$identifierRegistry[$identifierType][$this->getQuestionId()]) )
521  {
522  return false;
523  }
524 
525  $identifier = $this->fetchIdentifier($element, $identifierType);
526 
527  if( !in_array($identifier, self::$identifierRegistry[$identifierType][$this->getQuestionId()]) )
528  {
529  return false;
530  }
531 
532  return true;
533  }
534 
541  protected function fetchIdentifier(ilAssOrderingElement $element, $identifierType)
542  {
543  switch($identifierType)
544  {
545  case self::IDENTIFIER_TYPE_SOLUTION: return $element->getSolutionIdentifier();
546  case self::IDENTIFIER_TYPE_RANDOM: return $element->getRandomIdentifier();
547  }
548 
549  $this->throwUnknownIdentifierTypeException($identifierType);
550  }
551 
558  protected function populateIdentifier(ilAssOrderingElement $element, $identifierType, $identifier)
559  {
560  switch($identifierType)
561  {
562  case self::IDENTIFIER_TYPE_SOLUTION: $element->setSolutionIdentifier($identifier); break;
563  case self::IDENTIFIER_TYPE_RANDOM: $element->setRandomIdentifier($identifier); break;
564  default: $this->throwUnknownIdentifierTypeException($identifierType);
565  }
566  }
567 
574  protected function isValidIdentifier($identifierType, $identifier)
575  {
576  switch($identifierType)
577  {
578  case self::IDENTIFIER_TYPE_SOLUTION:
579  return self::isValidSolutionIdentifier($identifier);
580 
581  case self::IDENTIFIER_TYPE_RANDOM:
582  return self::isValidRandomIdentifier($identifier);
583  }
584 
585  $this->throwUnknownIdentifierTypeException($identifierType);
586  }
587 
593  protected function buildIdentifier($identifierType)
594  {
595  switch($identifierType)
596  {
597  case self::IDENTIFIER_TYPE_SOLUTION: return $this->buildSolutionIdentifier();
598  case self::IDENTIFIER_TYPE_RANDOM: return $this->buildRandomIdentifier();
599  }
600 
601  $this->throwUnknownIdentifierTypeException($identifierType);
602  }
603 
608  protected function throwUnknownIdentifierTypeException($identifierType)
609  {
610  throw new ilTestQuestionPoolException(
611  "unknown identifier type given (type: $identifierType)"
612  );
613  }
614 
619  protected function throwCouldNotBuildRandomIdentifierException($maxTries)
620  {
621  throw new ilTestQuestionPoolException(
622  "could not build random identifier (max tries: $maxTries)"
623  );
624  }
625 
630  protected function throwMissingReorderPositionException($randomIdentifier)
631  {
632  throw new ilTestQuestionPoolException(
633  "cannot reorder element due to missing position (random identifier: $randomIdentifier)"
634  );
635  }
636 
641  protected function throwUnknownRandomIdentifiersException($randomIdentifiers)
642  {
643  throw new ilTestQuestionPoolException(
644  'cannot reorder element due to one or more unknown random identifiers '.
645  '(' . implode(', ', $randomIdentifiers) . ')'
646  );
647  }
648 
652  protected function getLastSolutionIdentifier()
653  {
654  $lastSolutionIdentifier = null;
655 
656  foreach( $this->getRegisteredSolutionIdentifiers() as $registeredIdentifier)
657  {
658  if( $lastSolutionIdentifier > $registeredIdentifier )
659  {
660  continue;
661  }
662 
663  $lastSolutionIdentifier = $registeredIdentifier;
664  }
665 
666  return $lastSolutionIdentifier;
667  }
668 
672  protected function buildSolutionIdentifier()
673  {
674  $lastSolutionIdentifier = $this->getLastSolutionIdentifier();
675 
676  if( $lastSolutionIdentifier === null )
677  {
678  return 0;
679  }
680 
681  $nextSolutionIdentifier = $lastSolutionIdentifier + self::SOLUTION_IDENTIFIER_VALUE_INTERVAL;
682 
683  return $nextSolutionIdentifier;
684  }
685 
690  protected function buildRandomIdentifier()
691  {
692  $usedTriesCounter = 0;
693 
694  do
695  {
696  if( $usedTriesCounter >= self::RANDOM_IDENTIFIER_BUILD_MAX_TRIES )
697  {
698  $this->throwCouldNotBuildRandomIdentifierException(self::RANDOM_IDENTIFIER_BUILD_MAX_TRIES);
699  }
700 
701  $usedTriesCounter++;
702 
703  $lowerBound = self::RANDOM_IDENTIFIER_RANGE_LOWER_BOUND;
704  $upperBound = self::RANDOM_IDENTIFIER_RANGE_UPPER_BOUND;
705  $randomIdentifier = mt_rand($lowerBound, $upperBound);
706 
707  $testElement = new ilAssOrderingElement();
708  $testElement->setRandomIdentifier($randomIdentifier);
709  }
710  while( $this->isIdentifierRegistered($testElement, self::IDENTIFIER_TYPE_RANDOM) );
711 
712  return $randomIdentifier;
713  }
714 
715  public static function isValidSolutionIdentifier($identifier)
716  {
717  if( !is_numeric($identifier) )
718  {
719  return false;
720  }
721 
722  if( $identifier != (int)$identifier )
723  {
724  return false;
725  }
726 
727  if( $identifier < 0 )
728  {
729  return false;
730  }
731 
732  return true;
733  }
734 
735  public static function isValidRandomIdentifier($identifier)
736  {
737  if( !is_numeric($identifier) )
738  {
739  return false;
740  }
741 
742  if( $identifier != (int)$identifier )
743  {
744  return false;
745  }
746 
747  if( $identifier < self::RANDOM_IDENTIFIER_RANGE_LOWER_BOUND )
748  {
749  return false;
750  }
751 
752  if( $identifier > self::RANDOM_IDENTIFIER_RANGE_UPPER_BOUND )
753  {
754  return false;
755  }
756 
757  return true;
758  }
759 
760  public static function isValidPosition($position)
761  {
762  return self::isValidSolutionIdentifier($position); // this was the position earlier
763  }
764 
765  public static function isValidIndentation($indentation)
766  {
767  return self::isValidPosition($indentation); // horizontal position ^^
768  }
769 
774  {
775  foreach($this as $element)
776  {
777  $element->setRandomIdentifier( $this->buildRandomIdentifier() );
778  }
779  }
780 
785  public function hasSameElementSetByRandomIdentifiers(self $otherList)
786  {
787  $numIntersectingElements = count(array_intersect(
788  $otherList->getRandomIdentifierIndex(), $this->getRandomIdentifierIndex()
789  ));
790 
791  if( $numIntersectingElements != $this->countElements() )
792  {
793  return false;
794  }
795 
796  if( $numIntersectingElements != $otherList->countElements() )
797  {
798  return false;
799  }
800 
801  return true; // faster ;-)
802 
803  $otherListRandomIdentifierIndex = $otherList->getRandomIdentifierIndex();
804 
805  foreach($this as $orderingElement)
806  {
807  if( !in_array($orderingElement->getRandomIdentifier(), $otherListRandomIdentifierIndex) )
808  {
809  return false;
810  }
811 
812  $randomIdentifierIndexMatchingsCount = count( array_keys(
813  $otherListRandomIdentifierIndex, $orderingElement->getRandomIdentifier(), false
814  ));
815 
816  if( $randomIdentifierIndexMatchingsCount != 1 )
817  {
818  return false;
819  }
820  }
821 
822  return $this->countElements() == $otherList->countElements();
823  }
824 
825  public function getParityTrueElementList(self $otherList)
826  {
827  if( !$this->hasSameElementSetByRandomIdentifiers($otherList) )
828  {
829  throw new ilTestQuestionPoolException('cannot compare lists having different element sets');
830  }
831 
832  $parityTrueElementList = new self();
833  $parityTrueElementList->setQuestionId($this->getQuestionId());
834 
835  foreach($this as $thisElement)
836  {
837  $otherElement = $otherList->getElementByRandomIdentifier(
838  $thisElement->getRandomIdentifier()
839  );
840 
841  if( $otherElement->getPosition() != $thisElement->getPosition() )
842  {
843  continue;
844  }
845 
846  if( $otherElement->getIndentation() != $thisElement->getIndentation() )
847  {
848  continue;
849  }
850 
851  $parityTrueElementList->addElement($thisElement);
852  }
853 
854  return $parityTrueElementList;
855  }
856 
862  public function reorderByRandomIdentifiers($randomIdentifiers)
863  {
864  $positionsMap = array_flip( array_values($randomIdentifiers) );
865 
866  $orderedElements = array();
867 
868  foreach($this as $element)
869  {
870  if( !isset($positionsMap[$element->getRandomIdentifier()]) )
871  {
872  $this->throwMissingReorderPositionException($element->getRandomIdentifier());
873  }
874 
875  $position = $positionsMap[$element->getRandomIdentifier()];
876  unset($positionsMap[$element->getRandomIdentifier()]);
877 
878  $element->setPosition($position);
879  $orderedElements[$position] = $element;
880  }
881 
882  if( count($positionsMap) )
883  {
884  $this->throwUnknownRandomIdentifiersException( array_keys($positionsMap) );
885  }
886 
887  ksort($orderedElements);
888 
889  $this->setElements( array_values($orderedElements) );
890  }
891 
895  public function resetElementsIndentations()
896  {
897  foreach($this as $element)
898  {
899  $element->setIndentation(0);
900  }
901  }
902 
907  public function getDifferenceElementList(self $otherElementList)
908  {
909  $differenceRandomIdentifierIndex = $this->getDifferenceRandomIdentifierIndex($otherElementList);
910 
911  $differenceElementList = new self();
912  $differenceElementList->setQuestionId($this->getQuestionId());
913 
914  foreach($differenceRandomIdentifierIndex as $randomIdentifier)
915  {
916  $element = $this->getElementByRandomIdentifier($randomIdentifier);
917  $differenceElementList->addElement($element);
918  }
919 
920  return $differenceElementList;
921  }
922 
927  protected function getDifferenceRandomIdentifierIndex(self $otherElementList)
928  {
929  $differenceRandomIdentifierIndex = array_diff(
930  $this->getRandomIdentifierIndex(), $otherElementList->getRandomIdentifierIndex()
931  );
932 
933  return $differenceRandomIdentifierIndex;
934  }
935 
939  public function completeContentsFromElementList(self $otherList)
940  {
941  foreach($this as $thisElement)
942  {
943  if( !$otherList->elementExistByRandomIdentifier($thisElement->getRandomIdentifier()) )
944  {
945  continue;
946  }
947 
948  $otherElement = $otherList->getElementByRandomIdentifier(
949  $thisElement->getRandomIdentifier()
950  );
951 
952  $thisElement->setContent( $otherElement->getContent() );
953  }
954  }
955 
959  public function current() { return current($this->elements); }
960 
964  public function next() { return next($this->elements); }
965 
969  public function key() { return key($this->elements); }
970 
974  public function valid() { return ($this->key() !== null); }
975 
979  public function rewind() { return reset($this->elements); }
980 
984  public static function getFallbackDefaultElement()
985  {
986  $element = new ilAssOrderingElement();
987  $element->setRandomIdentifier(self::FALLBACK_DEFAULT_ELEMENT_RANDOM_IDENTIFIER);
988 
989  return $element;
990  }
991 
997  public static function buildInstance($questionId, $orderingElements = array())
998  {
999  $elementList = new self();
1000 
1001  $elementList->setQuestionId($questionId);
1002  $elementList->setElements($orderingElements);
1003 
1004  return $elementList;
1005  }
1006 }
__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)
removeElement(ilAssOrderingElement $removeElement)
setSolutionIdentifier($solutionIdentifier)
moveElementByPositions($currentPosition, $targetPosition)
$GLOBALS['loaded']
Global hash that tracks already loaded includes.
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)
Create styles array
The data for the language used.
fetchIdentifier(ilAssOrderingElement $element, $identifierType)
resetElementsIndentations()
resets the indentation to level 0 for all elements in list
global $ilDB
Add data(end) time
Method that wraps PHPs time in order to allow simulations with the workflow.
hasValidIdentifiers(ilAssOrderingElement $element)
ensureValidIdentifiers(ilAssOrderingElement $element)
clearElementContents()
clears the contents of all elements
registerIdentifier(ilAssOrderingElement $element, $identifierType)
getDifferenceElementList(self $otherElementList)