sequence.ajax.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. use Chamilo\CoreBundle\Entity\Sequence;
  4. use Chamilo\CoreBundle\Entity\SequenceResource;
  5. use ChamiloSession as Session;
  6. use Fhaculty\Graph\Graph;
  7. use Fhaculty\Graph\Vertex;
  8. use Graphp\GraphViz\GraphViz;
  9. /**
  10. * Responses to AJAX calls.
  11. */
  12. require_once __DIR__.'/../global.inc.php';
  13. $action = isset($_REQUEST['a']) ? $_REQUEST['a'] : null;
  14. $id = isset($_REQUEST['id']) ? $_REQUEST['id'] : null;
  15. $type = isset($_REQUEST['type']) ? $_REQUEST['type'] : null;
  16. $sequenceId = isset($_REQUEST['sequence_id']) ? $_REQUEST['sequence_id'] : 0;
  17. $em = Database::getManager();
  18. $repository = $em->getRepository('ChamiloCoreBundle:SequenceResource');
  19. switch ($action) {
  20. case 'graph':
  21. api_block_anonymous_users();
  22. api_protect_admin_script();
  23. switch ($type) {
  24. case 'session':
  25. $type = SequenceResource::SESSION_TYPE;
  26. /** @var Sequence $sequence */
  27. $sequence = $em->getRepository('ChamiloCoreBundle:Sequence')->find($sequenceId);
  28. if (empty($sequence)) {
  29. exit;
  30. }
  31. if ($sequence->hasGraph()) {
  32. $graph = $sequence->getUnSerializeGraph();
  33. $graph->setAttribute('graphviz.node.fontname', 'arial');
  34. $graphviz = new GraphViz();
  35. $graphImage = '';
  36. try {
  37. $graphImage = $graphviz->createImageSrc($graph);
  38. echo Display::img(
  39. $graphImage,
  40. get_lang('Dependency tree'),
  41. ['class' => 'center-block'],
  42. false
  43. );
  44. } catch (UnexpectedValueException $e) {
  45. error_log(
  46. $e->getMessage()
  47. .' - Graph could not be rendered in resources sequence'
  48. .' because GraphViz command "dot" could not be executed '
  49. .'- Make sure graphviz is installed.'
  50. );
  51. echo '<p class="text-center"><small>'.get_lang('Missing chart library. Please check the error log for details.')
  52. .'</small></p>';
  53. }
  54. }
  55. break;
  56. }
  57. break;
  58. case 'get_icon':
  59. api_block_anonymous_users();
  60. api_protect_admin_script();
  61. $link = '';
  62. switch ($type) {
  63. case 'session':
  64. $type = SequenceResource::SESSION_TYPE;
  65. $showDelete = isset($_REQUEST['show_delete']) ? $_REQUEST['show_delete'] : false;
  66. $image = Display::return_icon('item-sequence.png', null, null, ICON_SIZE_LARGE);
  67. $sessionInfo = api_get_session_info($id);
  68. if (!empty($sessionInfo)) {
  69. $linkDelete = $linkUndo = '';
  70. if ($showDelete) {
  71. $linkDelete = Display::toolbarButton(
  72. get_lang('Delete'),
  73. '#',
  74. 'trash',
  75. 'default',
  76. [
  77. 'class' => 'delete_vertex btn btn-block btn-xs',
  78. 'data-id' => $id,
  79. ]
  80. );
  81. $linkUndo = Display::toolbarButton(
  82. get_lang('Undo'),
  83. '#',
  84. 'undo',
  85. 'default',
  86. [
  87. 'class' => 'undo_delete btn btn-block btn-xs',
  88. 'style' => 'display: none;',
  89. 'data-id' => $id,
  90. ]
  91. );
  92. }
  93. $link = '<div class="parent" data-id="'.$id.'">';
  94. $link .= '<div class="big-icon">';
  95. $link .= $image;
  96. $link .= '<div class="sequence-course">'.$sessionInfo['name'].'</div>';
  97. $link .= Display::tag(
  98. 'button',
  99. $id,
  100. [
  101. 'class' => 'sequence-id',
  102. 'title' => get_lang('Use as reference'),
  103. 'type' => 'button',
  104. ]
  105. );
  106. $link .= $linkDelete;
  107. $link .= $linkUndo;
  108. $link .= '</div></div>';
  109. }
  110. break;
  111. }
  112. echo $link;
  113. break;
  114. case 'delete_vertex':
  115. api_block_anonymous_users();
  116. api_protect_admin_script();
  117. $vertexId = isset($_REQUEST['vertex_id']) ? $_REQUEST['vertex_id'] : null;
  118. $type = SequenceResource::SESSION_TYPE;
  119. /** @var Sequence $sequence */
  120. $sequence = $em->getRepository('ChamiloCoreBundle:Sequence')->find($sequenceId);
  121. if (empty($sequence)) {
  122. exit;
  123. }
  124. /** @var SequenceResource $sequenceResource */
  125. $sequenceResource = $repository->findOneBy(
  126. ['resourceId' => $id, 'type' => $type, 'sequence' => $sequence]
  127. );
  128. if (empty($sequenceResource)) {
  129. exit;
  130. }
  131. if ($sequenceResource->getSequence()->hasGraph()) {
  132. $graph = $sequenceResource->getSequence()->getUnSerializeGraph();
  133. if ($graph->hasVertex($vertexId)) {
  134. $edgeIterator = $graph->getEdges()->getIterator();
  135. $edgeToDelete = null;
  136. foreach ($edgeIterator as $edge) {
  137. if ($edge->getVertexStart()->getId() == $vertexId && $edge->getVertexEnd()->getId() == $id) {
  138. $edgeToDelete = $edge;
  139. $vertexFromTo = null;
  140. $vertexToFrom = null;
  141. foreach ($edgeIterator as $edges) {
  142. if (intval($edges->getVertexEnd()->getId()) === intval($id)) {
  143. $vertexFromTo = $edges;
  144. }
  145. if (intval($edges->getVertexStart()->getId()) === intval($vertexId)) {
  146. $vertexToFrom = $edges;
  147. }
  148. }
  149. if ($vertexFromTo && !$vertexToFrom) {
  150. Session::write('sr_vertex', true);
  151. $vertex = $graph->getVertex($id);
  152. $vertex->destroy();
  153. $em->remove($sequenceResource);
  154. }
  155. if ($vertexToFrom && $vertexFromTo) {
  156. $vertex = $graph->getVertex($vertexId);
  157. $edgeToDelete->destroy();
  158. }
  159. if ($vertexToFrom && !$vertexFromTo) {
  160. $vertex = $graph->getVertex($vertexId);
  161. $vertex->destroy();
  162. $sequenceResourceToDelete = $repository->findOneBy(
  163. [
  164. 'resourceId' => $vertexId,
  165. 'type' => $type,
  166. 'sequence' => $sequence,
  167. ]
  168. );
  169. $em->remove($sequenceResourceToDelete);
  170. }
  171. if (!$vertexToFrom && !$vertexFromTo) {
  172. Session::write('sr_vertex', true);
  173. $vertexTo = $graph->getVertex($id);
  174. $vertexFrom = $graph->getVertex($vertexId);
  175. if ($vertexTo->getVerticesEdgeFrom()->count() > 1) {
  176. $vertexFrom->destroy();
  177. $sequenceResourceToDelete = $repository->findOneBy(
  178. [
  179. 'resourceId' => $vertexId,
  180. 'type' => $type,
  181. 'sequence' => $sequence,
  182. ]
  183. );
  184. $em->remove($sequenceResourceToDelete);
  185. } else {
  186. $vertexTo->destroy();
  187. $vertexFrom->destroy();
  188. $sequenceResourceToDelete = $repository->findOneBy(
  189. [
  190. 'resourceId' => $vertexId,
  191. 'type' => $type,
  192. 'sequence' => $sequence,
  193. ]
  194. );
  195. $em->remove($sequenceResource);
  196. $em->remove($sequenceResourceToDelete);
  197. }
  198. }
  199. }
  200. }
  201. $sequence->setGraphAndSerialize($graph);
  202. $em->merge($sequence);
  203. $em->flush();
  204. }
  205. }
  206. break;
  207. case 'load_resource':
  208. api_block_anonymous_users();
  209. api_protect_admin_script();
  210. // children or parent
  211. $loadResourceType = isset($_REQUEST['load_resource_type']) ? $_REQUEST['load_resource_type'] : null;
  212. $sequenceId = isset($_REQUEST['sequence_id']) ? $_REQUEST['sequence_id'] : 0;
  213. $type = SequenceResource::SESSION_TYPE;
  214. /** @var Sequence $sequence */
  215. $sequence = $em->getRepository('ChamiloCoreBundle:Sequence')->find($sequenceId);
  216. if (empty($sequence)) {
  217. exit;
  218. }
  219. /** @var SequenceResource $sequenceResource */
  220. $sequenceResource = $repository->findOneBy(
  221. ['resourceId' => $id, 'type' => $type, 'sequence' => $sequence]
  222. );
  223. if (empty($sequenceResource)) {
  224. exit;
  225. }
  226. if ($sequenceResource->hasGraph()) {
  227. $graph = $sequenceResource->getSequence()->getUnSerializeGraph();
  228. /** @var Vertex $mainVertice */
  229. if ($graph->hasVertex($id)) {
  230. $mainVertex = $graph->getVertex($id);
  231. if (!empty($mainVertex)) {
  232. $vertexList = null;
  233. switch ($loadResourceType) {
  234. case 'parent':
  235. $vertexList = $mainVertex->getVerticesEdgeFrom();
  236. break;
  237. case 'children':
  238. $vertexList = $mainVertex->getVerticesEdgeTo();
  239. break;
  240. }
  241. $list = [];
  242. if (!empty($vertexList)) {
  243. foreach ($vertexList as $vertex) {
  244. $list[] = $vertex->getId();
  245. }
  246. }
  247. if (!empty($list)) {
  248. echo implode(',', $list);
  249. }
  250. }
  251. }
  252. }
  253. break;
  254. case 'save_resource':
  255. api_block_anonymous_users();
  256. api_protect_admin_script();
  257. $parents = isset($_REQUEST['parents']) ? $_REQUEST['parents'] : '';
  258. $sequenceId = isset($_REQUEST['sequence_id']) ? $_REQUEST['sequence_id'] : 0;
  259. $type = isset($_REQUEST['type']) ? $_REQUEST['type'] : '';
  260. if (empty($parents) || empty($sequenceId) || empty($type)) {
  261. exit;
  262. }
  263. /** @var Sequence $sequence */
  264. $sequence = $em->getRepository('ChamiloCoreBundle:Sequence')->find($sequenceId);
  265. if (empty($sequence)) {
  266. exit;
  267. }
  268. $vertexFromSession = Session::read('sr_vertex');
  269. if ($vertexFromSession) {
  270. Session::erase('sr_vertex');
  271. echo Display::return_message(get_lang('Saved..'), 'success');
  272. break;
  273. }
  274. $parents = str_replace($id, '', $parents);
  275. $parents = explode(',', $parents);
  276. $parents = array_filter($parents);
  277. if ($sequence->hasGraph()) {
  278. $graph = $sequence->getUnSerializeGraph();
  279. } else {
  280. $graph = new Graph();
  281. }
  282. switch ($type) {
  283. case 'session':
  284. $type = SequenceResource::SESSION_TYPE;
  285. $sessionInfo = api_get_session_info($id);
  286. $name = $sessionInfo['name'];
  287. if ($graph->hasVertex($id)) {
  288. $main = $graph->getVertex($id);
  289. } else {
  290. $main = $graph->createVertex($id);
  291. }
  292. foreach ($parents as $parentId) {
  293. if ($graph->hasVertex($parentId)) {
  294. $parent = $graph->getVertex($parentId);
  295. if (!$parent->hasEdgeTo($main)) {
  296. $parent->createEdgeTo($main);
  297. }
  298. } else {
  299. $parent = $graph->createVertex($parentId);
  300. $parent->createEdgeTo($main);
  301. }
  302. }
  303. foreach ($parents as $parentId) {
  304. $sequenceResourceParent = $repository->findOneBy(
  305. ['resourceId' => $parentId, 'type' => $type, 'sequence' => $sequence]
  306. );
  307. if (empty($sequenceResourceParent)) {
  308. $sequenceResourceParent = new SequenceResource();
  309. $sequenceResourceParent
  310. ->setSequence($sequence)
  311. ->setType(SequenceResource::SESSION_TYPE)
  312. ->setResourceId($parentId);
  313. $em->persist($sequenceResourceParent);
  314. }
  315. }
  316. //$graphviz = new GraphViz();
  317. //echo $graphviz->createImageHtml($graph);
  318. /** @var SequenceResource $sequenceResource */
  319. $sequenceResource = $repository->findOneBy(
  320. ['resourceId' => $id, 'type' => $type, 'sequence' => $sequence]
  321. );
  322. if (empty($sequenceResource)) {
  323. // Create
  324. $sequence->setGraphAndSerialize($graph);
  325. $sequenceResource = new SequenceResource();
  326. $sequenceResource
  327. ->setSequence($sequence)
  328. ->setType(SequenceResource::SESSION_TYPE)
  329. ->setResourceId($id);
  330. } else {
  331. // Update
  332. $sequenceResource->getSequence()->setGraphAndSerialize($graph);
  333. }
  334. $em->persist($sequenceResource);
  335. $em->flush();
  336. echo Display::return_message(get_lang('Saved..'), 'success');
  337. break;
  338. }
  339. break;
  340. case 'get_requirements':
  341. $userId = api_get_user_id();
  342. switch ($type) {
  343. case SequenceResource::SESSION_TYPE:
  344. $session = api_get_session_info($id);
  345. $sequences = $repository->getRequirements(
  346. $session['id'],
  347. $type
  348. );
  349. if (count($sequences) === 0) {
  350. break;
  351. }
  352. $sequenceList = SequenceResourceManager::checkRequirementsForUser($sequences, $type, $userId);
  353. $allowSubscription = SequenceResourceManager::checkSequenceAreCompleted($sequenceList);
  354. $courseController = new CoursesController();
  355. $view = new Template(null, false, false, false, false, false);
  356. $view->assign('sequences', $sequenceList);
  357. $view->assign('allow_subscription', $allowSubscription);
  358. if ($allowSubscription) {
  359. $view->assign(
  360. 'subscribe_button',
  361. $courseController->getRegisteredInSessionButton(
  362. $session['id'],
  363. $session['name'],
  364. false
  365. )
  366. );
  367. }
  368. $template = $view->get_template(
  369. 'sequence_resource/session_requirements.tpl'
  370. );
  371. $view->display($template);
  372. break;
  373. }
  374. break;
  375. }