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 6/** 7 * @author Björn Heyser <bheyser@databay.de> 8 * @version $Id$ 9 * 10 * @package Modules/Test(QuestionPool) 11 */ 12class ilAssOrderingElementList implements Iterator 13{ 14 public static $objectInstanceCounter = 0; 15 public $objectInstanceId; 16 17 const SOLUTION_IDENTIFIER_BUILD_MAX_TRIES = 1000; 18 const SOLUTION_IDENTIFIER_VALUE_INTERVAL = 1; 19 const SOLUTION_IDENTIFIER_START_VALUE = 0; 20 21 const RANDOM_IDENTIFIER_BUILD_MAX_TRIES = 1000; 22 const RANDOM_IDENTIFIER_RANGE_LOWER_BOUND = 1; 23 const RANDOM_IDENTIFIER_RANGE_UPPER_BOUND = 100000; 24 25 const FALLBACK_DEFAULT_ELEMENT_RANDOM_IDENTIFIER = 0; 26 const JS_ADDED_ELEMENTS_RANDOM_IDENTIFIER_START_VALUE = -1; 27 const JS_ADDED_ELEMENTS_RANDOM_IDENTIFIER_VALUE_INTERVAL = -1; 28 29 const IDENTIFIER_TYPE_SOLUTION = 'SolutionIds'; 30 const IDENTIFIER_TYPE_RANDOM = 'RandomIds'; 31 32 /** 33 * @var array[integer] 34 */ 35 protected static $identifierRegistry = array( 36 self::IDENTIFIER_TYPE_SOLUTION => array(), 37 self::IDENTIFIER_TYPE_RANDOM => array() 38 ); 39 40 /** 41 * @var integer 42 */ 43 protected $questionId; 44 45 /** 46 * @var array 47 */ 48 protected $elements; 49 50 /** 51 * ilAssOrderingElementList constructor. 52 */ 53 public function __construct() 54 { 55 $this->objectInstanceId = ++self::$objectInstanceCounter; 56 57 $this->questionId = null; 58 $this->resetElements(); 59 } 60 61 /** 62 * clone list by additionally cloning the element objects 63 */ 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 77 /** 78 * @return ilAssOrderingElementList 79 */ 80 public function getClone() 81 { 82 $that = clone $this; 83 return $that; 84 } 85 86 /** 87 * @return integer 88 */ 89 public function getQuestionId() 90 { 91 return $this->questionId; 92 } 93 94 /** 95 * @param integer $questionId 96 */ 97 public function setQuestionId($questionId) 98 { 99 $this->questionId = $questionId; 100 } 101 102 /** 103 * load elements from database 104 */ 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 132 /** 133 * TODO: refactor to a select/update/insert strategy incl. deleting all except existing 134 */ 135 public function saveToDb() 136 { 137 /** @var ilDBInterface $ilDB */ 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 162 /** 163 * clears the contents of all elements 164 */ 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 237 /** 238 * resets elements 239 */ 240 public function resetElements() 241 { 242 $this->elements = array(); 243 } 244 245 /** 246 * @param $elements 247 */ 248 public function setElements($elements) 249 { 250 $this->resetElements(); 251 252 foreach ($elements as $element) { 253 $this->addElement($element); 254 } 255 } 256 257 /** 258 * @return array[ilAssOrderingElement] 259 */ 260 public function getElements() 261 { 262 return $this->elements; 263 } 264 265 /** 266 * @return array 267 */ 268 public function getRandomIdentifierIndexedElements() 269 { 270 return $this->getIndexedElements(self::IDENTIFIER_TYPE_RANDOM); 271 } 272 273 /** 274 * @return array 275 */ 276 public function getRandomIdentifierIndex() 277 { 278 return array_keys($this->getRandomIdentifierIndexedElements()); 279 } 280 281 /** 282 * @return array 283 */ 284 public function getSolutionIdentifierIndexedElements() 285 { 286 return $this->getIndexedElements(self::IDENTIFIER_TYPE_SOLUTION); 287 } 288 289 /** 290 * @return array 291 */ 292 public function getSolutionIdentifierIndex() 293 { 294 return array_keys($this->getSolutionIdentifierIndexedElements()); 295 } 296 297 /** 298 * @return array 299 */ 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 311 /** 312 * @param ilAssOrderingElement $element 313 */ 314 public function addElement(ilAssOrderingElement $element) 315 { 316 if ($this->hasValidIdentifiers($element)) { 317 $this->registerIdentifiers($element); 318 } 319 320 $this->elements[] = $element; 321 } 322 323 /** 324 * @param $randomIdentifier 325 * @return ilAssOrderingElement 326 */ 327 public function getElementByPosition($position) 328 { 329 if (isset($this->elements[$position])) { 330 return $this->elements[$position]; 331 } 332 333 return null; 334 } 335 336 /** 337 * @param $position 338 * @return bool 339 */ 340 public function elementExistByPosition($position) 341 { 342 return ($this->getElementByPosition($position) !== null); 343 } 344 345 /** 346 * @param $randomIdentifier 347 * @return ilAssOrderingElement 348 */ 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 362 /** 363 * @param $randomIdentifier 364 * @return bool 365 */ 366 public function elementExistByRandomIdentifier($randomIdentifier) 367 { 368 return ($this->getElementByRandomIdentifier($randomIdentifier) !== null); 369 } 370 371 /** 372 * @param $randomIdentifier 373 * @return ilAssOrderingElement 374 */ 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 387 /** 388 * @param $solutionIdentifier 389 * @return bool 390 */ 391 public function elementExistBySolutionIdentifier($solutionIdentifier) 392 { 393 return ($this->getElementBySolutionIdentifier($solutionIdentifier) !== null); 394 } 395 396 /** 397 * @return array 398 */ 399 protected function getRegisteredSolutionIdentifiers() 400 { 401 return $this->getRegisteredIdentifiers(self::IDENTIFIER_TYPE_SOLUTION); 402 } 403 404 /** 405 * @return array 406 */ 407 protected function getRegisteredRandomIdentifiers() 408 { 409 return $this->getRegisteredIdentifiers(self::IDENTIFIER_TYPE_RANDOM); 410 } 411 412 /** 413 * @param string $identifierType 414 * @return array 415 */ 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 425 /** 426 * @param ilAssOrderingElement $element 427 * @return bool 428 */ 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 446 /** 447 * @param ilAssOrderingElement $element 448 */ 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 455 /** 456 * @param ilAssOrderingElement $element 457 * @param string $identifierType 458 */ 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 470 /** 471 * @param ilAssOrderingElement $element 472 */ 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 479 /** 480 * @param ilAssOrderingElement $element 481 * @param string $identifierType 482 * @throws ilTestQuestionPoolException 483 */ 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 497 /** 498 * @param ilAssOrderingElement $element 499 * @param string $identifierType 500 * @return bool 501 * @throws ilTestQuestionPoolException 502 */ 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 518 /** 519 * @param ilAssOrderingElement $element 520 * @param string $identifierType 521 * @return int 522 * @throws ilTestQuestionPoolException 523 */ 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 534 /** 535 * @param ilAssOrderingElement $element 536 * @param string $identifierType 537 * @param $identifier 538 * @throws ilTestQuestionPoolException 539 */ 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 549 /** 550 * @param string $identifierType 551 * @param $identifier 552 * @return mixed 553 * @throws ilTestQuestionPoolException 554 */ 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 568 /** 569 * @param string $identifierType 570 * @return integer 571 * @throws ilTestQuestionPoolException 572 */ 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 583 /** 584 * @param string $identifierType 585 * @throws ilTestQuestionPoolException 586 */ 587 protected function throwUnknownIdentifierTypeException($identifierType) 588 { 589 throw new ilTestQuestionPoolException( 590 "unknown identifier type given (type: $identifierType)" 591 ); 592 } 593 594 /** 595 * @param string $identifierType 596 * @throws ilTestQuestionPoolException 597 */ 598 protected function throwCouldNotBuildRandomIdentifierException($maxTries) 599 { 600 throw new ilTestQuestionPoolException( 601 "could not build random identifier (max tries: $maxTries)" 602 ); 603 } 604 605 /** 606 * @param string $randomIdentifier 607 * @throws ilTestQuestionPoolException 608 */ 609 protected function throwMissingReorderPositionException($randomIdentifier) 610 { 611 throw new ilTestQuestionPoolException( 612 "cannot reorder element due to missing position (random identifier: $randomIdentifier)" 613 ); 614 } 615 616 /** 617 * @param array $randomIdentifiers 618 * @throws ilTestQuestionPoolException 619 */ 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 628 /** 629 * @return integer|null $lastSolutionIdentifier 630 */ 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 646 /** 647 * @return integer|null $nextSolutionIdentifier 648 */ 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 662 /** 663 * @return int $randomIdentifier 664 * @throws ilTestQuestionPoolException 665 */ 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 736 /** 737 * 738 */ 739 public function distributeNewRandomIdentifiers() 740 { 741 foreach ($this as $element) { 742 $element->setRandomIdentifier($this->buildRandomIdentifier()); 743 } 744 } 745 746 /** 747 * @param ilAssOrderingElementList $otherList 748 * @return bool $hasSameElements 749 */ 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 816 /** 817 * @param $randomIdentifiers 818 * @return ilAssOrderingElementList 819 * @throws ilTestQuestionPoolException 820 */ 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 848 /** 849 * resets the indentation to level 0 for all elements in list 850 */ 851 public function resetElementsIndentations() 852 { 853 foreach ($this as $element) { 854 $element->setIndentation(0); 855 } 856 } 857 858 /** 859 * @param ilAssOrderingElementList $otherElementList 860 * @return $differenceElementList ilAssOrderingElementList 861 */ 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 877 /** 878 * @param ilAssOrderingElementList $other 879 * @return array 880 */ 881 protected function getDifferenceRandomIdentifierIndex(self $otherElementList) 882 { 883 $differenceRandomIdentifierIndex = array_diff( 884 $this->getRandomIdentifierIndex(), 885 $otherElementList->getRandomIdentifierIndex() 886 ); 887 888 return $differenceRandomIdentifierIndex; 889 } 890 891 /** 892 * @param ilAssOrderingElementList $otherList 893 */ 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 909 /** 910 * @return ilAssOrderingElement 911 */ 912 public function current() 913 { 914 return current($this->elements); 915 } 916 917 /** 918 * @return ilAssOrderingElement 919 */ 920 public function next() 921 { 922 return next($this->elements); 923 } 924 925 /** 926 * @return integer|bool 927 */ 928 public function key() 929 { 930 return key($this->elements); 931 } 932 933 /** 934 * @return bool 935 */ 936 public function valid() 937 { 938 return ($this->key() !== null); 939 } 940 941 /** 942 * @return ilAssOrderingElement 943 */ 944 public function rewind() 945 { 946 return reset($this->elements); 947 } 948 949 /** 950 * @return ilAssOrderingElement 951 */ 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 960 /** 961 * @param integer $questionId 962 * @param array[ilAssOrderingElement] $orderingElements 963 * @return ilAssOrderingElementList 964 */ 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} 990