Differences Between: [Versions 310 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 function scorm_seq_exit_action_rules($seq, $userid) { 18 $sco = $seq->currentactivity; 19 $ancestors = scorm_get_ancestors($sco); 20 $exittarget = null; 21 foreach (array_reverse($ancestors) as $ancestor) { 22 if (scorm_seq_rules_check($ancestor, 'exit') != null) { 23 $exittarget = $ancestor; 24 break; 25 } 26 } 27 if ($exittarget != null) { 28 $commons = array_slice($ancestors, 0, scorm_find_common_ancestor($ancestors, $exittarget)); 29 30 // Terminate Descendent Attempts Process. 31 if ($commons) { 32 foreach ($commons as $ancestor) { 33 scorm_seq_end_attempt($ancestor, $userid, $seq->attempt); 34 $seq->currentactivity = $ancestor; 35 } 36 } 37 } 38 return $seq; 39 } 40 41 function scorm_seq_post_cond_rules($seq, $userid) { 42 $sco = $seq->currentactivity; 43 if (!$seq->suspended) { 44 if ($action = scorm_seq_rules_check($sco, 'post') != null) { 45 switch($action) { 46 case 'retry': 47 case 'continue': 48 case 'previous': 49 $seq->sequencing = $action; 50 break; 51 case 'exitparent': 52 case 'exitall': 53 $seq->termination = $action; 54 break; 55 case 'retryall': 56 $seq->termination = 'exitall'; 57 $seq->sequencing = 'retry'; 58 break; 59 } 60 } 61 } 62 return $seq; 63 } 64 65 66 function scorm_seq_evaluate_rollupcond($sco, $conditioncombination, $rollupruleconds, $userid) { 67 $bag = Array(); 68 $con = ""; 69 $val = false; 70 $unk = false; 71 foreach ($rollupruleconds as $rolluprulecond) { 72 $condit = scorm_evaluate_condition($rolluprulecond, $sco, $userid); 73 if ($rolluprulecond->operator == 'not') { // If operator is not, negate the condition. 74 if ($rolluprulecond->cond != 'unknown') { 75 if ($condit) { 76 $condit = false; 77 } else { 78 $condit = true; 79 } 80 } else { 81 $condit = 'unknown'; 82 } 83 array_push($childrenbag, $condit); 84 } 85 } 86 if (empty($bag)) { 87 return 'unknown'; 88 } else { 89 $i = 0; 90 foreach ($bag as $b) { 91 if ($rolluprulecond->conditioncombination == 'all') { 92 $val = true; 93 if ($b == 'unknown') { 94 $unk = true; 95 } 96 if ($b === false) { 97 return false; 98 } 99 } else { 100 $val = false; 101 102 if ($b == 'unknown') { 103 $unk = true; 104 } 105 if ($b === true) { 106 return true; 107 } 108 } 109 } 110 } 111 if ($unk) { 112 return 'unknown'; 113 } 114 return $val; 115 } 116 117 function scorm_seq_check_child ($sco, $action, $userid) { 118 global $DB; 119 120 $included = false; 121 $sco = scorm_get_sco($sco->id); 122 $r = $DB->get_record('scorm_scoes_track', array('scoid' => $sco->id, 'userid' => $userid, 'element' => 'activityattemptcount')); 123 if ($action == 'satisfied' || $action == 'notsatisfied') { 124 if (!$sco->rollupobjectivesatisfied) { 125 $included = true; 126 if (($action == 'satisfied' && $sco->requiredforsatisfied == 'ifnotsuspended') || 127 ($action == 'notsatisfied' && $sco->requiredfornotsatisfied == 'ifnotsuspended')) { 128 129 if (!scorm_seq_is('activityprogressstatus', $sco->id, $userid) || 130 ((($r->value) > 0) && !scorm_seq_is('suspended', $sco->id, $userid))) { 131 $included = false; 132 } 133 134 } else { 135 if (($action == 'satisfied' && $sco->requiredforsatisfied == 'ifattempted') || 136 ($action == 'notsatisfied' && $sco->requiredfornotsatisfied == 'ifattempted')) { 137 if (!scorm_seq_is('activityprogressstatus', $sco->id, $userid) || (($r->value) == 0)) { 138 $included = false; 139 } 140 } else { 141 if (($action == 'satisfied' && $sco->requiredforsatisfied == 'ifnotskipped') || 142 ($action == 'notsatisfied' && $sco->requiredfornotsatisfied == 'ifnotskipped')) { 143 $rulch = scorm_seq_rules_check($sco, 'skip'); 144 if ($rulch != null) { 145 $included = false; 146 } 147 } 148 } 149 } 150 } 151 } 152 if ($action == 'completed' || $action == 'incomplete') { 153 if (!$sco->rollupprogresscompletion) { 154 $included = true; 155 156 if (($action == 'completed' && $sco->requiredforcompleted == 'ifnotsuspended') || 157 ($action == 'incomplete' && $sco->requiredforincomplete == 'ifnotsuspended')) { 158 159 if (!scorm_seq_is('activityprogressstatus', $sco->id, $userid) || 160 ((($r->value) > 0)&& !scorm_seq_is('suspended', $sco->id, $userid))) { 161 $included = false; 162 } 163 164 } else { 165 166 if (($action == 'completed' && $sco->requiredforcompleted == 'ifattempted') || 167 ($action == 'incomplete' && $sco->requiredforincomplete == 'ifattempted')) { 168 if (!scorm_seq_is('activityprogressstatus', $sco->id, $userid) || (($r->value) == 0)) { 169 $included = false; 170 } 171 172 } else { 173 if (($action == 'completed' && $sco->requiredforsatisfied == 'ifnotskipped') || 174 ($action == 'incomplete' && $sco->requiredfornotsatisfied == 'ifnotskipped')) { 175 $rulch = scorm_seq_rules_check($sco, 'skip'); 176 if ($rulch != null) { 177 $included = false; 178 } 179 } 180 } 181 } 182 } 183 } 184 return $included; 185 } 186 187 function scorm_seq_sequencing ($scoid, $userid, $seq) { 188 189 switch ($seq->sequencing) { 190 case 'start': 191 // We'll see the parameters we have to send, this should update delivery and end. 192 $seq = scorm_seq_start_sequencing($scoid, $userid, $seq); 193 $seq->sequencing = true; 194 break; 195 196 case 'resumeall': 197 // We'll see the parameters we have to send, this should update delivery and end. 198 $seq = scorm_seq_resume_all_sequencing($scoid, $userid, $seq); 199 $seq->sequencing = true; 200 break; 201 202 case 'exit': 203 // We'll see the parameters we have to send, this should update delivery and end. 204 $seq = scorm_seq_exit_sequencing($scoid, $userid, $seq); 205 $seq->sequencing = true; 206 break; 207 208 case 'retry': 209 // We'll see the parameters we have to send, this should update delivery and end. 210 $seq = scorm_seq_retry_sequencing($scoid, $userid, $seq); 211 $seq->sequencing = true; 212 break; 213 214 case 'previous': 215 // We'll see the parameters we have to send, this should update delivery and end. 216 $seq = scorm_seq_previous_sequencing($scoid, $userid, $seq); 217 $seq->sequencing = true; 218 break; 219 220 case 'choice': 221 // We'll see the parameters we have to send, this should update delivery and end. 222 $seq = scorm_seq_choice_sequencing($scoid, $userid, $seq); 223 $seq->sequencing = true; 224 break; 225 } 226 227 if ($seq->exception != null) { 228 $seq->sequencing = false; 229 return $seq; 230 } 231 232 $seq->sequencing = true; 233 return $seq; 234 } 235 236 function scorm_seq_start_sequencing($scoid, $userid, $seq) { 237 global $DB; 238 239 if (!empty($seq->currentactivity)) { 240 $seq->delivery = null; 241 $seq->exception = 'SB.2.5-1'; 242 return $seq; 243 } 244 $sco = $DB->get_record('scorm_scoes', array('scoid' => $scoid, 'userid' => $userid)); 245 if (($sco->parent == '/') && scorm_is_leaf($sco)) { // If the activity is the root and is leaf. 246 $seq->delivery = $sco; 247 } else { 248 $ancestors = scorm_get_ancestors($sco); 249 $ancestorsroot = array_reverse($ancestors); 250 $res = scorm_seq_flow($ancestorsroot[0], 'forward', $seq, true, $userid); 251 if ($res) { 252 return $res; 253 } 254 } 255 } 256 257 function scorm_seq_resume_all_sequencing($scoid, $userid, $seq) { 258 global $DB; 259 260 if (!empty($seq->currentactivity)) { 261 $seq->delivery = null; 262 $seq->exception = 'SB.2.6-1'; 263 return $seq; 264 } 265 $track = $DB->get_record('scorm_scoes_track', array('scoid' => $scoid, 'userid' => $userid, 'element' => 'suspendedactivity')); 266 if (!$track) { 267 $seq->delivery = null; 268 $seq->exception = 'SB.2.6-2'; 269 return $seq; 270 } 271 // We assign the sco to the delivery. 272 $seq->delivery = $DB->get_record('scorm_scoes', array('scoid' => $scoid, 'userid' => $userid)); 273 } 274 275 function scorm_seq_continue_sequencing($scoid, $userid, $seq) { 276 if (empty($seq->currentactivity)) { 277 $seq->delivery = null; 278 $seq->exception = 'SB.2.7-1'; 279 return $seq; 280 } 281 $currentact = $seq->currentactivity; 282 if ($currentact->parent != '/') { 283 // If the activity is the root and is leaf. 284 $parent = scorm_get_parent ($currentact); 285 286 if (!isset($parent->flow) || ($parent->flow == false)) { 287 $seq->delivery = null; 288 $seq->exception = 'SB.2.7-2'; 289 return $seq; 290 } 291 292 $res = scorm_seq_flow($currentact, 'forward', $seq, false, $userid); 293 if ($res) { 294 return $res; 295 } 296 } 297 } 298 299 function scorm_seq_previous_sequencing($scoid, $userid, $seq) { 300 if (empty($seq->currentactivity)) { 301 $seq->delivery = null; 302 $seq->exception = 'SB.2.8-1'; 303 return $seq; 304 } 305 306 $currentact = $seq->currentactivity; 307 if ($currentact->parent != '/') { // If the activity is the root and is leaf. 308 $parent = scorm_get_parent ($currentact); 309 if (!isset($parent->flow) || ($parent->flow == false)) { 310 $seq->delivery = null; 311 $seq->exception = 'SB.2.8-2'; 312 return $seq; 313 } 314 315 $res = scorm_seq_flow($currentact, 'backward', $seq, false, $userid); 316 if ($res) { 317 return $res; 318 } 319 } 320 } 321 322 function scorm_seq_exit_sequencing($scoid, $userid, $seq) { 323 if (empty($seq->currentactivity)) { 324 $seq->delivery = null; 325 $seq->exception = 'SB.2.11-1'; 326 return $seq; 327 } 328 329 if ($seq->active) { 330 $seq->endsession = false; 331 $seq->exception = 'SB.2.11-2'; 332 return $seq; 333 } 334 $currentact = $seq->currentactivity; 335 if ($currentact->parent == '/') { 336 $seq->endsession = true; 337 return $seq; 338 } 339 340 $seq->endsession = false; 341 return $seq; 342 } 343 344 function scorm_seq_retry_sequencing($scoid, $userid, $seq) { 345 if (empty($seq->currentactivity)) { 346 $seq->delivery = null; 347 $seq->exception = 'SB.2.10-1'; 348 return $seq; 349 } 350 if ($seq->active || $seq->suspended) { 351 $seq->delivery = null; 352 $seq->exception = 'SB.2.10-2'; 353 return $seq; 354 } 355 356 if (!scorm_is_leaf($seq->currentactivity)) { 357 $res = scorm_seq_flow($seq->currentactivity, 'forward', $seq, true, $userid); 358 if ($res != null) { 359 return $res; 360 } else { 361 // Return deliver. 362 $seq->delivery = null; 363 $seq->exception = 'SB.2.10-3'; 364 return $seq; 365 } 366 } else { 367 $seq->delivery = $seq->currentactivity; 368 return $seq; 369 } 370 371 } 372 373 function scorm_seq_choice_sequencing($sco, $userid, $seq) { 374 375 $avchildren = Array (); 376 $comancestor = null; 377 $traverse = null; 378 379 if ($sco == null) { 380 $seq->delivery = null; 381 $seq->exception = 'SB.2.9-1'; 382 return $seq; 383 } 384 385 $ancestors = scorm_get_ancestors($sco); 386 $arrpath = array_reverse($ancestors); 387 array_push ($arrpath, $sco); // Path from the root to the target. 388 389 foreach ($arrpath as $activity) { 390 if ($activity->parent != '/') { 391 $avchildren = scorm_get_available_children (scorm_get_parent($activity)); 392 $position = array_search($avchildren, $activity); 393 if ($position !== false) { 394 $seq->delivery = null; 395 $seq->exception = 'SB.2.9-2'; 396 return $seq; 397 } 398 } 399 400 if (scorm_seq_rules_check($activity, 'hidefromchoice' != null)) { 401 $seq->delivery = null; 402 $seq->exception = 'SB.2.9-3'; 403 return $seq; 404 } 405 } 406 407 if ($sco->parent != '/') { 408 $parent = scorm_sco_get_parent ($sco); 409 if ( isset($parent->choice) && ($parent->choice == false)) { 410 $seq->delivery = null; 411 $seq->exception = 'SB.2.9-4'; 412 return $seq; 413 } 414 } 415 416 if ($seq->currentactivity != null) { 417 $commonpos = scorm_find_common_ancestor($ancestors, $seq->currentactivity); 418 $comancestor = $arrpath [$commonpos]; 419 } else { 420 $comancestor = $arrpath [0]; 421 } 422 423 if ($seq->currentactivity === $sco) { 424 // MDL-51757 - this part of the SCORM 2004 sequencing and navigation was not completed. 425 throw new \coding_exception('Unexpected state encountered'); 426 } 427 428 $sib = scorm_get_siblings($seq->currentactivity); 429 $pos = array_search($sib, $sco); 430 431 if ($pos !== false) { 432 $siblings = array_slice($sib, 0, $pos - 1); 433 if (empty($siblings)) { 434 $seq->delivery = null; 435 $seq->exception = 'SB.2.9-5'; 436 return $seq; 437 } 438 439 $children = scorm_get_children (scorm_get_parent ($sco)); 440 $pos1 = array_search($children, $sco); 441 $pos2 = array_search($seq->currentactivity, $sco); 442 if ($pos1 > $pos2) { 443 $traverse = 'forward'; 444 } else { 445 $traverse = 'backward'; 446 } 447 448 foreach ($siblings as $sibling) { 449 $seq = scorm_seq_choice_activity_traversal($sibling, $userid, $seq, $traverse); 450 if (!$seq->reachable) { 451 $seq->delivery = null; 452 return $seq; 453 } 454 } 455 // MDL-51757 - this part of the SCORM 2004 sequencing and navigation was not completed. 456 throw new \coding_exception('Unexpected state encountered'); 457 } 458 459 if ($seq->currentactivity == null || $seq->currentactivity == $comancestor) { 460 $commonpos = scorm_find_common_ancestor($ancestors, $seq->currentactivity); 461 // Path from the common ancestor to the target activity. 462 $comtarget = array_slice($ancestors, 1, $commonpos - 1); 463 $comtarget = array_reverse($comtarget); 464 465 if (empty($comtarget)) { 466 $seq->delivery = null; 467 $seq->exception = 'SB.2.9-5'; 468 return $seq; 469 } 470 foreach ($comtarget as $act) { 471 $seq = scorm_seq_choice_activity_traversal($act, $userid, $seq, 'forward'); 472 if (!$seq->reachable) { 473 $seq->delivery = null; 474 return $seq; 475 } 476 $act = scorm_get_sco ($acti->id); 477 if (scorm_seq_is('active', $act->id, $userid) && ($act->id != $comancestor->id && $act->preventactivation)) { 478 $seq->delivery = null; 479 $seq->exception = 'SB.2.9-6'; 480 return $seq; 481 } 482 } 483 // MDL-51757 - this part of the SCORM 2004 sequencing and navigation was not completed. 484 throw new \coding_exception('Unexpected state encountered'); 485 } 486 487 if ($comancestor->id == $sco->id) { 488 489 $ancestorscurrent = scorm_get_ancestors($seq->currentactivity); 490 $possco = array_search($ancestorscurrent, $sco); 491 // Path from the current activity to the target. 492 $curtarget = array_slice($ancestorscurrent, 0, $possco); 493 494 if (empty($curtarget)) { 495 $seq->delivery = null; 496 $seq->exception = 'SB.2.9-5'; 497 return $seq; 498 } 499 $i = 0; 500 foreach ($curtarget as $activ) { 501 $i++; 502 if ($i != count($curtarget)) { 503 if (isset($activ->choiceexit) && ($activ->choiceexit == false)) { 504 $seq->delivery = null; 505 $seq->exception = 'SB.2.9-7'; 506 return $seq; 507 } 508 } 509 } 510 // MDL-51757 - this part of the SCORM 2004 sequencing and navigation was not completed. 511 throw new \coding_exception('Unexpected state encountered'); 512 } 513 514 if (array_search($ancestors, $comancestor) !== false) { 515 $ancestorscurrent = scorm_get_ancestors($seq->currentactivity); 516 $commonpos = scorm_find_common_ancestor($ancestors, $sco); 517 $curcommon = array_slice($ancestorscurrent, 0, $commonpos - 1); 518 if (empty($curcommon)) { 519 $seq->delivery = null; 520 $seq->exception = 'SB.2.9-5'; 521 return $seq; 522 } 523 524 $constrained = null; 525 foreach ($curcommon as $acti) { 526 $acti = scorm_get_sco($acti->id); 527 if (isset($acti->choiceexit) && ($acti->choiceexit == false)) { 528 $seq->delivery = null; 529 $seq->exception = 'SB.2.9-7'; 530 return $seq; 531 } 532 if ($constrained == null) { 533 if ($acti->constrainchoice == true) { 534 $constrained = $acti; 535 } 536 } 537 } 538 if ($constrained != null) { 539 $fwdir = scorm_get_preorder($constrained); 540 541 if (array_search($fwdir, $sco) !== false) { 542 $traverse = 'forward'; 543 } else { 544 $traverse = 'backward'; 545 } 546 $seq = scorm_seq_choice_flow($constrained, $traverse, $seq); 547 $actconsider = $seq->identifiedactivity; 548 $avdescendents = Array(); 549 $avdescendents = scorm_get_available_descendents($actconsider); 550 if (array_search ($avdescendents, $sco) !== false && $sco->id != $actconsider->id && $constrained->id != $sco->id ) { 551 $seq->delivery = null; 552 $seq->exception = 'SB.2.9-8'; 553 return $seq; 554 } 555 // CONTINUE 11.5.5 ! 556 } 557 558 $commonpos = scorm_find_common_ancestor($ancestors, $seq->currentactivity); 559 $comtarget = array_slice($ancestors, 1, $commonpos - 1);// Path from the common ancestor to the target activity. 560 $comtarget = array_reverse($comtarget); 561 562 if (empty($comtarget)) { 563 $seq->delivery = null; 564 $seq->exception = 'SB.2.9-5'; 565 return $seq; 566 } 567 568 $fwdir = scorm_get_preorder($seq->currentactivity); 569 570 if (array_search($fwdir, $sco) !== false) { 571 foreach ($comtarget as $act) { 572 $seq = scorm_seq_choice_activity_traversal($act, $userid, $seq, 'forward'); 573 if (!$seq->reachable) { 574 $seq->delivery = null; 575 return $seq; 576 } 577 $act = scorm_get_sco($act->id); 578 if (scorm_seq_is('active', $act->id, $userid) && ($act->id != $comancestor->id && 579 ($act->preventactivation == true))) { 580 $seq->delivery = null; 581 $seq->exception = 'SB.2.9-6'; 582 return $seq; 583 } 584 } 585 586 } else { 587 foreach ($comtarget as $act) { 588 $act = scorm_get_sco($act->id); 589 if (scorm_seq_is('active', $act->id, $userid) && $act->id != $comancestor->id && $act->preventactivation == true) { 590 $seq->delivery = null; 591 $seq->exception = 'SB.2.9-6'; 592 return $seq; 593 } 594 } 595 } 596 // MDL-51757 - this part of the SCORM 2004 sequencing and navigation was not completed. 597 throw new \coding_exception('Unexpected state encountered'); 598 } 599 600 if (scorm_is_leaf ($sco)) { 601 $seq->delivery = $sco; 602 $seq->exception = 'SB.2.9-6'; 603 return $seq; 604 } 605 606 $seq = scorm_seq_flow($sco, 'forward', $seq, true, $userid); 607 if ($seq->deliverable == false) { 608 scorm_terminate_descendent_attempts($comancestor, $userid, $seq); 609 scorm_seq_end_attempt($comancestor, $userid, $seq->attempt); 610 $seq->currentactivity = $sco; 611 $seq->delivery = null; 612 $seq->exception = 'SB.2.9-9'; 613 return $seq; 614 } else { 615 return $seq; 616 } 617 618 } 619 620 function scorm_seq_choice_flow ($constrained, $traverse, $seq) { 621 $seq = scorm_seq_choice_flow_tree ($constrained, $traverse, $seq); 622 if ($seq->identifiedactivity == null) { 623 $seq->identifiedactivity = $constrained; 624 return $seq; 625 } else { 626 return $seq; 627 } 628 } 629 630 function scorm_seq_choice_flow_tree ($constrained, $traverse, $seq) { 631 $islast = false; 632 $parent = scorm_get_parent ($constrained); 633 if ($traverse == 'forward') { 634 $preord = scorm_get_preorder($constrained); 635 if (count($preorder) == 0 || (count($preorder) == 0 && $preorder[0]->id = $constrained->id)) { 636 // TODO: undefined. 637 $islast = true; // The function is the last activity available. 638 } 639 if ($constrained->parent == '/' || $islast) { 640 $seq->nextactivity = null; 641 return $seq; 642 } 643 $avchildren = scorm_get_available_children($parent); // Available children. 644 if ($avchildren[count($avchildren) - 1]->id == $constrained->id) { 645 $seq = scorm_seq_choice_flow_tree ($parent, 'forward', $seq); 646 return $seq; 647 } else { 648 $i = 0; 649 while ($i < count($avchildren)) { 650 if ($avchildren [$i]->id == $constrained->id) { 651 $seq->nextactivity = $avchildren [$i + 1]; 652 return $seq; 653 } else { 654 $i++; 655 } 656 } 657 } 658 } 659 660 if ($traverse == 'backward') { 661 if ($constrained->parent == '/' ) { 662 $seq->nextactivity = null; 663 return $seq; 664 } 665 666 $avchildren = scorm_get_available_children($parent); // Available children. 667 if ($avchildren [0]->id == $constrained->id) { 668 $seq = scorm_seq_choice_flow_tree ($parent, 'backward', $seq); 669 return $seq; 670 } else { 671 $i = count($avchildren) - 1; 672 while ($i >= 0) { 673 if ($avchildren [$i]->id == $constrained->id) { 674 $seq->nextactivity = $avchildren [$i - 1]; 675 return $seq; 676 } else { 677 $i--; 678 } 679 } 680 } 681 } 682 } 683 684 function scorm_seq_choice_activity_traversal($activity, $userid, $seq, $direction) { 685 if ($direction == 'forward') { 686 $act = scorm_seq_rules_check($activity, 'stopforwardtraversal'); 687 688 if ($act != null) { 689 $seq->reachable = false; 690 $seq->exception = 'SB.2.4-1'; 691 return $seq; 692 } 693 $seq->reachable = false; 694 return $seq; 695 } 696 697 if ($direction == 'backward') { 698 $parentsco = scorm_get_parent($activity); 699 if ($parentsco != null) { 700 if (isset($parentsco->forwardonly) && ($parentsco->forwardonly == true)) { 701 $seq->reachable = false; 702 $seq->exception = 'SB.2.4-2'; 703 return $seq; 704 } else { 705 $seq->reachable = false; 706 $seq->exception = 'SB.2.4-3'; 707 return $seq; 708 } 709 } 710 } 711 $seq->reachable = true; 712 return $seq; 713 } 714 715 // Delivery Request Process. 716 717 function scorm_sequencing_delivery($scoid, $userid, $seq) { 718 719 if (!scorm_is_leaf($seq->delivery)) { 720 $seq->deliveryvalid = false; 721 $seq->exception = 'DB.1.1-1'; 722 return $seq; 723 } 724 $ancestors = scorm_get_ancestors($seq->delivery); 725 $arrpath = array_reverse($ancestors); 726 array_push ($arrpath, $seq->delivery); // Path from the root to the target. 727 728 if (empty($arrpath)) { 729 $seq->deliveryvalid = false; 730 $seq->exception = 'DB.1.1-2'; 731 return $seq; 732 } 733 734 foreach ($arrpath as $activity) { 735 if (scorm_check_activity($activity, $userid)) { 736 $seq->deliveryvalid = false; 737 $seq->exception = 'DB.1.1-3'; 738 return $seq; 739 } 740 } 741 742 $seq->deliveryvalid = true; 743 return $seq; 744 745 } 746 747 function scorm_content_delivery_environment($seq, $userid) { 748 global $DB; 749 750 $act = $seq->currentactivity; 751 if (scorm_seq_is('active', $act->id, $userid)) { 752 $seq->exception = 'DB.2-1'; 753 return $seq; 754 } 755 $track = $DB->get_record('scorm_scoes_track', array('scoid' => $act->id, 756 'userid' => $userid, 757 'element' => 'suspendedactivity')); 758 if ($track != null) { 759 $seq = scorm_clear_suspended_activity($seq->delivery, $seq, $userid); 760 761 } 762 $seq = scorm_terminate_descendent_attempts ($seq->delivery, $userid, $seq); 763 $ancestors = scorm_get_ancestors($seq->delivery); 764 $arrpath = array_reverse($ancestors); 765 array_push ($arrpath, $seq->delivery); 766 foreach ($arrpath as $activity) { 767 if (!scorm_seq_is('active', $activity->id, $userid)) { 768 if (!isset($activity->tracked) || ($activity->tracked == 1)) { 769 if (!scorm_seq_is('suspended', $activity->id, $userid)) { 770 $r = $DB->get_record('scorm_scoes_track', array('scoid' => $activity->id, 771 'userid' => $userid, 772 'element' => 'activityattemptcount')); 773 $r->value = ($r->value) + 1; 774 $DB->update_record('scorm_scoes_track', $r); 775 if ($r->value == 1) { 776 scorm_seq_set('activityprogressstatus', $activity->id, $userid, 'true'); 777 } 778 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectiveprogressstatus', 'false'); 779 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectivesatisfiedstatus', 'false'); 780 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectivemeasurestatus', 'false'); 781 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectivenormalizedmeasure', 0.0); 782 783 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptprogressstatus', 'false'); 784 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptcompletionstatus', 'false'); 785 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptabsoluteduration', 0.0); 786 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptexperiencedduration', 0.0); 787 scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptcompletionamount', 0.0); 788 } 789 } 790 scorm_seq_set('active', $activity->id, $userid, 'true'); 791 } 792 } 793 $seq->delivery = $seq->currentactivity; 794 scorm_seq_set('suspendedactivity', $activity->id, $userid, 'false'); 795 796 // ONCE THE DELIVERY BEGINS (How should I check that?). 797 798 if (isset($activity->tracked) || ($activity->tracked == 0)) { 799 // How should I track the info and what should I do to not record the information for the activity during delivery? 800 $atabsdur = $DB->get_record('scorm_scoes_track', array('scoid' => $activity->id, 801 'userid' => $userid, 802 'element' => 'attemptabsoluteduration')); 803 $atexpdur = $DB->get_record('scorm_scoes_track', array('scoid' => $activity->id, 804 'userid' => $userid, 805 'element' => 'attemptexperiencedduration')); 806 } 807 return $seq; 808 } 809 810 function scorm_clear_suspended_activity($act, $seq, $userid) { 811 global $DB; 812 $currentact = $seq->currentactivity; 813 $track = $DB->get_record('scorm_scoes_track', array('scoid' => $currentact->id, 814 'userid' => $userid, 815 'element' => 'suspendedactivity')); 816 if ($track != null) { 817 $ancestors = scorm_get_ancestors($act); 818 $commonpos = scorm_find_common_ancestor($ancestors, $currentact); 819 if ($commonpos !== false) { 820 if ($activitypath = array_slice($ancestors, 0, $commonpos)) { 821 if (!empty($activitypath)) { 822 823 foreach ($activitypath as $activity) { 824 if (scorm_is_leaf($activity)) { 825 scorm_seq_set('suspended', $activity->id, $userid, false); 826 } else { 827 $children = scorm_get_children($activity); 828 $bool = false; 829 foreach ($children as $child) { 830 if (scorm_seq_is('suspended', $child->id, $userid)) { 831 $bool = true; 832 } 833 } 834 if (!$bool) { 835 scorm_seq_set('suspended', $activity->id, $userid, false); 836 } 837 } 838 } 839 } 840 } 841 } 842 scorm_seq_set('suspendedactivity', $act->id, $userid, false); 843 } 844 } 845 846 function scorm_select_children_process($scoid, $userid) { 847 global $DB; 848 849 $sco = scorm_get_sco($scoid); 850 if (!scorm_is_leaf($sco)) { 851 if (!scorm_seq_is('suspended', $scoid, $userid) && !scorm_seq_is('active', $scoid, $userid)) { 852 $r = $DB->get_record('scorm_scoes_track', array('scoid' => $scoid, 853 'userid' => $userid, 854 'element' => 'selectiontiming')); 855 856 switch ($r->value) { 857 case 'oneachnewattempt': 858 case 'never': 859 break; 860 861 case 'once': 862 if (!scorm_seq_is('activityprogressstatus', $scoid, $userid)) { 863 if (scorm_seq_is('selectioncountsstatus', $scoid, $userid)) { 864 $childlist = ''; 865 $res = $DB->get_record('scorm_scoes_track', array('scoid' => $scoid, 866 'userid' => $userid, 867 'element' => 'selectioncount')); 868 $i = ($res->value) - 1; 869 $children = scorm_get_children($sco); 870 871 while ($i >= 0) { 872 $pos = array_rand($children); 873 array_push($childlist, $children[$pos]); 874 array_splice($children, $pos, 1); 875 $i--; 876 } 877 sort($childlist); 878 $clist = serialize($childlist); 879 scorm_seq_set('availablechildren', $scoid, $userid, false); 880 scorm_seq_set('availablechildren', $scoid, $userid, $clist); 881 } 882 } 883 break; 884 } 885 } 886 } 887 } 888 889 function scorm_randomize_children_process($scoid, $userid) { 890 global $DB; 891 892 $sco = scorm_get_sco($scoid); 893 if (!scorm_is_leaf($sco)) { 894 if (!scorm_seq_is('suspended', $scoid, $userid) && !scorm_seq_is('active', $scoid, $userid)) { 895 $r = $DB->get_record('scorm_scoes_track', array('scoid' => $scoid, 896 'userid' => $userid, 897 'element' => 'randomizationtiming')); 898 899 switch ($r->value) { 900 case 'never': 901 break; 902 903 case 'oneachnewattempt': 904 case 'once': 905 if (!scorm_seq_is('activityprogressstatus', $scoid, $userid)) { 906 if (scorm_seq_is('randomizechildren', $scoid, $userid)) { 907 $childlist = array(); 908 $res = scorm_get_available_children($sco); 909 $i = count($res) - 1; 910 $children = $res->value; 911 912 while ($i >= 0) { 913 $pos = array_rand($children); 914 array_push($childlist, $children[$pos]); 915 array_splice($children, $pos, 1); 916 $i--; 917 } 918 919 $clist = serialize ($childlist); 920 scorm_seq_set('availablechildren', $scoid, $userid, false); 921 scorm_seq_set('availablechildren', $scoid, $userid, $clist); 922 } 923 } 924 break; 925 } 926 } 927 } 928 } 929 930 function scorm_terminate_descendent_attempts($activity, $userid, $seq) { 931 $ancestors = scorm_get_ancestors($seq->currentactivity); 932 $commonpos = scorm_find_common_ancestor($ancestors, $activity); 933 if ($commonpos !== false) { 934 if ($activitypath = array_slice($ancestors, 1, $commonpos - 2)) { 935 if (!empty($activitypath)) { 936 foreach ($activitypath as $sco) { 937 scorm_seq_end_attempt($sco, $userid, $seq->attempt); 938 } 939 } 940 } 941 } 942 } 943 944 function scorm_sequencing_exception($seq) { 945 global $OUTPUT; 946 if ($seq->exception != null) { 947 switch ($seq->exception) { 948 case 'NB.2.1-1': 949 echo $OUTPUT->notification("Sequencing session has already begun"); 950 break; 951 case 'NB.2.1-2': 952 echo $OUTPUT->notification("Sequencing session has not begun"); 953 break; 954 case 'NB.2.1-3': 955 echo $OUTPUT->notification("Suspended activity is not defined"); 956 break; 957 case 'NB.2.1-4': 958 echo $OUTPUT->notification("Flow Sequencing Control Model Violation"); 959 break; 960 case 'NB.2.1-5': 961 echo $OUTPUT->notification("Flow or Forward only Sequencing Control Model Violation"); 962 break; 963 case 'NB.2.1-6': 964 echo $OUTPUT->notification("No activity is previous to the root"); 965 break; 966 case 'NB.2.1-7': 967 echo $OUTPUT->notification("Unsupported Navigation Request"); 968 break; 969 case 'NB.2.1-8': 970 echo $OUTPUT->notification("Choice Exit Sequencing Control Model Violation"); 971 break; 972 case 'NB.2.1-9': 973 echo $OUTPUT->notification("No activities to consider"); 974 break; 975 case 'NB.2.1-10': 976 echo $OUTPUT->notification("Choice Sequencing Control Model Violation"); 977 break; 978 case 'NB.2.1-11': 979 echo $OUTPUT->notification("Target Activity does not exist"); 980 break; 981 case 'NB.2.1-12': 982 echo $OUTPUT->notification("Current Activity already terminated"); 983 break; 984 case 'NB.2.1-13': 985 echo $OUTPUT->notification("Undefined Navigation Request"); 986 break; 987 988 case 'TB.2.3-1': 989 echo $OUTPUT->notification("Current Activity already terminated"); 990 break; 991 case 'TB.2.3-2': 992 echo $OUTPUT->notification("Current Activity already terminated"); 993 break; 994 case 'TB.2.3-4': 995 echo $OUTPUT->notification("Current Activity already terminated"); 996 break; 997 case 'TB.2.3-5': 998 echo $OUTPUT->notification("Nothing to suspend; No active activities"); 999 break; 1000 case 'TB.2.3-6': 1001 echo $OUTPUT->notification("Nothing to abandon; No active activities"); 1002 break; 1003 1004 case 'SB.2.1-1': 1005 echo $OUTPUT->notification("Last activity in the tree"); 1006 break; 1007 case 'SB.2.1-2': 1008 echo $OUTPUT->notification("Cluster has no available children"); 1009 break; 1010 case 'SB.2.1-3': 1011 echo $OUTPUT->notification("No activity is previous to the root"); 1012 break; 1013 case 'SB.2.1-4': 1014 echo $OUTPUT->notification("Forward Only Sequencing Control Model Violation"); 1015 break; 1016 1017 case 'SB.2.2-1': 1018 echo $OUTPUT->notification("Flow Sequencing Control Model Violation"); 1019 break; 1020 case 'SB.2.2-2': 1021 echo $OUTPUT->notification("Activity unavailable"); 1022 break; 1023 1024 case 'SB.2.3-1': 1025 echo $OUTPUT->notification("Forward Traversal Blocked"); 1026 break; 1027 case 'SB.2.3-2': 1028 echo $OUTPUT->notification("Forward Only Sequencing Control Model Violation"); 1029 break; 1030 case 'SB.2.3-3': 1031 echo $OUTPUT->notification("No activity is previous to the root"); 1032 break; 1033 1034 case 'SB.2.5-1': 1035 echo $OUTPUT->notification("Sequencing session has already begun"); 1036 break; 1037 1038 case 'SB.2.6-1': 1039 echo $OUTPUT->notification("Sequencing session has already begun"); 1040 break; 1041 case 'SB.2.6-2': 1042 echo $OUTPUT->notification("No Suspended activity is defined"); 1043 break; 1044 1045 case 'SB.2.7-1': 1046 echo $OUTPUT->notification("Sequencing session has not begun"); 1047 break; 1048 case 'SB.2.7-2': 1049 echo $OUTPUT->notification("Flow Sequencing Control Model Violation"); 1050 break; 1051 1052 case 'SB.2.8-1': 1053 echo $OUTPUT->notification("Sequencing session has not begun"); 1054 break; 1055 case 'SB.2.8-2': 1056 echo $OUTPUT->notification("Flow Sequencing Control Model Violation"); 1057 break; 1058 1059 case 'SB.2.9-1': 1060 echo $OUTPUT->notification("No target for Choice"); 1061 break; 1062 case 'SB.2.9-2': 1063 echo $OUTPUT->notification("Target Activity does not exist or is unavailable"); 1064 break; 1065 case 'SB.2.9-3': 1066 echo $OUTPUT->notification("Target Activity hidden from choice"); 1067 break; 1068 case 'SB.2.9-4': 1069 echo $OUTPUT->notification("Choice Sequencing Control Model Violation"); 1070 break; 1071 case 'SB.2.9-5': 1072 echo $OUTPUT->notification("No activities to consider"); 1073 break; 1074 case 'SB.2.9-6': 1075 echo $OUTPUT->notification("Unable to activate target; target is not a child of the Current Activity"); 1076 break; 1077 case 'SB.2.9-7': 1078 echo $OUTPUT->notification("Choice Exit Sequencing Control Model Violation"); 1079 break; 1080 case 'SB.2.9-8': 1081 echo $OUTPUT->notification("Unable to choose target activity - constrained choice"); 1082 break; 1083 case 'SB.2.9-9': 1084 echo $OUTPUT->notification("Choice Request Prevented by Flow-only Activity"); 1085 break; 1086 1087 case 'SB.2.10-1': 1088 echo $OUTPUT->notification("Sequencing session has not begun"); 1089 break; 1090 case 'SB.2.10-2': 1091 echo $OUTPUT->notification("Current Activity is active or suspended"); 1092 break; 1093 case 'SB.2.10-3': 1094 echo $OUTPUT->notification("Flow Sequencing Control Model Violation"); 1095 break; 1096 1097 case 'SB.2.11-1': 1098 echo $OUTPUT->notification("Sequencing session has not begun"); 1099 break; 1100 case 'SB.2.11-2': 1101 echo $OUTPUT->notification("Current Activity has not been terminated"); 1102 break; 1103 1104 case 'SB.2.12-2': 1105 echo $OUTPUT->notification("Undefined Sequencing Request"); 1106 break; 1107 1108 case 'DB.1.1-1': 1109 echo $OUTPUT->notification("Cannot deliver a non-leaf activity"); 1110 break; 1111 case 'DB.1.1-2': 1112 echo $OUTPUT->notification("Nothing to deliver"); 1113 break; 1114 case 'DB.1.1-3': 1115 echo $OUTPUT->notification("Activity unavailable"); 1116 break; 1117 1118 case 'DB.2-1': 1119 echo $OUTPUT->notification("Identified activity is already active"); 1120 break; 1121 1122 } 1123 1124 } 1125 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body