lp_stats.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. <?php //$id:$
  2. /**
  3. * This script displays statistics on the current learning path (scorm)
  4. *
  5. * This script must be included by lp_controller.php to get basic initialisation
  6. * @package dokeos.learnpath
  7. * @author Yannick Warnier <ywarnier@beeznest.org>
  8. */
  9. /**
  10. * Handfull functions
  11. */
  12. /**
  13. * Return the number of interactions for the given learnpath Item View ID
  14. * @param integer Item View ID
  15. * @return integer Number of interactions
  16. */
  17. function get_interactions_count_from_db($lp_iv_id){
  18. $table = Database::get_course_table('lp_iv_interaction');
  19. $sql = "SELECT count(*) FROM $table WHERE lp_iv_id = $lp_iv_id";
  20. $res = api_sql_query($sql,__FILE__,__LINE__);
  21. $row = Database::fetch_array($res);
  22. $num = $row[0];
  23. return $num;
  24. }
  25. /**
  26. * Return the interactions as an array for the given lp_iv_id
  27. * @param integer Learnpath Item View ID
  28. * @return array
  29. */
  30. function get_iv_interactions_array($lp_iv_id){
  31. $list = array();
  32. $table = Database::get_course_table('lp_iv_interaction');
  33. $sql = "SELECT * FROM $table WHERE lp_iv_id = $lp_iv_id ORDER BY order_id ASC";
  34. $res = api_sql_query($sql,__FILE__,__LINE__);
  35. $num = Database::num_rows($res);
  36. if($num>0){
  37. $list[] = array(
  38. "order_id"=>'Order',
  39. "id"=>'Interaction ID',
  40. "type"=>'Type',
  41. "time"=>'Time (finished at ...)',
  42. "correct_responses"=>'Correct responses',
  43. "student_response"=>'Student response',
  44. "result"=>'Result',
  45. "latency"=>'Latency (time spent)');
  46. while ($row = Database::fetch_array($res)){
  47. $list[] = array(
  48. "order_id"=>($row['order_id']+1),
  49. "id"=>$row['interaction_id'],
  50. "type"=>$row['interaction_type'],
  51. "time"=>$row['completion_time'],
  52. //"correct_responses"=>$row['correct_responses'],
  53. //hide correct responses from students
  54. "correct_responses"=>'',
  55. "student_response"=>$row['student_response'],
  56. "result"=>$row['result'],
  57. "latency"=>$row['latency']);
  58. }
  59. }
  60. return $list;
  61. }
  62. /**
  63. * Script
  64. */
  65. //require_once('learnpath.class.php');
  66. //require_once('scorm.class.php');
  67. require_once('resourcelinker.inc.php');
  68. if(isset($_SESSION['lpobject'])){
  69. $temp = $_SESSION['lpobject'];
  70. $_SESSION['oLP'] = unserialize($temp);
  71. }
  72. if(is_object($_SESSION['oLP'])){
  73. $charset_lang = $_SESSION['oLP']->encoding;
  74. }else{
  75. $charset_lang = 'ISO-8859-1';
  76. }
  77. $dokeos_charset = 'ISO-8859-1';
  78. $charset = $charset_lang;
  79. $w=$tablewidth-20;
  80. $htmlHeadXtra[] = '' .
  81. '<style type="text/css" media="screen, projection">
  82. /*<![CDATA[*/
  83. @import "../css/default/scorm.css";
  84. /*]]>*/
  85. </style>';
  86. include_once('../inc/reduced_header.inc.php');
  87. echo '<body>';
  88. //if display in fullscreen required
  89. if (strcmp($_GET["fs"],"true")==0)
  90. { $output .= "<table align='center'>"; }
  91. else
  92. { $output .= "<table class='margin_table'>"; }
  93. //check if the user asked for the "extend all" option
  94. $extend_all_link = '';
  95. $extend_all = 0;
  96. if(!empty($_GET['extend_all'])){
  97. $extend_all_link = '<a href="lp_controller.php?action=stats"><img src="../img/visible.gif" alt="fold_view" border="0"></a>';
  98. $extend_all = 1;
  99. }else{
  100. $extend_all_link = '<a href="lp_controller.php?action=stats&extend_all=1"><img src="../img/invisible.gif" alt="extend_view" border="0"></a>';
  101. }
  102. $output .="<tr><td><div class='title'>".htmlentities(get_lang('ScormMystatus'),ENT_QUOTES,$dokeos_charset)."</div></td></tr>"
  103. ."<tr><td>&nbsp;</td></tr>"
  104. ."<tr><td>"
  105. ."<table border='0' class='data_table'><tr>\n"
  106. .'<td width="16">'.$extend_all_link.'</td>'
  107. .'<td colspan="4" class="title"><div class="mystatusfirstrow">'.htmlentities(get_lang('ScormLessonTitle'),ENT_QUOTES,$dokeos_charset)."</div></td>\n"
  108. .'<td colspan="2" class="title"><div class="mystatusfirstrow">'.htmlentities(get_lang('ScormStatus'),ENT_QUOTES,$dokeos_charset)."</div></td>\n"
  109. .'<td colspan="2" class="title"><div class="mystatusfirstrow">'.htmlentities(get_lang('ScormScore'),ENT_QUOTES,$dokeos_charset)."</div></td>\n"
  110. .'<td colspan="2" class="title"><div class="mystatusfirstrow">'.htmlentities(get_lang('ScormTime'),ENT_QUOTES,$dokeos_charset)."</div></td></tr>\n";
  111. //going through the items using the $items[] array instead of the database order ensures
  112. // we get them in the same order as in the imsmanifest file, which is rather random when using
  113. // the database table
  114. $TBL_LP_ITEM = Database::get_course_table('lp_item');
  115. $TBL_LP_ITEM_VIEW = Database::get_course_table('lp_item_view');
  116. $TBL_LP_VIEW = Database::get_course_table('lp_view');
  117. $lp_id = $_SESSION['oLP']->get_id();
  118. $list = $_SESSION['oLP']->get_flat_ordered_items_list($lp_id);
  119. $sql = "SELECT max(view_count) FROM $TBL_LP_VIEW WHERE lp_id = $lp_id AND user_id = $_uid";
  120. $res = api_sql_query($sql,__FILE__,__LINE__);
  121. $view = '';
  122. if(Database::num_rows($res)>0){
  123. $myrow = Database::fetch_array($res);
  124. $view = $myrow[0];
  125. }
  126. $counter = 0;
  127. //error_log('New LP - Querying views for latest attempt: '.$sql,0);
  128. $total_score=0;
  129. $total_max_score=0;
  130. $total_time=0;
  131. $h = get_lang('h');
  132. foreach($list as $my_item_id){
  133. $extend_this = 0;
  134. $qry_order = 'DESC';
  135. if((!empty($_GET['extend_id']) and $_GET['extend_id'] == $my_item_id) OR $extend_all){
  136. $extend_this = 1;
  137. $qry_order = 'ASC';
  138. }
  139. if(!empty($view)){
  140. $sql="SELECT iv.status as mystatus, v.view_count as mycount, iv.score as myscore, iv.total_time as mytime, i.id as myid, i.title as mytitle, i.max_score as mymaxscore, iv.view_count as iv_view_count, iv.id as iv_id " .
  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 = $_uid " .
  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, iv.score as myscore, iv.total_time as mytime, i.id as myid, i.title as mytitle, i.max_score as mymaxscore, iv.view_count as iv_view_count, iv.id as iv_id " .
  151. " FROM $TBL_LP_ITEM as i, $TBL_LP_ITEM_VIEW as iv, $TBL_LP_VIEW as v " .
  152. " WHERE i.id = iv.lp_item_id " .
  153. " AND i.id = $my_item_id " .
  154. " AND iv.lp_view_id = v.id " .
  155. " AND i.lp_id = $lp_id " .
  156. " AND v.user_id = $_uid ".
  157. " ORDER BY iv.view_count $qry_order ";
  158. }
  159. $result = api_sql_query($sql,__FILE__,__LINE__);
  160. $num = Database::num_rows($result);
  161. $time_for_total = 'NaN';
  162. if(($extend_this OR $extend_all) && $num>0){
  163. $row = Database::fetch_array($result);
  164. //if there are several attempts, and the link to extend has been clicked...
  165. if (($counter % 2)==0) { $oddclass="row_odd"; } else { $oddclass="row_even"; }
  166. if($inter_num)
  167. $extend_link = '<a href="lp_controller.php?action=stats&fold_id='.$my_item_id.'"><img src="../img/visible.gif" alt="fold_view" border="0"></a>'."\n";
  168. $title=$row['mytitle'];
  169. if(empty($title)){
  170. $title = rl_get_resource_name(api_get_course_id(),$lp_id,$row['myid']);
  171. }
  172. $output .= "<tr class='$oddclass'>\n"
  173. ."<td>$extend_link</td>\n"
  174. .'<td colspan="4" class="content"><div class="mystatus">'.$title."</div></td>\n"
  175. .'<td colspan="2" class="content"></td>'."\n"
  176. .'<td colspan="2" class="content"></td>'."\n"
  177. .'<td colspan="2" class="content"></td>'."\n"
  178. ."</tr>\n";
  179. $counter ++;
  180. do{
  181. //check if there are interactions below
  182. $extend_attempt_link = '';
  183. $extend_this_attempt = 0;
  184. if(get_interactions_count_from_db($row['iv_id'])>0 && !$extend_all){
  185. if(!empty($_GET['extend_attempt_id']) && $_GET['extend_attempt_id'] == $row['iv_id'] ){
  186. //the extend button for this attempt has been clicked
  187. $extend_this_attempt = 1;
  188. $extend_attempt_link = '<a href="lp_controller.php?action=stats&extend_id='.$my_item_id.'&fold_attempt_id='.$row['iv_id'].'"><img src="../img/visible.gif" alt="fold_attempt_view" border="0"></a>'."\n";
  189. }else{ //same case if fold_attempt_id is set, so not implemented explicitly
  190. //the extend button for this attempt has not been clicked
  191. $extend_attempt_link = '<a href="lp_controller.php?action=stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].'"><img src="../img/invisible.gif" alt="extend_attempt_view" border="0"></a>'."\n";
  192. }
  193. }
  194. if (($counter % 2)==0) { $oddclass="row_odd"; } else { $oddclass="row_even"; }
  195. $lesson_status=$row['mystatus'];
  196. $score=$row['myscore'];
  197. $time_for_total = $row['mytime'];
  198. $time=learnpathItem::get_scorm_time('php',$row['mytime']);
  199. $scoIdentifier=$row['myid'];
  200. if($score==0){
  201. $maxscore = 0;
  202. }else{
  203. $maxscore = $row['mymaxscore'];
  204. }
  205. //Remove "NaN" if any (@todo: locate the source of these NaN)
  206. $time = str_replace('NaN','00'.$h.'00\'00"',$time);
  207. if (($lesson_status=='completed') or ($lesson_status=='passed')) { $color='green'; } else { $color='black'; }
  208. $mylanglist = array(
  209. 'completed' => 'ScormCompstatus',
  210. 'incomplete'=> 'ScormIncomplete',
  211. 'failed' => 'ScormFailed',
  212. 'passed' => 'ScormPassed',
  213. 'browsed' => 'ScormBrowsed',
  214. 'not attempted' => 'ScormNotAttempted',
  215. );
  216. $my_lesson_status = htmlentities(get_lang($mylanglist[$lesson_status]),ENT_QUOTES,$dokeos_charset);
  217. //$my_lesson_status = get_lang($mylanglist[$lesson_status]);
  218. $output .= "<tr class='$oddclass'>\n"
  219. ."<td></td>\n"
  220. ."<td>$extend_attempt_link</td>\n"
  221. .'<td colspan="3">Attempt '.$row['iv_view_count']."</td>\n"
  222. //."<td><font color='$color'><div class='mystatus'>".htmlentities($array_status[$lesson_status],ENT_QUOTES,$charset_lang)."</div></font></td>\n"
  223. .'<td colspan="2"><font color="'.$color.'"><div class="mystatus">'.$my_lesson_status."</div></font></td>\n"
  224. .'<td colspan="2"><div class="mystatus" align="center">'.($score==0?'-':$score.'/'.$maxscore)."</div></td>\n"
  225. .'<td colspan="2"><div class="mystatus">'.$time."</div></td>\n"
  226. ."</tr>\n";
  227. $counter ++;
  228. if($extend_this_attempt OR $extend_all){
  229. $list = get_iv_interactions_array($row['iv_id']);
  230. foreach($list as $id=>$interaction)
  231. {
  232. if (($counter % 2)==0) { $oddclass="row_odd"; } else { $oddclass="row_even"; }
  233. $output .= "<tr class='$oddclass'>\n"
  234. .'<td></td>'."\n"
  235. .'<td></td>'."\n"
  236. .'<td>&nbsp;</td>'."\n"
  237. .'<td>'.$interaction['order_id'].'</td>'."\n"
  238. .'<td>'.$interaction['id'].'</td>'."\n"
  239. //."<td><font color='$color'><div class='mystatus'>".htmlentities($array_status[$lesson_status],ENT_QUOTES,$charset_lang)."</div></font></td>\n"
  240. .'<td colspan="2">'.$interaction['type']."</td>\n"
  241. //.'<td>'.$interaction['correct_responses']."</td>\n"
  242. .'<td>'.$interaction['student_response']."</td>\n"
  243. .'<td>'.$interaction['result']."</td>\n"
  244. .'<td>'.$interaction['latency']."</td>\n"
  245. .'<td>'.$interaction['time']."</td>\n"
  246. ."</tr>\n";
  247. $counter ++;
  248. }
  249. }
  250. }while($row = Database::fetch_array($result));
  251. }else{
  252. $row = Database::fetch_array($result);
  253. //check if there are interactions below
  254. $extend_attempt_link = '';
  255. $extend_this_attempt = 0;
  256. $inter_num = get_interactions_count_from_db($row['iv_id']);
  257. if($inter_num>0 && !$extend_all){
  258. if(!empty($_GET['extend_attempt_id']) && $_GET['extend_attempt_id'] == $row['iv_id'] ){
  259. //the extend button for this attempt has been clicked
  260. $extend_this_attempt = 1;
  261. $extend_attempt_link = '<a href="lp_controller.php?action=stats&extend_id='.$my_item_id.'&fold_attempt_id='.$row['iv_id'].'"><img src="../img/visible.gif" alt="fold_attempt_view" border="0"></a>'."\n";
  262. }else{ //same case if fold_attempt_id is set, so not implemented explicitly
  263. //the extend button for this attempt has not been clicked
  264. $extend_attempt_link = '<a href="lp_controller.php?action=stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].'"><img src="../img/invisible.gif" alt="extend_attempt_view" border="0"></a>'."\n";
  265. }
  266. }
  267. if (($counter % 2)==0) { $oddclass="row_odd"; } else { $oddclass="row_even"; }
  268. //$extend_link = '<img src="../img/invisible.gif" alt="extend_disabled">';
  269. $extend_link = '';
  270. if($inter_num>1){
  271. $extend_link = '<a href="lp_controller.php?action=stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].'"><img src="../img/invisible.gif" alt="extend_view" border="0"></a>';
  272. }
  273. if (($counter % 2)==0) { $oddclass="row_odd"; } else { $oddclass="row_even"; }
  274. $lesson_status=$row['mystatus'];
  275. $score=$row['myscore'];
  276. $time_for_total = $row['mytime'];
  277. $time=learnpathItem::get_scorm_time('php',$row['mytime']);
  278. $scoIdentifier=$row['myid'];
  279. $title=$row['mytitle'];
  280. if($score==0){
  281. $maxscore = 0;
  282. }else{
  283. $maxscore = $row['mymaxscore'];
  284. }
  285. if(empty($title)){
  286. $title = rl_get_resource_name(api_get_course_id(),$lp_id,$row['myid']);
  287. }
  288. //Remove "NaN" if any (@todo: locate the source of these NaN)
  289. $time = str_replace('NaN','00'.$h.'00\'00"',$time);
  290. if (($lesson_status=='completed') or ($lesson_status=='passed')) { $color='green'; } else { $color='black'; }
  291. $mylanglist = array(
  292. 'completed' => 'ScormCompstatus',
  293. 'incomplete'=> 'ScormIncomplete',
  294. 'failed' => 'ScormFailed',
  295. 'passed' => 'ScormPassed',
  296. 'browsed' => 'ScormBrowsed',
  297. 'not attempted' => 'ScormNotAttempted',
  298. );
  299. $my_lesson_status = htmlentities(get_lang($mylanglist[$lesson_status]),ENT_QUOTES,$dokeos_charset);
  300. $output .= "<tr class='$oddclass'>\n"
  301. ."<td>$extend_link</td>\n"
  302. .'<td colspan="4"><div class="mystatus">'.$title.'</div></td>'."\n"
  303. //."<td><font color='$color'><div class='mystatus'>".htmlentities($array_status[$lesson_status],ENT_QUOTES,$charset_lang)."</div></font></td>\n"
  304. .'<td colspan="2"><font color="'.$color.'"><div class="mystatus">'.$my_lesson_status."</div></font></td>\n"
  305. .'<td colspan="2"><div class="mystatus" align="center">'.($score==0?'-':$score.'/'.$maxscore)."</div></td>\n"
  306. .'<td colspan="2"><div class="mystatus">'.$time."</div></td>\n"
  307. ."</tr>\n";
  308. $counter ++;
  309. if($extend_this_attempt OR $extend_all){
  310. $list = get_iv_interactions_array($row['iv_id']);
  311. foreach($list as $id=>$interaction)
  312. {
  313. if (($counter % 2)==0) { $oddclass="row_odd"; } else { $oddclass="row_even"; }
  314. $output .= "<tr class='$oddclass'>\n"
  315. .'<td></td>'."\n"
  316. .'<td></td>'."\n"
  317. .'<td>&nbsp;</td>'."\n"
  318. .'<td>'.$interaction['order_id'].'</td>'."\n"
  319. .'<td>'.$interaction['id'].'</td>'."\n"
  320. //."<td><font color='$color'><div class='mystatus'>".htmlentities($array_status[$lesson_status],ENT_QUOTES,$charset_lang)."</div></font></td>\n"
  321. .'<td colspan="2">'.$interaction['type']."</td>\n"
  322. //.'<td>'.$interaction['correct_responses']."</td>\n"
  323. .'<td>'.$interaction['student_response']."</td>\n"
  324. .'<td>'.$interaction['result']."</td>\n"
  325. .'<td>'.$interaction['latency']."</td>\n"
  326. .'<td>'.$interaction['time']."</td>\n"
  327. ."</tr>\n";
  328. $counter ++;
  329. }
  330. }
  331. }
  332. //only sum up the latest attempt each time
  333. $total_max_score += $maxscore;
  334. $total_score += $score;
  335. $total_time += $time_for_total;
  336. }
  337. $total_time = learnpathItem::get_scorm_time('php',$total_time);
  338. //$total_time = str_replace('NaN','00:00:00',$total_time);
  339. $total_time = str_replace('NaN','00'.$h.'00\'00"',$total_time);
  340. if($total_max_score==0){$total_max_score=1;}
  341. $total_percent = number_format((((float)$total_score/(float)$total_max_score)*100),1,'.','');
  342. if (($counter % 2)==0) { $oddclass="row_odd"; } else { $oddclass="row_even"; }
  343. $output .= "<tr class='$oddclass'>\n"
  344. ."<td></td>\n"
  345. .'<td colspan="4"><div class="mystatus"><i>'.htmlentities(get_lang('AccomplishedStepsTotal'),ENT_QUOTES,$dokeos_charset)."</i></div></td>\n"
  346. //."<td><font color='$color'><div class='mystatus'>".htmlentities($array_status[$lesson_status],ENT_QUOTES,$charset_lang)."</div></font></td>\n"
  347. .'<td colspan="2"></td>'."\n"
  348. .'<td colspan="2"><div class="mystatus" align="center">'.($total_score==0?'-':$total_percent.'%')."</div></td>\n"
  349. .'<td colspan="2"><div class="mystatus">'.$total_time.'</div></td>'."\n"
  350. ."</tr>\n";
  351. $output .= "</table></td></tr></table>";
  352. $output .= "</body></html>";
  353. echo $output;
  354. ?>