No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

NavigationRequest.php 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. <?php
  2. namespace Logipro\Bundle\SCORMBundle\LearningModels\SCORM2004\SequencingNavigation;
  3. use Logipro\Bundle\SCORMBundle\Entity\Scorm2004\Scorm2004MapTrackItem;
  4. use Logipro\Bundle\SCORMBundle\LearningModels\SCORM2004\SequencingNavigation\SeqNavRequest;
  5. use Logipro\Bundle\SCORMBundle\LearningModels\SCORM2004\SequencingNavigation\SequencingRequest;
  6. use Logipro\Bundle\SCORMBundle\LearningModels\SCORM2004\SequencingNavigation\TerminationRequest;
  7. use Symfony\Component\DependencyInjection\ContainerInterface;
  8. class NavigationRequest extends SeqNavRequest
  9. {
  10. // Requete de Navigation
  11. const NAVIGATION_START = 'NAVIGATION_START';
  12. const NAVIGATION_RESUME_ALL = 'NAVIGATION_RESUME_ALL';
  13. const NAVIGATION_CONTINUE = 'NAVIGATION_CONTINUE';
  14. const NAVIGATION_PREVIOUS = 'NAVIGATION_PREVIOUS';
  15. const NAVIGATION_FORWARD = 'NAVIGATION_FORWARD';
  16. const NAVIGATION_BACKWARD = 'NAVIGATION_BACKWARD';
  17. const NAVIGATION_CHOICE = 'NAVIGATION_CHOICE';
  18. const NAVIGATION_JUMP = 'NAVIGATION_JUMP';
  19. const NAVIGATION_EXIT = 'NAVIGATION_EXIT';
  20. const NAVIGATION_EXIT_ALL = 'NAVIGATION_EXIT_ALL';
  21. const NAVIGATION_SUSPEND_ALL = 'NAVIGATION_SUSPEND_ALL';
  22. const NAVIGATION_ABANDON = 'NAVIGATION_ABANDON';
  23. const NAVIGATION_ABANDON_ALL = 'NAVIGATION_ABANDON_ALL';
  24. /**
  25. * Type de la requete de terminaison résultante
  26. *
  27. * @var string
  28. */
  29. protected $terminationRequest;
  30. /**
  31. * Type de la requete de sequencage résultante
  32. *
  33. * @var string
  34. */
  35. protected $sequencingRequest;
  36. /**
  37. * Constructeur
  38. *
  39. * @param ContainerInterface $container
  40. * @param string $navigationRequest
  41. * @param string $registrationKey
  42. * @param string $targetItemId
  43. */
  44. public function __construct(ContainerInterface $container, string $navigationRequest, string $registrationKey, ?string $targetItemId = '')
  45. {
  46. parent::__construct($container, $navigationRequest, $registrationKey, $targetItemId);
  47. // Initialisation des variables de l'instance
  48. $this->terminationRequest = null;
  49. $this->sequencingRequest = null;
  50. // On applique le processus relatif à la requete passée en argument
  51. switch ($this->request) {
  52. case self::NAVIGATION_START:
  53. $this->processStart();
  54. break;
  55. case self::NAVIGATION_RESUME_ALL:
  56. $this->processResumeAll();
  57. break;
  58. case self::NAVIGATION_CONTINUE:
  59. $this->processContinue();
  60. break;
  61. case self::NAVIGATION_PREVIOUS:
  62. $this->processPrevious();
  63. break;
  64. case self::NAVIGATION_FORWARD:
  65. case self::NAVIGATION_BACKWARD:
  66. $this->processDepracated();
  67. break;
  68. case self::NAVIGATION_CHOICE:
  69. $this->processChoice();
  70. break;
  71. case self::NAVIGATION_JUMP:
  72. $this->processJump();
  73. break;
  74. case self::NAVIGATION_EXIT:
  75. case self::NAVIGATION_ABANDON:
  76. $this->processQuit();
  77. break;
  78. case self::NAVIGATION_EXIT_ALL:
  79. case self::NAVIGATION_ABANDON_ALL:
  80. case self::NAVIGATION_SUSPEND_ALL:
  81. $this->processQuitAll();
  82. break;
  83. default:
  84. //@TODO mettre en place les var de langue
  85. $this->exception = '_AGO_SCORM_EXCEPTION_NB_2_1_13';
  86. return;
  87. }
  88. }
  89. /**
  90. * Traite la requete concernant l'événement de navigation 'Start'
  91. *
  92. * Ref ADL: Navigation Request Process [NB.2.1]
  93. */
  94. protected function processStart(): void
  95. {
  96. // Vérifier que la session d'activité n'aie pas déjà été initiée (cad qu'il n'existe pas un plannode courant)
  97. if (!$this->currentItem) {
  98. $this->validationState = true;
  99. $this->sequencingRequest = SequencingRequest::SEQUENCING_START;
  100. } else {
  101. //@TODO mettre en place les var de langue
  102. $this->exception = '_AGO_SCORM_EXCEPTION_NB_2_1_1';
  103. }
  104. }
  105. /**
  106. * Traite la requete concernant l'événement de navigation 'Resume All'
  107. *
  108. * Ref ADL: Navigation Request Process [NB.2.1]
  109. */
  110. protected function processResumeAll(): void
  111. {
  112. // Vérifier que la session d'activité n'aie pas déjà été initiée (cad qu'il n'existe pas un plannode courant)
  113. if (!$this->currentItem) {
  114. // Vérifier que la précédente session aie bien été arrétée
  115. // par une instruction 'suspend all'
  116. if ($this->suspendedItem) {
  117. $this->validationState = true;
  118. $this->sequencingRequest = SequencingRequest::SEQUENCING_RESUME_ALL;
  119. } else {
  120. //@TODO mettre en place les var de langue
  121. $this->exception = '_AGO_SCORM_EXCEPTION_NB_2_1_3';
  122. }
  123. } else {
  124. //@TODO mettre en place les var de langue
  125. $this->exception = '_AGO_SCORM_EXCEPTION_NB_2_1_1';
  126. }
  127. }
  128. /**
  129. * Traite la requete concernant l'événement de navigation 'Continue'
  130. *
  131. * Ref ADL: Navigation Request Process [NB.2.1]
  132. */
  133. protected function processContinue(): void
  134. {
  135. $em = $this->getDoctrine()->getManager();
  136. // Vérifier que la session d'activité aie bien été initiée (cad qu'il existe un plannode courant)
  137. if (!$this->currentItem) {
  138. //@TODO mettre en place les var de langue
  139. $this->exception = '_AGO_SCORM_EXCEPTION_NB_2_1_2';
  140. return;
  141. }
  142. // Vérifier que l'on ne soit pas à la racine de l'arbre
  143. // et que la valeur du controle de sequencage pour le paramètre 'flow' nous autorise à passer au noeud suivant
  144. $currentParent = $this->domScorm2004->getParent($this->currentItem);
  145. // Si le plannode a un parent, ce n'est pas la racine
  146. if ($currentParent) {
  147. if ($this->getSequencingControl($currentParent, 'flow')) {
  148. $this->validationState = true;
  149. $this->sequencingRequest = SequencingRequest::SEQUENCING_CONTINUE;
  150. // Terminer l'activité en cours si ce n'est pas déjà fait
  151. $scorm2004MapTrackItemRepository = $em->getRepository(Scorm2004MapTrackItem::class);
  152. $mapTrackItem = $scorm2004MapTrackItemRepository->findOneBy(array('item_identifier' => $this->currentItem, 'scorm2004Track' => $this->scorm2004Track));
  153. if ($mapTrackItem->getIsActive()) {
  154. $this->terminationRequest = TerminationRequest::TERMINATION_EXIT;
  155. }
  156. return;
  157. }
  158. }
  159. //@TODO mettre en place les var de langue
  160. $this->exception = '_AGO_SCORM_EXCEPTION_NB_2_1_4';
  161. }
  162. /**
  163. * Traite la requete concernant l'événement de navigation 'Previous'
  164. *
  165. * Ref ADL: Navigation Request Process [NB.2.1]
  166. */
  167. protected function processPrevious(): void
  168. {
  169. $em = $this->getDoctrine()->getManager();
  170. // Vérifier que la session de planNode aie bien été initiée (cad qu'il existe un plannode courant)
  171. if (!$this->currentItem) {
  172. //@TODO mettre en place les var de langue
  173. $this->exception = '_AGO_SCORM_EXCEPTION_NB_2_1_2';
  174. return;
  175. }
  176. // Vérifier que l'on ne soit pas à la racine de l'arbre
  177. $currentParent = $this->domScorm2004->getParent($this->currentItem);
  178. // Si le plannode a un parent, ce n'est pas la racine
  179. if ($currentParent) {
  180. // Vérifier que la valeur du controle de sequencage pour les paramètre 'flow' et ' forward only'
  181. // nous autorise à passer à un autre planNode
  182. if ($this->getSequencingControl($currentParent, 'flow') && !$this->getSequencingControl($currentParent, 'forwardOnly')) {
  183. $this->validationState = true;
  184. $this->sequencingRequest = SequencingRequest::SEQUENCING_PREVIOUS;
  185. // Terminer l'activité en cours si ce n'est pas déjà fait
  186. $scorm2004MapTrackItemRepository = $em->getRepository(Scorm2004MapTrackItem::class);
  187. $mapTrackItem = $scorm2004MapTrackItemRepository->findOneBy(array('item_identifier' => $this->currentItem, 'scorm2004Track' => $this->scorm2004Track));
  188. if ($mapTrackItem->getIsActive()) {
  189. $this->terminationRequest = TerminationRequest::TERMINATION_EXIT;
  190. }
  191. } else {
  192. // le mode de controle flow n'est pas respecté
  193. //@TODO mettre en place les var de langue
  194. $this->exception = '_AGO_SCORM_EXCEPTION_NB_2_1_5';
  195. }
  196. } else {
  197. // la racine ne possède pas de plannode précédent
  198. //@TODO mettre en place les var de langue
  199. $this->exception = '_AGO_SCORM_EXCEPTION_NB_2_1_6';
  200. }
  201. }
  202. /**
  203. * Traite les requetes concernant les événements de navigation 'forward' et 'backward'
  204. *
  205. * Ref ADL: Navigation Request Process [NB.2.1]
  206. */
  207. protected function processDepracated(): void
  208. {
  209. // les requetes 'forward' et 'backward' ne sont pas supportées par SCORM 2004
  210. //@TODO mettre en place les var de langue
  211. $this->exception = '_AGO_SCORM_EXCEPTION_NB_2_1_7';
  212. return;
  213. }
  214. /**
  215. * Traite la requete concernant l'événement de navigation 'choice'
  216. *
  217. * Ref ADL: Navigation Request Process [NB.2.1]
  218. */
  219. protected function processChoice(): void
  220. {
  221. $em = $this->getDoctrine()->getManager();
  222. $scorm2004MapTrackItemRepository = $em->getRepository(Scorm2004MapTrackItem::class);
  223. // Vérifier l'existence du noeud cible
  224. if ($this->targetItem) {
  225. // Vérifier que la requete de sequencage 'choice' soit auorisée pour le cluster du noeud cible
  226. $targetParent = $this->domScorm2004->getParent($this->targetItem);
  227. // Si le plannode est la racine (n'a pas de parent) ou est autorisé à utilisé une requete de choix
  228. if (!$targetParent || $this->getSequencingControl($targetParent, 'choice')) {
  229. // On débute la session par un sequencage 'choice'
  230. if (!$this->currentItem) {
  231. $this->validationState = true;
  232. $this->sequencingRequest = SequencingRequest::SEQUENCING_CHOICE;
  233. return;
  234. }
  235. // Vérifier que les planNode courant et ciblé ne sont pas enfants du même parent
  236. $currentParent = $this->domScorm2004->getParent($this->currentItem);
  237. if ($targetParent != $currentParent) {
  238. // On définit le chemin partant du noeud courant inclus jusqu'au noeud parent commun
  239. // Ce noeud commun ne sera pas terminé sauf si il est le noeud courant
  240. $commonPlanNode = $this->domScorm2004->findCommonAncestor($this->currentItem, $this->targetItem);
  241. if ($commonPlanNode == $this->currentItem) {
  242. $planNodePath = $this->domScorm2004->getDirectPath($this->currentItem, $commonPlanNode, true, true);
  243. } else {
  244. $planNodePath = $this->domScorm2004->getDirectPath($this->currentItem, $commonPlanNode, true, false);
  245. }
  246. if (!empty($planNodePath)) {
  247. foreach ($planNodePath as $planNode) {
  248. // Vérifier que l'action 'choice' ne terminera pas un noeud
  249. // qui n'est pas autorisé à être terminé par 'choice'
  250. $mapTrackItem = $scorm2004MapTrackItemRepository->findOneBy(array('item_identifier' => $planNode, 'scorm2004Track' => $this->scorm2004Track));
  251. if ($mapTrackItem->getIsActive()) {
  252. if (!$this->getSequencingControl($planNode, 'choiceExit')) {
  253. $this->exception = '_AGO_SCORM_EXCEPTION_NB_2_1_8';
  254. $this->targetItem = null;
  255. return;
  256. }
  257. }
  258. }
  259. } else {
  260. $this->exception = '_AGO_SCORM_EXCEPTION_NB_2_1_9';
  261. $this->targetItem = null;
  262. return;
  263. }
  264. }
  265. // Les planNodes courant et ciblé sont issus du même parent
  266. $mapTrackCurrentItem = $scorm2004MapTrackItemRepository->findOneBy(array('item_identifier' => $this->currentItem, 'scorm2004Track' => $this->scorm2004Track));
  267. if ($mapTrackCurrentItem->getIsActive()) {
  268. // Vérifier que le noeud courant soit autorisé à être terminé par une requete 'choice'
  269. if (!$this->getSequencingControl($this->currentItem, 'choiceExit')) {
  270. $this->exception = '_AGO_SCORM_EXCEPTION_NB_2_1_8';
  271. $this->targetItem = null;
  272. return;
  273. } else {
  274. $this->validationState = true;
  275. $this->terminationRequest = TerminationRequest::TERMINATION_EXIT;
  276. $this->sequencingRequest = SequencingRequest::SEQUENCING_CHOICE;
  277. }
  278. } else {
  279. $this->validationState = true;
  280. $this->sequencingRequest = SequencingRequest::SEQUENCING_CHOICE;
  281. }
  282. } else {
  283. $this->exception = '_AGO_SCORM_EXCEPTION_NB_2_1_10';
  284. $this->targetItem = null;
  285. return;
  286. }
  287. } else {
  288. // l'activité ciblée n'existe pas
  289. $this->exception = '_AGO_SCORM_EXCEPTION_NB_2_1_11';
  290. $this->targetItem = null;
  291. return;
  292. }
  293. }
  294. /**
  295. * Traite la requete concernant l'événement de navigation 'jump'
  296. *
  297. * Ref ADL: Navigation Request Process [NB.2.1]
  298. */
  299. protected function processJump(): void
  300. {
  301. if ($this->targetItem) {
  302. // On récupère les plannodes disponibles à partir du parent de la cible
  303. $targetParent = $this->domScorm2004->getParent($this->targetItem);
  304. $availableSiblings = $this->getAvailableChildren($targetParent);
  305. // Vérifier que le noeud ciblé soit bien dans ses noeuds disponibles
  306. if (array_search($this->targetItem, $availableSiblings) !== false) {
  307. $this->validationState = true;
  308. $this->terminationRequest = TerminationRequest::TERMINATION_EXIT;
  309. $this->sequencingRequest = SequencingRequest::SEQUENCING_JUMP;
  310. return;
  311. }
  312. }
  313. $this->exception = '_AGO_SCORM_EXCEPTION_NB_2_1_11';
  314. $this->targetItem = null;
  315. }
  316. /**
  317. * Traite la requete concernant l'événement de navigation 'exit' ou 'abandon'
  318. *
  319. * Ref ADL: Navigation Request Process [NB.2.1]
  320. */
  321. protected function processQuit(): void
  322. {
  323. $em = $this->getDoctrine()->getManager();
  324. $scorm2004MapTrackItemRepository = $em->getRepository(Scorm2004MapTrackItem::class);
  325. // Vérifier que la session aie bien été initiée
  326. if ($this->currentItem) {
  327. // Vérifier que le noeud courant est actif pour pouvoir le quitter
  328. $mapTrackCurrentItem = $scorm2004MapTrackItemRepository->findOneBy(array('item_identifier' => $this->currentItem, 'scorm2004Track' => $this->scorm2004Track));
  329. if ($mapTrackCurrentItem->getIsActive()) {
  330. $this->validationState = true;
  331. // La terminaison dépend de la nature de la requete définie ici par request
  332. $this->terminationRequest = $this->request == self::NAVIGATION_EXIT ? TerminationRequest::TERMINATION_EXIT : TerminationRequest::TERMINATION_ABANDON;
  333. $this->sequencingRequest = SequencingRequest::SEQUENCING_EXIT;
  334. return;
  335. } else {
  336. $this->exception = '_AGO_SCORM_EXCEPTION_NB_2_1_12';
  337. return;
  338. }
  339. } else {
  340. $this->exception = '_AGO_SCORM_EXCEPTION_NB_2_1_2';
  341. return;
  342. }
  343. }
  344. /**
  345. * Traite la requete concernant l'événement de navigation 'exit all' ou 'abandon all' ou 'suspend all'
  346. *
  347. * Ref ADL: Navigation Request Process [NB.2.1]
  348. */
  349. protected function processQuitAll(): void
  350. {
  351. // Vérifier que la session aie bien été initiée
  352. if ($this->currentItem) {
  353. $this->validationState = true;
  354. // La terminaison dépend de la nature de la requete définie ici par request
  355. switch ($this->request) {
  356. case self::NAVIGATION_EXIT_ALL:
  357. $this->terminationRequest = TerminationRequest::TERMINATION_EXIT_ALL;
  358. break;
  359. case self::NAVIGATION_ABANDON_ALL:
  360. $this->terminationRequest = TerminationRequest::TERMINATION_ABANDON_ALL;
  361. break;
  362. case self::NAVIGATION_SUSPEND_ALL:
  363. $this->terminationRequest = TerminationRequest::TERMINATION_SUSPEND_ALL;
  364. break;
  365. }
  366. $this->sequencingRequest = SequencingRequest::SEQUENCING_EXIT;
  367. } else {
  368. $this->exception = '_AGO_SCORM_EXCEPTION_NB_2_1_2';
  369. return;
  370. }
  371. }
  372. // GETTERS
  373. /**
  374. * Retourne le type de la requete de terminaison résultante
  375. *
  376. * @return string
  377. */
  378. public function getTerminationRequest(): ?string
  379. {
  380. return $this->terminationRequest;
  381. }
  382. /**
  383. * Retourne le type de la requete de sequencage résultante
  384. *
  385. * @return string
  386. */
  387. public function getSequencingRequest(): ?string
  388. {
  389. return $this->sequencingRequest;
  390. }
  391. /**
  392. * Retourne l'activité ciblée par la requete
  393. *
  394. * @return string
  395. */
  396. public function getTargetPlanNode(): ?string
  397. {
  398. return $this->targetItem;
  399. }
  400. }