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.

ScormEngine.php 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929
  1. <?php
  2. namespace Logipro\Bundle\SCORMBundle\Services;
  3. use Doctrine\Common\Persistence\ManagerRegistry;
  4. use Doctrine\ORM\EntityManagerInterface;
  5. use Logipro\Bundle\SCORMBundle\Entity\Course;
  6. use Logipro\Bundle\SCORMBundle\Entity\Learner;
  7. use Logipro\Bundle\SCORMBundle\Entity\MapCourseZipfile;
  8. use Logipro\Bundle\SCORMBundle\Entity\Registration;
  9. use Logipro\Bundle\SCORMBundle\Entity\RegistrationAttempt;
  10. use Logipro\Bundle\SCORMBundle\Entity\ZipFile;
  11. use Logipro\Bundle\SCORMBundle\LearningModels\DOMSCORM12;
  12. use Logipro\Bundle\SCORMBundle\LearningModels\DOMSCORM2004;
  13. use Logipro\Bundle\SCORMBundle\Package\Common\PackageTypeDetector;
  14. use Logipro\Bundle\SCORMBundle\Player\SCORM2004\Scorm2004PlayerLogic;
  15. use Logipro\Bundle\SCORMBundle\Package\PackageValidator;
  16. use Symfony\Component\DependencyInjection\ContainerInterface;
  17. use Symfony\Component\DependencyInjection\ContainerAwareTrait;
  18. use Symfony\Component\DependencyInjection\Reference;
  19. use Symfony\Component\DependencyInjection\ContainerAwareInterface;
  20. use Symfony\Component\HttpFoundation\Cookie;
  21. use Symfony\Component\HttpFoundation\Request;
  22. use Symfony\Component\HttpFoundation\Response;
  23. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  24. /**
  25. * Service de communication du moteur
  26. */
  27. class ScormEngine implements ContainerAwareInterface
  28. {
  29. use ContainerAwareTrait;
  30. protected $packageFolder;
  31. protected $contentFolder;
  32. protected $contentUrlPrefix;
  33. /**
  34. * la variable de session passé automatiquement par le kernel
  35. * du fait de sa déclaration ET de sa présence dans la déclaration de service
  36. * (ici services.xml) Presence de la ligne <argument type="service" id="session"/>
  37. *
  38. * @var SessionInterface
  39. */
  40. protected $session;
  41. /**
  42. * la response est créée ou modifiée pour inserer un cookie dans le header
  43. * lors de la lecture du paquet (ce cookie est uniquement utilisé dans un mecanisme de
  44. * blocage de sécurité)
  45. *
  46. * @var Response
  47. */
  48. private $response;
  49. public function __construct(string $packageFolder, string $contentFolder, string $contentUrlPrefix, SessionInterface $session)
  50. {
  51. $this->packageFolder = $packageFolder;
  52. $this->contentFolder = $contentFolder;
  53. $this->contentUrlPrefix = $contentUrlPrefix;
  54. $this->session = $session;
  55. }
  56. // COURS
  57. /**
  58. * Crée un cours à partir d'un package identifié par un chemin
  59. *
  60. * @param string $courseKey
  61. * @param string $zipPath
  62. * @param bool $analyse
  63. * @param string $versioningRule
  64. *
  65. * @return array
  66. */
  67. public function createCourse(string $courseKey, string $zipPath, bool $analyse = false, string $versioningRule = Course::VERSIONING_RULE_DEFAULT)
  68. {
  69. // Création de la structure de la réponse
  70. $response = array(
  71. 'code' => 200,
  72. 'isSuccessfullyCreated' => false,
  73. 'error' => '',
  74. 'parserErrors' => array(),
  75. 'course' => array(
  76. 'courseKey' => '',
  77. 'maxVersion' => 0,
  78. 'versioningRule' => $versioningRule
  79. ),
  80. 'metadata' => array(
  81. 'isAlreadyExisting' => false,
  82. 'standard' => '',
  83. 'title' => '',
  84. 'duration' => ''
  85. )
  86. );
  87. // Controle sur la clef fournie (elle doit etre non null et non existante en BD)
  88. if (!empty($courseKey)) {
  89. $course = $this->requireCourse($courseKey);
  90. if ($course) {
  91. $response['code'] = 400;
  92. $response['error'] = 'La clef de cours existe déjà. Utilser \'updateCourse\' pour mettre à jours un cours existant';
  93. return $response;
  94. }
  95. // ZIP
  96. // Test de l'existence du fichier à uploader
  97. if (!file_exists($zipPath)) {
  98. $response['code'] = 400;
  99. $response['error'] = 'Le chemin ne pointe pas vers un paquet valide';
  100. return $response;
  101. }
  102. // Validation du Package
  103. $validation = PackageValidator::validatePackage($zipPath);
  104. if (!$validation['validation']['status']) {
  105. return $response;
  106. }
  107. $response['metadata']['standard'] = $validation['standard'];
  108. $response['metadata']['title'] = $validation['title'];
  109. // Récupération de la signature du zip
  110. $hash = md5_file($zipPath);
  111. // Récupération de l'entity manager
  112. $em = $this->getDoctrine()->getManager();
  113. // Test de l'existence de la signature
  114. $repository = $em->getRepository(ZipFile::class);
  115. $zipFile = $repository->findOneBy(['zipFileprint' => $hash]);
  116. $response['metadata']['isAlreadyExisting'] = !empty($zipFile);
  117. // On s'arrete ici si seule l'analyse du paquet est demandée
  118. if ($analyse) {
  119. return $response;
  120. }
  121. // si le fichier n'existe pas déjà on le crée et on le stock coté moteur
  122. if (empty($zipFile)) {
  123. $response['metadata']['isAlreadyExisting'] = false;
  124. //upload du fichier coté moteur
  125. $uploadDate = new \DateTime('NOW');
  126. $fileName = pathinfo($zipPath)['filename'];
  127. $filePath = $this->packageFolder . '/' . $hash;
  128. if (copy($zipPath, $filePath) === false) {
  129. // Si la copie plante, on retourne une erreur
  130. $response['code'] = 400;
  131. $response['error'] = 'Erreur lors de la copie du fichier zip';
  132. return $response;
  133. }
  134. $endUploadDate = new \DateTime('NOW');
  135. // Création d'un objet permettant de traiter le fichier zip
  136. $zipFile = new ZipFile();
  137. $zipFile->setZipFileName($fileName);
  138. $zipFile->setZipFileprint($hash);
  139. $zipFile->setUploadDate($uploadDate);
  140. $zipFile->setEndUploadDate($endUploadDate);
  141. $zipFile->setStandard($validation['standard']);
  142. $zipFile->setImportStatus(ZipFile::IMPORT_STATUS_PROCESSING);
  143. $em->persist($zipFile);
  144. $em->flush();
  145. // Une fois l'objet ZipFile créé, on l'extrait
  146. $zipFile->extractZipFile($this->packageFolder, $this->contentFolder);
  147. }
  148. // COURS
  149. // Création du cours
  150. $course = new Course();
  151. $course->setCourseKey($courseKey);
  152. $course->setVersionRule($versioningRule);
  153. $em->persist($course);
  154. // Métadonées du cours
  155. $response['course']['courseKey'] = $course->getCourseKey();
  156. $response['course']['maxVersion'] = $course->getMaxVersion();
  157. // Mapping Zip/Cours
  158. $mapping = new MapCourseZipfile();
  159. $mapping->setCourse($course);
  160. $mapping->setZipFile($zipFile);
  161. $mapping->setVersion($response['course']['maxVersion']);
  162. $em->persist($mapping);
  163. $em->flush();
  164. $response['isSuccessfullyCreated'] = true;
  165. }
  166. return $response;
  167. }
  168. /**
  169. * Remplace le package d'un cours
  170. *
  171. * @param string $courseKey
  172. * @param string $zipPath
  173. * @param bool $analyse
  174. * @param string $versioningRule
  175. *
  176. * @return array
  177. */
  178. public function updateCourse(string $courseKey, string $zipPath, bool $analyse = false, string $versioningRule = Course::VERSIONING_RULE_DEFAULT)
  179. {
  180. // Création de la structure de la réponse
  181. $response = array(
  182. 'code' => 200,
  183. 'isSuccessfullyUpdated' => false,
  184. 'error' => '',
  185. 'parserErrors' => array(),
  186. 'course' => array(
  187. 'courseKey' => '',
  188. 'maxVersion' => 0,
  189. 'versioningRule' => $versioningRule
  190. ),
  191. 'metadata' => array(
  192. 'isAlreadyExisting' => false,
  193. 'standard' => '',
  194. 'title' => '',
  195. 'duration' => ''
  196. )
  197. );
  198. // Controle sur la clef fournie (elle doit etre non null et non existante en BD)
  199. if (!empty($courseKey)) {
  200. $course = $this->requireCourse($courseKey);
  201. if (empty($course)) {
  202. $response['code'] = 400;
  203. $response['error'] = 'La clef de cours ne fait référence à aucun cours existant';
  204. return $response;
  205. }
  206. // ZIP
  207. // Test de l'existence du fichier à uploader
  208. if (!file_exists($zipPath)) {
  209. $response['code'] = 400;
  210. $response['error'] = 'le chemin ne pointe pas vers un paquet valide';
  211. return $response;
  212. }
  213. // Validation du Package
  214. $validation = PackageValidator::validatePackage($zipPath);
  215. if (!$validation['validation']['status']) {
  216. return $response;
  217. }
  218. $response['metadata']['standard'] = $validation['standard'];
  219. $response['metadata']['title'] = $validation['title'];
  220. // Récupération de la signature du zip
  221. $hash = md5_file($zipPath);
  222. // Récupération de l'entity manager
  223. $em = $this->getDoctrine()->getManager();
  224. // Test de l'existence de la signature
  225. $repository = $em->getRepository(ZipFile::class);
  226. $zipFile = $repository->findOneBy(['zipFileprint' => $hash]);
  227. $response['metadata']['isAlreadyExisting'] = !empty($zipFile);
  228. // On s'arrete ici si seule l'analyse du paquet est demandée
  229. if ($analyse) {
  230. return $response;
  231. }
  232. // si le fichier n'existe pas déjà on le crée et on le stock coté moteur
  233. if (empty($zipFile)) {
  234. $response['metadata']['isAlreadyExisting'] = false;
  235. //upload du fichier coté moteur
  236. $uploadDate = new \DateTime('NOW');
  237. $fileName = pathinfo($zipPath)['filename'];
  238. $filePath = $this->packageFolder . '/' . $hash;
  239. if (copy($zipPath, $filePath) === false) {
  240. // Si la copie plante, on retourne une erreur
  241. $response['code'] = 400;
  242. $response['error'] = 'Erreur lors de la copie du fichier zip';
  243. return $response;
  244. }
  245. $endUploadDate = new \DateTime('NOW');
  246. // Création d'un objet permettant de traiter le fichier zip
  247. $zipFile = new ZipFile();
  248. $zipFile->setZipFileName($fileName);
  249. $zipFile->setZipFileprint($hash);
  250. $zipFile->setUploadDate($uploadDate);
  251. $zipFile->setEndUploadDate($endUploadDate);
  252. $zipFile->setStandard($validation['standard']);
  253. $zipFile->setImportStatus(ZipFile::IMPORT_STATUS_PROCESSING);
  254. $em->persist($zipFile);
  255. // Une fois l'objet ZipFile créé, on l'extrait
  256. $zipFile->extractZipFile($this->packageFolder, $this->contentFolder);
  257. }
  258. // COURS
  259. // MaJ du cours
  260. $course->setVersionRule($versioningRule);
  261. $newMaxVersion = $course->getMaxVersion();
  262. $newMaxVersion++;
  263. $course->setMaxVersion($newMaxVersion);
  264. $em->persist($course);
  265. // Métadonées du cours
  266. $response['course']['courseKey'] = $course->getCourseKey();
  267. $response['course']['maxVersion'] = $newMaxVersion;
  268. // Mapping Zip/Cours
  269. $mapping = new MapCourseZipfile();
  270. $mapping->setCourse($course);
  271. $mapping->setZipFile($zipFile);
  272. $mapping->setVersion($newMaxVersion);
  273. $em->persist($mapping);
  274. $em->flush();
  275. $response['isSuccessfullyUpdated'] = true;
  276. }
  277. return $response;
  278. }
  279. /**
  280. * Remplace la règle de versionning d'un cours
  281. *
  282. * @param string $courseKey
  283. * @param string $versionRule
  284. *
  285. * @return string
  286. */
  287. public function updateCourseVersionRule(string $courseKey, string $versionRule)
  288. {
  289. $em = $this->getDoctrine()->getManager();
  290. $course = $this->requireCourse($courseKey);
  291. if ($course) {
  292. $course->setVersionRule($versionRule);
  293. $em->persist($course);
  294. $em->flush();
  295. return $course->getCourseKey();
  296. }
  297. return null;
  298. }
  299. /**
  300. * Supprime une activité
  301. *
  302. * @return bool
  303. */
  304. public function deleteCourse(string $courseKey)
  305. {
  306. $em = $this->getDoctrine()->getManager();
  307. $course = $this->requireCourse($courseKey);
  308. if ($course) {
  309. $em->remove($course);
  310. $em->flush();
  311. return true;
  312. }
  313. return false;
  314. }
  315. /**
  316. * retourne le numéro de version de l'activité
  317. */
  318. public function getCourseCurrentVersion(string $courseKey)
  319. {
  320. $course = $this->requireCourse($courseKey);
  321. if ($course) {
  322. return $course->getMaxVersion();
  323. }
  324. return null;
  325. }
  326. /**
  327. * retourne la règle de versionnig
  328. */
  329. public function getCourseVersionRule()
  330. {
  331. $course = $this->requireCourse($courseKey);
  332. if ($course) {
  333. return $course->getVersionRule();
  334. }
  335. return null;
  336. }
  337. public function getCourses() : array
  338. {
  339. $em = $this->getDoctrine()->getManager();
  340. $repository = $em->getRepository(Course::class);
  341. $courses = $repository->findAll();
  342. return $courses;
  343. }
  344. // LEARNER
  345. /**
  346. * Création d'un apprenant
  347. *
  348. * @param string $learnerKey
  349. * @param string $familyName
  350. * @param string $givenName
  351. * @return int
  352. */
  353. public function createLearner(string $learnerKey, string $familyName, string $givenName)
  354. {
  355. if (!empty($learnerKey)) {
  356. $learner = $this->requireLearner($learnerKey);
  357. if (empty($learner)) {
  358. $em = $this->getDoctrine()->getManager();
  359. $learner = new Learner();
  360. $learner->setLearnerKey($learnerKey);
  361. $learner->setFamilyName($familyName);
  362. $learner->setGivenName($givenName);
  363. $em->persist($learner);
  364. $em->flush();
  365. return $learner->getLearnerId();
  366. }
  367. }
  368. return null;
  369. }
  370. /**
  371. * Modification d'un apprenant
  372. *
  373. * @param string $learnerKey
  374. * @param string $familyName
  375. * @param string $givenName
  376. * @return int
  377. */
  378. public function updateLearner(string $learnerKey, string $familyName, string $givenName)
  379. {
  380. if (!empty($learnerKey)) {
  381. $learner = $this->requireLearner($learnerKey);
  382. if ($learner) {
  383. $learner->setFamilyName($familyName);
  384. $learner->setGivenName($givenName);
  385. $em->persist($learner);
  386. $em->flush();
  387. }
  388. }
  389. return $learner->getLearnerKey();
  390. }
  391. /**
  392. * récupération d'un apprenant
  393. *
  394. * @param string $learnerKey
  395. *
  396. * @return Learner
  397. */
  398. public function getLearner(string $learnerKey)
  399. {
  400. $em = $this->getDoctrine()->getManager();
  401. $learner = $this->requireLearner($learnerKey);
  402. return $learner;
  403. }
  404. public function getLearners()
  405. {
  406. $em = $this->getDoctrine()->getManager();
  407. $repository = $em->getRepository(Learner::class);
  408. $learners = $repository->findAll();
  409. return $learners;
  410. }
  411. /**
  412. * supprime un apprenant
  413. *
  414. * @param string $learnerKey
  415. *
  416. * @return bool
  417. */
  418. public function deleteLearner(string $learnerKey)
  419. {
  420. $em = $this->getDoctrine()->getManager();
  421. $learner = $this->requireLearner($learnerKey);
  422. if ($learner) {
  423. $em->remove($learner);
  424. $em->flush();
  425. return true;
  426. }
  427. return false;
  428. }
  429. // REGISTRATION
  430. /**
  431. * création d'une inscription
  432. *
  433. * @param string $registrationKey
  434. * @param string $courseKey
  435. * @param string $learnerKey
  436. *
  437. * @return string
  438. */
  439. public function createRegistration(string $registrationKey, string $courseKey, string $learnerKey)
  440. {
  441. if (!empty($registrationKey)) {
  442. $registration = $this->requireRegistration($registrationKey);
  443. $course = $this->requireCourse($courseKey);
  444. $learner = $this->requireLearner($learnerKey);
  445. if (empty($registration) && $course && $learner) {
  446. $em = $this->getDoctrine()->getManager();
  447. $registration = new Registration();
  448. $registration->setRegistrationKey($registrationKey);
  449. $registration->setCourse($course);
  450. $registration->setLearner($learner);
  451. $em->persist($registration);
  452. $em->flush();
  453. return $registration->getRegistrationKey();
  454. }
  455. }
  456. return null;
  457. }
  458. /**
  459. * Renvoie les variables necessaire pour l'affichage du contenu du lecteur
  460. * dans le cadre d'une inscription (pour un apprenant et pour un cours)
  461. *
  462. * @param string $registrationKey
  463. * @param string $data
  464. *
  465. * @return array
  466. */
  467. public function getPlayerVariables(string $registrationKey, string $data = null, Response $response = null) : array
  468. {
  469. $result = array();
  470. // Vérification de l'existance de l'inscription
  471. $registration = $this->requireRegistration($registrationKey);
  472. if (empty($registration)) {
  473. // Erreur : une inscription valide doit être passée
  474. return null;
  475. }
  476. $em = $this->getDoctrine()->getManager();
  477. // Récupération du cours et des infos de version
  478. $course = $registration->getCourse();
  479. $maxVersion = $course->getMaxVersion();
  480. $versionRule = $course->getVersionRule();
  481. // Récupération du registrationAttempt courant
  482. $attemptRepository = $em->getRepository(RegistrationAttempt::class);
  483. $currentAttempt = $attemptRepository->findOneBy(array('registration' => $registration), array('registrationAttemptId' => 'desc'));
  484. $needCreation = empty($currentAttempt);
  485. $currentVersion = $needCreation ? null : $currentAttempt->getCourseVersion();
  486. // Vérification de l'existance d'un essai
  487. // et, si oui, de la présence d'une nouvelle version si la règle de versionning impose un restart
  488. if ($needCreation || ($versionRule == Course::VERSIONING_RULE_RESTART && $currentVersion < $maxVersion)) {
  489. $newAttempt = new RegistrationAttempt();
  490. $newAttempt->setCourseVersion($maxVersion);
  491. $newAttempt->setRegistration($registration);
  492. $em->persist($newAttempt);
  493. $em->flush();
  494. $currentAttempt = $newAttempt;
  495. $currentVersion = $maxVersion;
  496. if (!$needCreation) {
  497. // TODO Indiquer dans la réponse que l'on a effectué une modification de version pour l'apprenan
  498. $data = null;
  499. }
  500. }
  501. // Récupération du zip correspondant et ainsi de la version du standard utilisée
  502. $mapCourseZipRepository = $em->getRepository(MapCourseZipfile::class);
  503. $mapCourseZip = $mapCourseZipRepository->findOneBy(array('course' => $course, 'version' => $currentVersion));
  504. $zipFile = $mapCourseZip->getZipFile();
  505. $standard = $zipFile->getStandard();
  506. // Traitement des données en fonction du standard
  507. $variables = null;
  508. switch ($standard) {
  509. case DOMSCORM2004::SCORM_2004:
  510. $playerLogic = new Scorm2004PlayerLogic();
  511. $playerLogic->setContainer($this->container);
  512. $variables = $playerLogic->getScorm2004PlayerVariables($registrationKey, $zipFile, $currentAttempt, $data);
  513. break;
  514. case DOMSCORM12::SCORM_12:
  515. default:
  516. return null;
  517. }
  518. if ($variables['result'] == 'player') {
  519. // Construction d'un URL protégé
  520. $courseKey = $zipFile->getZipFileprint();
  521. $this->prepareContentAccess($courseKey, $response);
  522. $protection = $this->getBaseUrl($courseKey);
  523. $url = $variables['player']['content'];
  524. $url = $protection . '/' . $url;
  525. $variables['player']['content'] = $url;
  526. } else {
  527. $this->response = new Response();
  528. }
  529. return $variables;
  530. }
  531. /**
  532. * supprime une inscription
  533. *
  534. * @param string $registrationKey
  535. *
  536. * @return string
  537. */
  538. public function deleteRegistration(string $registrationKey)
  539. {
  540. $registration = $this->requireRegistration($registrationKey);
  541. if ($registration) {
  542. $em = $this->getDoctrine()->getManager();
  543. $em->remove($registration);
  544. $em->flush();
  545. return true;
  546. }
  547. return false;
  548. }
  549. /**
  550. * supprime les données d'apprentissage d'un apprenant pour une inscription
  551. *
  552. * @param string $learnerKey
  553. *
  554. * @return bool
  555. */
  556. public function resetRegistraitonData(string $registrationKey)
  557. {
  558. $em = $this->getDoctrine()->getManager();
  559. $trackRepository = $em->getRepository(Registration::class);
  560. $registration = $this->requireRegistration($registrationKey);
  561. if ($registration) {
  562. // Récupération des Registrations Attempts
  563. $attempts = $this->getAttempts($registrationKey);
  564. // Efface les RegistrationAttempts
  565. // Les objets SCORM seront effacés en cascade
  566. foreach ($attempts as $attempt) {
  567. $em->remove($attempt);
  568. }
  569. // Création d'un nouveau RegistrationAttempt
  570. $course = $registration->getCourse();
  571. $attempt = new RegistrationAttempt();
  572. $attempt->setCourseVersion($course->getMaxVersion());
  573. $attempt->setRegistration($registration);
  574. $em->persist($attempt);
  575. $em->flush();
  576. return true;
  577. }
  578. return false;
  579. }
  580. public function getRegistrations()
  581. {
  582. $em = $this->getDoctrine()->getManager();
  583. $repository = $em->getRepository(Registration::class);
  584. $registrations = $repository->findAll();
  585. return $registrations;
  586. }
  587. // ATTEMPT
  588. /**
  589. * Récupération des essais
  590. *
  591. * @param string $registrationKey
  592. *
  593. * @return string
  594. */
  595. public function getAttempts(string $registrationKey)
  596. {
  597. $em = $this->getDoctrine()->getManager();
  598. $registration = $this->requireRegistration($registrationKey);
  599. if ($registration) {
  600. $attempts = $registration->getRegistrationAttempts();
  601. return ($attempts);
  602. }
  603. return null;
  604. }
  605. /**
  606. * Récupération de l'id de l'essai en cours
  607. *
  608. * @param string $registrationKey
  609. *
  610. * @return int
  611. */
  612. public function getCurrentAttempt(string $registrationKey)
  613. {
  614. $em = $this->getDoctrine()->getManager();
  615. $registration = $this->requireRegistration($registrationKey);
  616. if ($registration) {
  617. $attemptRepository = $em->getRepository(RegistrationAttempt::class);
  618. $currentAttempt = $attemptRepository->findCurrentAttemptByRegistration($registration);
  619. return $currentAttempt->registrationAttemptId();
  620. }
  621. return null;
  622. }
  623. /**
  624. * Récupération de la version de l'activité pour l'essai
  625. *
  626. * @param int $attemptId
  627. *
  628. * @return int
  629. */
  630. public function getAttemptCourseVersion(int $attemptId)
  631. {
  632. $em = $this->getDoctrine()->getManager();
  633. $attempt = $this->requireRegistrationAttempt($attemptId);
  634. if ($attempt) {
  635. return $attempt->getCourseVersion();
  636. }
  637. return null;
  638. }
  639. /**
  640. * Récupération des statistiques liées à un essai
  641. *
  642. * @param int $attemptId
  643. *
  644. * @return array
  645. */
  646. public function getAttemptStats(int $attemptId)
  647. {
  648. }
  649. // TOOLS
  650. /**
  651. * Undocumented function
  652. *
  653. * @param string $courseKey
  654. * @param Response $response
  655. * @return void
  656. */
  657. private function prepareContentAccess(string $courseKey, Response $response = null) : void
  658. {
  659. if (!$this->session->has('scormkey')) {
  660. $scormkey = rand();
  661. $this->session->set('scormkey', $scormkey);
  662. } else {
  663. $scormkey = $this->session->get('scormkey');
  664. }
  665. if (null === $response) {
  666. $this->response = new Response();
  667. } else {
  668. $this->response = $response;
  669. }
  670. $pathCookie = $this->contentUrlPrefix."/$scormkey/$courseKey/";
  671. $md5cookiekey = md5($scormkey);
  672. $cookie = new Cookie('SCORMBundle', $md5cookiekey, 0, $pathCookie);
  673. $this->response->headers->setCookie($cookie);
  674. }
  675. /**
  676. * il FAUT utiliser la Response de l'objet ScormEngine pour bénéficier du cookie
  677. * de sécurité (sans cela blocage complet de l'acces à la ressource)
  678. *
  679. * @return Response
  680. */
  681. public function getResponse() : Response
  682. {
  683. return $this->response;
  684. }
  685. /**
  686. * renvoi l'url de base permettant d'acceder à un fichier de la ressource
  687. * Format :
  688. * /content/nomdupaquet/clefautorisation
  689. *
  690. * Example :
  691. * /content/
  692. *
  693. * @return string
  694. */
  695. public function getBaseUrl($courseKey) : string
  696. {
  697. return $this->contentUrlPrefix.'/'.$this->session->get('scormkey').'/'.$courseKey;
  698. }
  699. /**
  700. *
  701. * @throws \LogicException
  702. * @return ManagerRegistry
  703. */
  704. protected function getDoctrine(): ManagerRegistry
  705. {
  706. if (!$this->container->has('doctrine')) {
  707. throw new \LogicException('The DoctrineBundle is not registered in your application. Try running "composer require symfony/orm-pack".');
  708. }
  709. return $this->container->get('doctrine');
  710. }
  711. /**
  712. * Retourne l'activité
  713. *
  714. * @param string $courseKey
  715. * @return Course
  716. */
  717. protected function requireCourse(string $courseKey)
  718. {
  719. $em = $this->getDoctrine()->getManager();
  720. $repository = $em->getRepository(Course::class);
  721. $course = $repository->findOneBy(array('courseKey' => $courseKey));
  722. return $course;
  723. }
  724. /**
  725. * Retourne l'apprenant
  726. *
  727. * @param string $learnerKey
  728. * @return Learner
  729. */
  730. protected function requireLearner(string $learnerKey)
  731. {
  732. $em = $this->getDoctrine()->getManager();
  733. $repository = $em->getRepository(Learner::class);
  734. $learner = $repository->findOneBy(array('learnerKey' => $learnerKey));
  735. return $learner;
  736. }
  737. /**
  738. * Retourne l'inscription
  739. *
  740. * @param string $registrationKey
  741. *
  742. * @return Registration
  743. */
  744. protected function requireRegistration(string $registrationKey)
  745. {
  746. $em = $this->getDoctrine()->getManager();
  747. $repository = $em->getRepository(Registration::class);
  748. $registration = $repository->findOneBy(array('registrationKey' => $registrationKey));
  749. return $registration;
  750. }
  751. /**
  752. * Retourne un essais relatif à une inscription
  753. *
  754. * @param int $attemptId
  755. *
  756. * @return RegistrationAttempt
  757. */
  758. protected function requireRegistrationAttempt(int $attemptId)
  759. {
  760. $em = $this->getDoctrine()->getManager();
  761. $repository = $em->getRepository(RegistrationAttempt::class);
  762. $attempt = $repository->find($attemptId);
  763. return $attempt;
  764. }
  765. }