lp_stats.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. <?php
  2. /*
  3. ==============================================================================
  4. Dokeos - elearning and course management software
  5. Copyright (c) 2008 Dokeos SPRL
  6. For a full list of contributors, see "credits.txt".
  7. The full license can be read in "license.txt".
  8. This program is free software; you can redistribute it and/or
  9. modify it under the terms of the GNU General Public License
  10. as published by the Free Software Foundation; either version 2
  11. of the License, or (at your option) any later version.
  12. See the GNU General Public License for more details.
  13. Contact address: Dokeos, rue du Corbeau, 108, B-1030 Brussels, Belgium
  14. Mail: info@dokeos.com
  15. ==============================================================================
  16. */
  17. /**
  18. * This script displays statistics on the current learning path (scorm)
  19. *
  20. * This script must be included by lp_controller.php to get basic initialisation
  21. * @package dokeos.learnpath
  22. * @author Yannick Warnier <ywarnier@beeznest.org>
  23. */
  24. require_once('learnpath.class.php');
  25. //require_once('scorm.class.php');
  26. require_once ('resourcelinker.inc.php');
  27. if(empty($_SESSION['_course']['id']) && isset($_GET['course']))
  28. {
  29. $course_code = Database :: escape_string($_GET['course']);
  30. }
  31. else
  32. {
  33. $course_code = $_SESSION['_course']['id'];
  34. }
  35. //The two following variables have to be declared by the includer script
  36. //$lp_id = $_SESSION['oLP']->get_id();
  37. //$list = $_SESSION['oLP']->get_flat_ordered_items_list($lp_id);
  38. //$user_id = $_user['user_id'];
  39. //$stats_charset = $_SESSION['oLP']->encoding
  40. if(!isset($origin))
  41. $origin = '';
  42. if($origin != 'tracking')
  43. {
  44. if (!empty ($stats_charset)) {
  45. $charset_lang = $stats_charset;
  46. } else {
  47. $charset_lang = api_get_setting('platform_charset');
  48. }
  49. $dokeos_charset = api_get_setting('platform_charset');
  50. $charset = $charset_lang;
  51. $w = $tablewidth -20;
  52. $htmlHeadXtra[] = ''.'<style type="text/css" media="screen, projection">
  53. /*<![CDATA[*/
  54. @import "../css/default/scorm.css";
  55. /*]]>*/
  56. </style>';
  57. include_once ('../inc/reduced_header.inc.php');
  58. echo '<body>';
  59. }
  60. //if display in fullscreen required
  61. if (strcmp($_GET["fs"], "true") == 0)
  62. {
  63. $output .= "<table align='center'>";
  64. }
  65. else
  66. {
  67. $output .= "<table class='margin_table'>";
  68. }
  69. //check if the user asked for the "extend all" option
  70. $extend_all_link = '';
  71. $extend_all = 0;
  72. if($origin == 'tracking')
  73. {
  74. $url_suffix = '&course='.$_GET['course'].'&student_id='.$_GET['student_id'].'&lp_id='.$_GET['lp_id'].'&origin='.$_GET['origin'];
  75. }
  76. else
  77. {
  78. $url_suffix = '';
  79. }
  80. if (!empty ($_GET['extend_all']))
  81. {
  82. $extend_all_link = '<a href="'.api_get_self().'?action=stats'.$url_suffix.'"><img src="../img/view_less_stats.gif" alt="fold_view" border="0"></a>';
  83. $extend_all = 1;
  84. }
  85. else
  86. {
  87. $extend_all_link = '<a href="'.api_get_self().'?action=stats&extend_all=1'.$url_suffix.'"><img src="../img/view_more_stats.gif" alt="extend_view" border="0"></a>';
  88. }
  89. if($origin != 'tracking')
  90. {
  91. $output .= "<tr><td><div class='title'>".htmlentities(get_lang('ScormMystatus'), ENT_QUOTES, $dokeos_charset)."</div></td></tr>";
  92. }
  93. $output .= "<tr><td>&nbsp;</td></tr>"."<tr><td>"."<table border='0' class='data_table'><tr>\n".'<td width="16">'.$extend_all_link.'</td>'.'<td colspan="4" class="title"><div class="mystatusfirstrow">'.htmlentities(get_lang('ScormLessonTitle'), ENT_QUOTES, $dokeos_charset)."</div></td>\n".'<td colspan="2" class="title"><div class="mystatusfirstrow">'.htmlentities(get_lang('ScormStatus'), ENT_QUOTES, $dokeos_charset)."</div></td>\n".'<td colspan="2" class="title"><div class="mystatusfirstrow">'.htmlentities(get_lang('ScormScore'), ENT_QUOTES, $dokeos_charset)."</div></td>\n".'<td colspan="2" class="title"><div class="mystatusfirstrow">'.htmlentities(get_lang('ScormTime'), ENT_QUOTES, $dokeos_charset)."</div></td><td class='title'><div class='mystatusfirstrow'>".htmlentities(get_lang('Actions'), ENT_QUOTES, $dokeos_charset)."</div></td></tr>\n";
  94. //going through the items using the $items[] array instead of the database order ensures
  95. // we get them in the same order as in the imsmanifest file, which is rather random when using
  96. // the database table
  97. $TBL_LP_ITEM = Database :: get_course_table('lp_item');
  98. $TBL_LP_ITEM_VIEW = Database :: get_course_table('lp_item_view');
  99. $TBL_LP_VIEW = Database :: get_course_table('lp_view');
  100. $tbl_stats_exercices = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
  101. $sql = "SELECT max(view_count) FROM $TBL_LP_VIEW " .
  102. "WHERE lp_id = $lp_id AND user_id = '".$user_id."'";
  103. $res = api_sql_query($sql, __FILE__, __LINE__);
  104. $view = '';
  105. if (Database :: num_rows($res) > 0)
  106. {
  107. $myrow = Database :: fetch_array($res);
  108. $view = $myrow[0];
  109. }
  110. $counter = 0;
  111. //error_log('New LP - Querying views for latest attempt: '.$sql,0);
  112. $total_score = 0;
  113. $total_max_score = 0;
  114. $total_time = 0;
  115. $h = get_lang('h');
  116. if($export_csv)
  117. {
  118. $csv_content[] = array (
  119. get_lang('ScormLessonTitle'),
  120. get_lang('ScormStatus'),
  121. get_lang('ScormScore'),
  122. get_lang('ScormTime')
  123. );
  124. }
  125. foreach ($list as $my_item_id)
  126. {
  127. $extend_this = 0;
  128. $qry_order = 'DESC';
  129. if ((!empty ($_GET['extend_id']) and $_GET['extend_id'] == $my_item_id) OR $extend_all) {
  130. $extend_this = 1;
  131. $qry_order = 'ASC';
  132. }
  133. if (!empty ($view))
  134. {
  135. $sql = "SELECT iv.status as mystatus, v.view_count as mycount, " .
  136. "iv.score as myscore, iv.total_time as mytime, i.id as myid, " .
  137. "i.title as mytitle, i.max_score as mymaxscore, " .
  138. "iv.max_score as myviewmaxscore, " .
  139. "i.item_type as item_type, iv.view_count as iv_view_count, " .
  140. "iv.id as iv_id, path as path ".
  141. " FROM $TBL_LP_ITEM as i, $TBL_LP_ITEM_VIEW as iv, $TBL_LP_VIEW as v ".
  142. " WHERE i.id = iv.lp_item_id ".
  143. " AND i.id = $my_item_id ".
  144. " AND iv.lp_view_id = v.id ".
  145. " AND i.lp_id = $lp_id ".
  146. " AND v.user_id = ".$user_id." ".
  147. " AND v.view_count = $view ".
  148. " ORDER BY iv.view_count $qry_order ";
  149. } else {
  150. $sql = "SELECT iv.status as mystatus, v.view_count as mycount, " .
  151. "iv.score as myscore, iv.total_time as mytime, i.id as myid, " .
  152. "i.title as mytitle, i.max_score as mymaxscore, " .
  153. "iv.max_score as myviewmaxscore, " .
  154. "i.item_type as item_type, iv.view_count as iv_view_count, " .
  155. "iv.id as iv_id, path as path ".
  156. " FROM $TBL_LP_ITEM as i, $TBL_LP_ITEM_VIEW as iv, $TBL_LP_VIEW as v ".
  157. " WHERE i.id = iv.lp_item_id ".
  158. " AND i.id = $my_item_id ".
  159. " AND iv.lp_view_id = v.id ".
  160. " AND i.lp_id = $lp_id ".
  161. " AND v.user_id = ".$user_id." ".
  162. " ORDER BY iv.view_count $qry_order ";
  163. }
  164. $result = api_sql_query($sql, __FILE__, __LINE__);
  165. $num = Database :: num_rows($result);
  166. $time_for_total = 'NaN';
  167. if (($extend_this OR $extend_all) && $num > 0)
  168. {
  169. $row = Database :: fetch_array($result);
  170. //if there are several attempts, and the link to extend has been clicked...
  171. if (($counter % 2) == 0)
  172. {
  173. $oddclass = "row_odd";
  174. }
  175. else
  176. {
  177. $oddclass = "row_even";
  178. }
  179. if ($inter_num)
  180. $extend_link = '<a href="'.api_get_self().'?action=stats&fold_id='.$my_item_id.$url_suffix.'"><img src="../img/visible.gif" alt="fold_view" border="0"></a>'."\n";
  181. $title = $row['mytitle'];
  182. $title = stripslashes(html_entity_decode($title,ENT_QUOTES, $dokeos_charset));
  183. if (empty ($title))
  184. {
  185. $title = rl_get_resource_name(api_get_course_id(), $lp_id, $row['myid']);
  186. }
  187. if ($row['item_type'] != 'dokeos_chapter')
  188. {
  189. if($row['item_type'] == 'quiz')
  190. {
  191. if($origin != 'tracking')
  192. {
  193. $sql_last_attempt='SELECT exe_id FROM '.$tbl_stats_exercices.' WHERE exe_exo_id="'.$row['path'].'" AND exe_user_id="'.api_get_user_id().'" AND exe_cours_id="'.$course_code.'" ORDER BY exe_date DESC LIMIT 1';
  194. }
  195. else{
  196. $sql_last_attempt='SELECT exe_id FROM '.$tbl_stats_exercices.' WHERE exe_exo_id="'.$row['path'].'" AND exe_user_id="'.$_GET['student_id'].'" AND exe_cours_id="'.$course_code.'" ORDER BY exe_date DESC LIMIT 1';
  197. }
  198. $resultLastAttempt = api_sql_query($sql_last_attempt,__FILE__,__LINE__);
  199. $num = Database::num_rows($resultLastAttempt);
  200. if($num>0)
  201. {
  202. $id_last_attempt=Database::result($resultLastAttempt,0,0);
  203. }
  204. if($origin != 'tracking')
  205. {
  206. $correct_test_link = '<a href="../exercice/exercise_show.php?origin=student_progress&id='.$id_last_attempt.'&cidReq='.$course_code.'" target="_parent"><img src="'.api_get_path(WEB_IMG_PATH).'quiz.gif"></a>';
  207. }
  208. else
  209. {
  210. $correct_test_link = '<a href="../exercice/exercise_show.php?origin=tracking_course&id='.$id_last_attempt.'&cidReq='.$course_code.'&student='.$_GET['student_id'].'" target="_parent"><img src="'.api_get_path(WEB_IMG_PATH).'quiz.gif"></a>';
  211. }
  212. }
  213. else{
  214. $correct_test_link='-';
  215. }
  216. $output .= "<tr class='$oddclass'>\n"."<td>$extend_link</td>\n".'<td colspan="4" class="content"><div class="mystatus">'.htmlentities($title)."</div></td>\n".'<td colspan="2" class="content"></td>'."\n".'<td colspan="2" class="content"></td>'."\n".'<td colspan="2" class="content"></td><td class="content">'.$correct_test_link.'</td>'."\n"."</tr>\n";
  217. }
  218. $counter ++;
  219. do {
  220. //check if there are interactions below
  221. $extend_attempt_link = '';
  222. $extend_this_attempt = 0;
  223. if ((learnpath :: get_interactions_count_from_db($row['iv_id']) > 0 || learnpath :: get_objectives_count_from_db($row['iv_id']) > 0 ) && !$extend_all) {
  224. if (!empty ($_GET['extend_attempt_id']) && $_GET['extend_attempt_id'] == $row['iv_id']) {
  225. //the extend button for this attempt has been clicked
  226. $extend_this_attempt = 1;
  227. $extend_attempt_link = '<a href="'.api_get_self().'?action=stats&extend_id='.$my_item_id.'&fold_attempt_id='.$row['iv_id'].$url_suffix.'"><img src="../img/visible.gif" alt="fold_attempt_view" border="0"></a>'."\n";
  228. } else { //same case if fold_attempt_id is set, so not implemented explicitly
  229. //the extend button for this attempt has not been clicked
  230. $extend_attempt_link = '<a href="'.api_get_self().'?action=stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].$url_suffix.'"><img src="../img/invisible.gif" alt="extend_attempt_view" border="0"></a>'."\n";
  231. }
  232. }
  233. if (($counter % 2) == 0)
  234. {
  235. $oddclass = "row_odd";
  236. } else {
  237. $oddclass = "row_even";
  238. }
  239. $lesson_status = $row['mystatus'];
  240. $score = $row['myscore'];
  241. $time_for_total = $row['mytime'];
  242. $time = learnpathItem :: get_scorm_time('js', $row['mytime']);
  243. $type;
  244. $scoIdentifier = $row['myid'];
  245. if ($score == 0) {
  246. $maxscore = 0;
  247. } else {
  248. if($row['item_type'] == 'sco')
  249. {
  250. if(!empty($row['myviewmaxscore']) and $row['myviewmaxscore']>0)
  251. {
  252. $maxscore=$row['myviewmaxscore'];
  253. }
  254. elseif($row['myviewmaxscore'] === '')
  255. {
  256. $maxscore = 0;
  257. }
  258. else
  259. {
  260. $maxscore = $row['mymaxscore'];
  261. }
  262. }
  263. else
  264. {
  265. $maxscore = $row['mymaxscore'];
  266. }
  267. }
  268. //Remove "NaN" if any (@todo: locate the source of these NaN)
  269. $time = str_replace('NaN', '00'.$h.'00\'00"', $time);
  270. if (($lesson_status == 'completed') or ($lesson_status == 'passed')) {
  271. $color = 'green';
  272. } else {
  273. $color = 'black';
  274. }
  275. $mylanglist = array ('completed' => 'ScormCompstatus', 'incomplete' => 'ScormIncomplete', 'failed' => 'ScormFailed', 'passed' => 'ScormPassed', 'browsed' => 'ScormBrowsed', 'not attempted' => 'ScormNotAttempted',);
  276. $my_lesson_status = htmlentities(get_lang($mylanglist[$lesson_status]), ENT_QUOTES, $dokeos_charset);
  277. //$my_lesson_status = get_lang($mylanglist[$lesson_status]);
  278. if ($row['item_type'] != 'dokeos_chapter') {
  279. $output .= "<tr class='$oddclass'>\n"."<td></td>\n"."<td>$extend_attempt_link</td>\n".'<td colspan="3">'.htmlentities(get_lang('Attempt'), ENT_QUOTES, $dokeos_charset).' '.$row['iv_view_count']."</td>\n"
  280. //."<td><font color='$color'><div class='mystatus'>".htmlentities($array_status[$lesson_status],ENT_QUOTES,$charset_lang)."</div></font></td>\n"
  281. .'<td colspan="2"><font color="'.$color.'"><div class="mystatus">'.$my_lesson_status."</div></font></td>\n".'<td colspan="2"><div class="mystatus" align="center">'. ($score == 0 ? '-' : ($maxscore==0?$score:$score.'/'.$maxscore))."</div></td>\n".'<td colspan="2"><div class="mystatus">'.$time."</div></td><td></td>\n"."</tr>\n";
  282. }
  283. $counter ++;
  284. if ($extend_this_attempt OR $extend_all) {
  285. $list1 = learnpath :: get_iv_interactions_array($row['iv_id']);
  286. foreach ($list1 as $id => $interaction) {
  287. if (($counter % 2) == 0) {
  288. $oddclass = "row_odd";
  289. } else {
  290. $oddclass = "row_even";
  291. }
  292. $output .= "<tr class='$oddclass'>\n".'<td></td>'."\n".'<td></td>'."\n".'<td>&nbsp;</td>'."\n".'<td>'.$interaction['order_id'].'</td>'."\n".'<td>'.$interaction['id'].'</td>'."\n"
  293. //."<td><font color='$color'><div class='mystatus'>".htmlentities($array_status[$lesson_status],ENT_QUOTES,$charset_lang)."</div></font></td>\n"
  294. .'<td colspan="2">'.$interaction['type']."</td>\n"
  295. //.'<td>'.$interaction['correct_responses']."</td>\n"
  296. .'<td>'.urldecode($interaction['student_response'])."</td>\n".'<td>'.$interaction['result']."</td>\n".'<td>'.$interaction['latency']."</td>\n".'<td>'.$interaction['time']."</td>\n<td></td>\n</tr>\n";
  297. $counter ++;
  298. }
  299. $list2 = learnpath :: get_iv_objectives_array($row['iv_id']);
  300. foreach ($list2 as $id => $interaction) {
  301. if (($counter % 2) == 0) {
  302. $oddclass = "row_odd";
  303. } else {
  304. $oddclass = "row_even";
  305. }
  306. $output .= "<tr class='$oddclass'>\n".'<td></td>'."\n".'<td></td>'."\n".'<td>&nbsp;</td>'."\n".'<td>'.$interaction['order_id'].'</td>'."\n".'<td colspan="2">'.$interaction['objective_id'].'</td>'."\n"
  307. .'<td colspan="2">'.$interaction['status']."</td>\n"
  308. .'<td>'.$interaction['score_raw']."</td>\n".'<td>'.$interaction['score_max']."</td>\n".'<td>'.$interaction['score_min']."</td>\n<td></td>\n</tr>\n";
  309. $counter ++;
  310. }
  311. }
  312. } while ($row = Database :: fetch_array($result));
  313. } elseif($num>0) {
  314. $row = Database :: fetch_array($result);
  315. //check if there are interactions below
  316. $extend_attempt_link = '';
  317. $extend_this_attempt = 0;
  318. $inter_num = learnpath :: get_interactions_count_from_db($row['iv_id']);
  319. $objec_num = learnpath :: get_objectives_count_from_db($row['iv_id']);
  320. if (($inter_num > 0 || $objec_num > 0) && !$extend_all) {
  321. if (!empty ($_GET['extend_attempt_id']) && $_GET['extend_attempt_id'] == $row['iv_id']) {
  322. //the extend button for this attempt has been clicked
  323. $extend_this_attempt = 1;
  324. $extend_attempt_link = '<a href="'.api_get_self().'?action=stats&extend_id='.$my_item_id.'&fold_attempt_id='.$row['iv_id'].$url_suffix.'"><img src="../img/visible.gif" alt="fold_attempt_view" border="0"></a>'."\n";
  325. } else { //same case if fold_attempt_id is set, so not implemented explicitly
  326. //the extend button for this attempt has not been clicked
  327. $extend_attempt_link = '<a href="'.api_get_self().'?action=stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].$url_suffix.'"><img src="../img/invisible.gif" alt="extend_attempt_view" border="0"></a>'."\n";
  328. }
  329. }
  330. if (($counter % 2) == 0) {
  331. $oddclass = "row_odd";
  332. } else {
  333. $oddclass = "row_even";
  334. }
  335. //$extend_link = '<img src="../img/invisible.gif" alt="extend_disabled">';
  336. $extend_link = '';
  337. if ($inter_num > 1) {
  338. $extend_link = '<a href="'.api_get_self().'?action=stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].$url_suffix.'"><img src="../img/invisible.gif" alt="extend_view" border="0"></a>';
  339. }
  340. if (($counter % 2) == 0) {
  341. $oddclass = "row_odd";
  342. } else {
  343. $oddclass = "row_even";
  344. }
  345. $lesson_status = $row['mystatus'];
  346. $score = $row['myscore'];
  347. $subtotal_time = $row['mytime'];
  348. //if($row['mytime']==0){
  349. while ($tmp_row = Database :: fetch_array($result))
  350. {
  351. $subtotal_time += $tmp_row['mytime'];
  352. }
  353. //}
  354. $time_for_total = $subtotal_time;
  355. $time = learnpathItem :: get_scorm_time('js', $subtotal_time);
  356. $scoIdentifier = $row['myid'];
  357. $title = $row['mytitle'];
  358. $title = stripslashes(html_entity_decode($title,ENT_QUOTES, $dokeos_charset));
  359. if ($score == 0)
  360. {
  361. $maxscore = 0;
  362. }
  363. else
  364. {
  365. if($row['item_type'] == 'sco')
  366. {
  367. if(!empty($row['myviewmaxscore']) and $row['myviewmaxscore']>0)
  368. {
  369. $maxscore=$row['myviewmaxscore'];
  370. }
  371. elseif($row['myviewmaxscore'] === '')
  372. {
  373. $maxscore = 0;
  374. }
  375. else
  376. {
  377. $maxscore = $row['mymaxscore'];
  378. }
  379. }
  380. else
  381. {
  382. $maxscore = $row['mymaxscore'];
  383. }
  384. }
  385. if (empty ($title))
  386. {
  387. $title = rl_get_resource_name(api_get_course_id(), $lp_id, $row['myid']);
  388. }
  389. //Remove "NaN" if any (@todo: locate the source of these NaN)
  390. //$time = str_replace('NaN', '00'.$h.'00\'00"', $time);
  391. if (($lesson_status == 'completed') or ($lesson_status == 'passed')) {
  392. $color = 'green';
  393. } else {
  394. $color = 'black';
  395. }
  396. $mylanglist = array ('completed' => 'ScormCompstatus', 'incomplete' => 'ScormIncomplete', 'failed' => 'ScormFailed', 'passed' => 'ScormPassed', 'browsed' => 'ScormBrowsed', 'not attempted' => 'ScormNotAttempted',);
  397. $my_lesson_status = htmlentities(get_lang($mylanglist[$lesson_status]), ENT_QUOTES, $dokeos_charset);
  398. if ($row['item_type'] != 'dokeos_chapter') {
  399. if($row['item_type'] == 'quiz'){
  400. $correct_test_link = '';
  401. if($origin != 'tracking' && $origin != 'tracking_course'){
  402. $sql_last_attempt='SELECT exe_id FROM '.$tbl_stats_exercices.' WHERE exe_exo_id="'.$row['path'].'" AND exe_user_id="'.api_get_user_id().'" AND exe_cours_id="'.$course_code.'" ORDER BY exe_date ASC';
  403. }
  404. else{
  405. $sql_last_attempt='SELECT exe_id FROM '.$tbl_stats_exercices.' WHERE exe_exo_id="'.$row['path'].'" AND exe_user_id="'.Database::escape_string($_GET['student_id']).'" AND exe_cours_id="'.Database::escape_string($_GET['course']).'" ORDER BY exe_date';
  406. }
  407. $resultLastAttempt = api_sql_query($sql_last_attempt,__FILE__,__LINE__);
  408. $num = Database::num_rows($resultLastAttempt);
  409. if($num>0)
  410. {
  411. if($num>1)
  412. {
  413. $i = 1;
  414. while($rowLA = Database::fetch_array($resultLastAttempt))
  415. {
  416. $laid = $rowLA['exe_id'];
  417. if($origin != 'tracking')
  418. {
  419. $correct_test_link .= '<a href="../exercice/exercise_show.php?origin=student_progress&id='.$laid.'&cidReq='.$course_code.'" target="_parent" title="'.get_lang('Attempt').' '.$i.'"><img src="'.api_get_path(WEB_IMG_PATH).'quiz.gif"></a> ';
  420. }
  421. else
  422. {
  423. $correct_test_link .= '<a href="../exercice/exercise_show.php?origin=tracking_course&id='.$laid.'&cidReq='.Security::remove_XSS(Database::escape_string($_GET['course'])).'&student='.$_GET['student_id'].'" target="_parent" title="'.get_lang('Attempt').' '.$i.'"><img src="'.api_get_path(WEB_IMG_PATH).'quiz.gif"></a> ';
  424. }
  425. $i++;
  426. }
  427. $correct_test_link = substr($correct_test_link,0,-1);
  428. }
  429. else
  430. {
  431. $id_last_attempt=Database::result($resultLastAttempt,0,0);
  432. if($origin != 'tracking'){
  433. $correct_test_link = '<a href="../exercice/exercise_show.php?origin=student_progress&id='.$id_last_attempt.'&cidReq='.$course_code.'" target="_parent"><img src="'.api_get_path(WEB_IMG_PATH).'quiz.gif"></a>';
  434. }
  435. else{
  436. $correct_test_link = '<a href="../exercice/exercise_show.php?origin=tracking_course&id='.$id_last_attempt.'&cidReq='.Security::remove_XSS(Database::escape_string($_GET['course'])).'&student='.$_GET['student_id'].'" target="_parent"><img src="'.api_get_path(WEB_IMG_PATH).'quiz.gif"></a>';
  437. }
  438. }
  439. }
  440. else
  441. {
  442. $correct_test_link='-';
  443. }
  444. }
  445. else{
  446. $correct_test_link='-';
  447. }
  448. $output .= "<tr class='$oddclass'>\n"."<td>$extend_link</td>\n".'<td colspan="4"><div class="mystatus">'.htmlentities($title).'</div></td>'."\n"
  449. //."<td><font color='$color'><div class='mystatus'>".htmlentities($array_status[$lesson_status],ENT_QUOTES,$charset_lang)."</div></font></td>\n"
  450. .'<td colspan="2"><font color="'.$color.'"><div class="mystatus">'.$my_lesson_status."</div></font></td>\n".'<td colspan="2"><div class="mystatus" align="center">'. ($score == 0 ? '-' : ($maxscore==0?$score:$score.'/'.$maxscore))."</div></td>\n".'<td colspan="2"><div class="mystatus">'.$time."</div></td><td>$correct_test_link</td>\n"."</tr>\n";
  451. if($export_csv)
  452. {
  453. $temp = array();
  454. $temp[] = $title;
  455. $temp[] = html_entity_decode($my_lesson_status);
  456. $temp[] = ($score == 0 ? '-' : ($maxscore==0?$score:$score.'/'.$maxscore));
  457. $temp[] = $time;
  458. $csv_content[] = $temp;
  459. }
  460. }
  461. $counter ++;
  462. if ($extend_this_attempt OR $extend_all) {
  463. $list1 = learnpath :: get_iv_interactions_array($row['iv_id']);
  464. foreach ($list1 as $id => $interaction) {
  465. if (($counter % 2) == 0) {
  466. $oddclass = "row_odd";
  467. } else {
  468. $oddclass = "row_even";
  469. }
  470. $output .= "<tr class='$oddclass'>\n".'<td></td>'."\n".'<td></td>'."\n".'<td>&nbsp;</td>'."\n".'<td>'.$interaction['order_id'].'</td>'."\n".'<td>'.$interaction['id'].'</td>'."\n"
  471. //."<td><font color='$color'><div class='mystatus'>".htmlentities($array_status[$lesson_status],ENT_QUOTES,$charset_lang)."</div></font></td>\n"
  472. .'<td colspan="2">'.$interaction['type']."</td>\n"
  473. //.'<td>'.$interaction['correct_responses']."</td>\n"
  474. .'<td>'.urldecode($interaction['student_response'])."</td>\n".'<td>'.$interaction['result']."</td>\n".'<td>'.$interaction['latency']."</td>\n".'<td>'.$interaction['time']."</td>\n<td></td>\n</tr>\n";
  475. $counter ++;
  476. }
  477. $list2 = learnpath :: get_iv_objectives_array($row['iv_id']);
  478. foreach ($list2 as $id => $interaction) {
  479. if (($counter % 2) == 0) {
  480. $oddclass = "row_odd";
  481. } else {
  482. $oddclass = "row_even";
  483. }
  484. $output .= "<tr class='$oddclass'>\n".'<td></td>'."\n".'<td></td>'."\n".'<td>&nbsp;</td>'."\n".'<td>'.$interaction['order_id'].'</td>'."\n".'<td colspan="2">'.$interaction['objective_id'].'</td>'."\n"
  485. .'<td colspan="2">'.$interaction['status']."</td>\n"
  486. .'<td>'.$interaction['score_raw']."</td>\n".'<td>'.$interaction['score_max']."</td>\n".'<td>'.$interaction['score_min']."</td>\n<td></td>\n</tr>\n";
  487. $counter ++;
  488. }
  489. }
  490. }
  491. //only sum up the latest attempt each time
  492. $total_max_score += $maxscore;
  493. $total_score += $score;
  494. $total_time += $time_for_total;
  495. }
  496. $total_time = learnpathItem :: get_scorm_time('js', $total_time);
  497. //$total_time = str_replace('NaN','00:00:00',$total_time);
  498. $total_time = str_replace('NaN', '00'.$h.'00\'00"', $total_time);
  499. $lp_type = learnpath::get_type_static($lp_id);
  500. $total_percent = 0;
  501. $final_score = '0%';
  502. if($lp_type == 2) //if scorm
  503. {
  504. if($total_max_score == 0)
  505. {
  506. $total_percent = number_format((float) $total_score, 1, '.', '');
  507. $final_score = ($total_score == 0 ? '-' : $total_percent);
  508. }
  509. else
  510. {
  511. $total_percent = number_format((((float) $total_score / (float) $total_max_score) * 100), 1, '.', '');
  512. $final_score = ($total_score == 0 ? '-' : $total_percent.'%');
  513. }
  514. }
  515. else
  516. {
  517. if ($total_max_score == 0) {
  518. $total_max_score = 1;
  519. }
  520. $total_percent = number_format((((float) $total_score / (float) $total_max_score) * 100), 1, '.', '');
  521. $final_score = ($total_score == 0 ? '-' : $total_percent.'%');
  522. }
  523. if (($counter % 2) == 0) {
  524. $oddclass = "row_odd";
  525. } else {
  526. $oddclass = "row_even";
  527. }
  528. $output .= "<tr class='$oddclass'>\n"."<td></td>\n".'<td colspan="4"><div class="mystatus"><i>'.htmlentities(get_lang('AccomplishedStepsTotal'), ENT_QUOTES, $dokeos_charset)."</i></div></td>\n"
  529. //."<td><font color='$color'><div class='mystatus'>".htmlentities($array_status[$lesson_status],ENT_QUOTES,$charset_lang)."</div></font></td>\n"
  530. .'<td colspan="2"></td>'."\n".'<td colspan="2"><div class="mystatus" align="center">'. $final_score."</div></td>\n".'<td colspan="2"><div class="mystatus">'.$total_time.'</div></td><td></td>'."\n"."</tr>\n";
  531. $output .= "</table></td></tr></table>";
  532. if($export_csv)
  533. {
  534. $temp = array('','','','');
  535. $csv_content[] = $temp;
  536. $temp = array(get_lang('AccomplishedStepsTotal'),'',$final_score,$total_time);
  537. $csv_content[] = $temp;
  538. ob_end_clean();
  539. Export :: export_table_csv($csv_content, 'reporting_learning_path_details');
  540. }
  541. if($origin != 'tracking')
  542. {
  543. $output .= "</body></html>";
  544. }
  545. echo $output;
  546. ?>