/** * convert a duration in seconds to a human readable duration * @author Sebastien Piraux <*****@*****.**> * @param integer duration time in seconds to convert to a human readable duration */ function claro_disp_duration($duration) { pushClaroMessage((function_exists('claro_html_debug_backtrace') ? claro_html_debug_backtrace() : 'claro_html_debug_backtrace() not defined') . 'claro_ disp _duration() is deprecated , use claro_ html _duration()', 'error'); return claro_html_duration($duration); }
protected function renderContent() { if (isset($_REQUEST['exId']) && is_numeric($_REQUEST['exId'])) { $exId = (int) $_REQUEST['exId']; } else { $exId = null; } $exerciseResults = $this->prepareContent(); $jsloader = JavascriptLoader::getInstance(); $jsloader->load('jquery'); $context = array('cidReq' => $this->courseId, 'cidReset' => true, 'userId' => $this->userId); $html = '<script language="javascript" type="text/javascript">' . "\n" . ' $(document).ready(function() {' . ' $(\'.exerciseDetails\').hide();' . ' $(\'.exerciseDetailsToggle\').click( function()' . ' {' . ' $(this).next(".exerciseDetails").toggle();' . ' return false;' . ' });' . ' });' . '</script>' . "\n\n"; $html .= '<table class="claroTable emphaseLine" cellpadding="2" cellspacing="1" border="0" align="center" style="width: 99%;">' . "\n" . '<thead>' . "\n" . '<tr class="headerX">' . "\n" . '<th>' . get_lang('Exercises') . '</th>' . "\n" . '<th>' . get_lang('Worst score') . '</th>' . "\n" . '<th>' . get_lang('Best score') . '</th>' . "\n" . '<th>' . get_lang('Average score') . '</th>' . "\n" . '<th>' . get_lang('Average Time') . '</th>' . "\n" . '<th>' . get_lang('Attempts') . '</th>' . "\n" . '<th>' . get_lang('Last attempt') . '</th>' . "\n" . '</tr>' . "\n" . '</thead>' . "\n"; if (!empty($exerciseResults) && is_array($exerciseResults)) { $html .= '<tbody>' . "\n"; foreach ($exerciseResults as $result) { $html .= '<tr class="exerciseDetailsToggle">' . "\n" . '<td><a href="#">' . claro_htmlspecialchars($result['title']) . '</td>' . "\n" . '<td>' . (int) $result['minimum'] . '</td>' . "\n" . '<td>' . (int) $result['maximum'] . '</td>' . "\n" . '<td>' . round($result['average'] * 10) / 10 . '</td>' . "\n" . '<td>' . claro_html_duration(floor($result['avgTime'])) . '</td>' . "\n" . '<td>' . (int) $result['attempts'] . '</td>' . "\n" . '<td>' . claro_html_localised_date(get_locale('dateTimeFormatLong'), strtotime($result['lastAttempt'])) . "</td> \n"; $html .= '</tr>' . "\n"; // details $exerciseDetails = $this->getUserExerciceDetails($result['id']); if (is_array($exerciseDetails) && !empty($exerciseDetails)) { $html .= '<tr class="exerciseDetails" >'; if (claro_is_course_manager()) { $html .= '<td><a href="' . claro_htmlspecialchars(Url::Contextualize(get_module_url('CLQWZ') . '/track_exercise_reset.php?cmd=resetAllAttemptsForUser&exId=' . $result['id'], $context)) . '">' . get_lang('delete all') . '</a></td>'; } else { $html .= '<td> </td>' . "\n"; } $html .= '<td colspan="6" class="noHover">' . "\n" . '<table class="claroTable emphaseLine" cellspacing="1" cellpadding="2" border="0" width="100%" style="width: 99%;">' . "\n" . '<thead>' . "\n"; $html .= '' . '<tr>' . "\n" . '<th><small>' . get_lang('Date') . '</small></th>' . "\n" . '<th><small>' . get_lang('Score') . '</small></th>' . "\n" . '<th><small>' . get_lang('Time') . '</small></th>' . "\n" . '<th><small>' . get_lang('Delete') . '</small></th>' . "\n" . '</tr>' . "\n" . '</thead>' . "\n" . '<tbody>' . "\n"; foreach ($exerciseDetails as $details) { $html .= '<tr>' . "\n" . '<td><small>' . "\n" . '<a href="' . get_module_url('CLQWZ') . '/track_exercise_details.php?trackedExId=' . $details['id'] . '">' . claro_html_localised_date(get_locale('dateTimeFormatLong'), strtotime($details['date'])) . '</a></small></td>' . "\n" . '<td><small>' . $details['result'] . '/' . $details['weighting'] . '</small></td>' . "\n" . '<td><small>' . claro_html_duration($details['time']) . '</small></td>' . "\n"; if (claro_is_course_manager()) { $html .= '<td><small><a href="' . claro_htmlspecialchars(Url::Contextualize(get_module_url('CLQWZ') . '/track_exercise_reset.php?cmd=resetAttemptForUser&trackId=' . $details['id'], $context)) . '">' . get_lang('delete') . '</a></small></td>' . "\n"; } else { $html .= '<td><small>-</small></td>'; } $html .= '</tr>' . "\n"; } $html .= '</tbody>' . "\n" . '</table>' . "\n\n" . '</td>' . "\n" . '</tr>' . "\n"; } } $html .= '</tbody>' . "\n"; } else { $html .= '<tbody>' . "\n" . '<tr>' . "\n" . '<td colspan="7" align="center">' . get_lang('No result') . '</td>' . "\n" . '</tr>' . "\n" . '</tbody>' . "\n"; } $html .= '</table>' . "\n\n"; return $html; }
/** * Builds the csv export * @return a string in csv format */ public function buildCsv() { $tbl_mdb_names = claro_sql_get_main_tbl(); $tbl_cdb_names = get_module_course_tbl(array('qwz_exercise', 'qwz_tracking'), claro_get_current_course_id()); $tbl_user = $tbl_mdb_names['user']; $tbl_rel_course_user = $tbl_mdb_names['rel_course_user']; $tbl_qwz_exercise = $tbl_cdb_names['qwz_exercise']; $tbl_qwz_tracking = $tbl_cdb_names['qwz_tracking']; $sql = "SELECT\n `U`.`prenom` AS `firstname`,\n `U`.`nom` AS `lastname`,\n MIN(TE.`result`) AS `minimum`,\n MAX(TE.`result`) AS `maximum`,\n AVG(TE.`result`) AS `average`,\n COUNT(TE.`result`) AS `attempts`,\n AVG(TE.`time`) AS `avgTime`\n FROM\n (`" . $tbl_user . "` AS `U`,\n `" . $tbl_rel_course_user . "` AS `CU`,\n `" . $tbl_qwz_exercise . "` AS `QT`)\n LEFT JOIN\n `" . $tbl_qwz_tracking . "` AS `TE`\n ON `CU`.`user_id` = `TE`.`user_id`\n AND `QT`.`id` = `TE`.`exo_id`\n WHERE `CU`.`user_id` = `U`.`user_id`\n AND `CU`.`code_cours` = '" . claro_sql_escape(claro_get_current_course_id()) . "'\n AND (\n `TE`.`exo_id` = " . claro_sql_escape($this->exId) . "\n OR\n `TE`.`exo_id` IS NULL\n )\n GROUP BY `U`.`user_id`\n ORDER BY `lastname` DESC, `firstname` DESC"; // !!!! we have to order by lastname and firstname DESC because of the array_reverse below $csvDatas = claro_sql_query_fetch_all($sql); $i = 0; foreach ($csvDatas as $csvLine) { if ($csvLine['attempts'] == 0) { $csvDatas[$i]['minimum'] = '-'; $csvDatas[$i]['maximum'] = '-'; $csvDatas[$i]['average'] = '-'; $csvDatas[$i]['avgTime'] = '-'; } else { $csvDatas[$i]['average'] = (double) (round($csvLine['average'] * 100) / 100); $csvDatas[$i]['avgTime'] = claro_html_duration(floor($csvLine['avgTime'])); } $i++; } $csvDatas[] = array('firstname' => get_lang('First name'), 'lastname' => get_lang('Last name'), 'minimum' => get_lang('Worst score'), 'maximum' => get_lang('Best score'), 'average' => get_lang('Average score'), 'attempts' => get_lang('Attempts'), 'avgTime' => get_lang('Average Time')); $this->recordList = array_reverse($csvDatas); return $this->export(); }
$out .= '</p>' . "\n\n"; $tempView = $view; $levelView++; $out .= '<p>' . "\n"; if ('1' == $view[$levelView]) { $tempView[$levelView] = '0'; //-- Courses with unexisting users registered : courses that have users not registered on the platform $out .= '- ' . ' ' . '<b>' . get_lang('Courses with unexisting users registered') . '</b>' . ' ' . '<small>' . '[<a href="' . $_SERVER['PHP_SELF'] . '?view=' . $tempView . '">' . get_lang('Close') . '</a>]' . '</small>' . '<br />' . "\n"; if (false === ($datagrid[$levelView] = $Cache_Lite->get($levelView))) { $sql = "\n SELECT concat('(',cu.code_cours,') <br />', c.administrativeNumber,' : ',c.intitule) course,\n cu.user_id AS user_id\n FROM `" . $tbl_rel_course_user . "` AS cu\n INNER JOIN `" . $tbl_course . "` AS c\n ON c.code = cu.code_cours\n LEFT JOIN `" . $tbl_user . "` AS u\n ON u.user_id = cu.user_id\n WHERE u.user_id is null\n ORDER BY user_id\n LIMIT 100"; $option['colTitleList'] = array('code', 'count'); $data = claro_sql_query_fetch_all($sql); if (!is_array($data) || 0 == sizeof($data)) { $dg->set_colTitleList(array(get_lang('Code'), get_lang('Total'))); } $dg->set_grid($data); $datagrid[$levelView] = $dg->render(); $Cache_Lite->save($datagrid[$levelView], $levelView); } $out .= $datagrid[$levelView] . '<small>' . get_lang('Last computing') . ' ' . claro_html_localised_date(get_locale('dateTimeFormatLong') . ':%S', $Cache_Lite->lastModified()) . ', ' . get_lang('%delay ago', array('%delay' => claro_html_duration(time() - $Cache_Lite->lastModified()))) . '</small>' . '<br />'; } else { $tempView[$levelView] = '1'; $out .= '+' . ' ' . '<a href="' . $_SERVER['PHP_SELF'] . '?view=' . $tempView . '">' . get_lang('Courses with unexisting users registered') . '</a>'; } $out .= '</p>' . "\n\n"; break; default: trigger_error('display (' . $display . ') unknown', E_USER_NOTICE); } $claroline->display->body->appendContent($out); echo $claroline->display->render();
// required by getGrade and getQuestionFeedbackHtml $question->answer->extractResponseFromTracking($trackedQuestion['trackId']); $questionResult[$i] = $question->answer->gradeResponse(); $questionGrade[$i] = $question->getGrade(); // sum of score $totalResult += $questionResult[$i]; $totalGrade += $questionGrade[$i]; // save question object in a list to reuse it later $questionList[$i] = $question; $i++; } // else skip question } // display // display infos about the details ... $out .= '<ul>' . "\n" . '<li>' . get_lang('Last name') . ' : ' . $thisAttemptDetails['lastname'] . '</li>' . "\n" . '<li>' . get_lang('First name') . ' : ' . $thisAttemptDetails['firstname'] . '</li>' . "\n" . '<li>' . get_lang('Date') . ' : ' . claro_html_localised_date(get_locale('dateTimeFormatLong'), $thisAttemptDetails['unix_exe_date']) . '</li>' . "\n" . '<li>' . get_lang('Score') . ' : ' . $thisAttemptDetails['result'] . '/' . $thisAttemptDetails['weighting'] . '</li>' . "\n" . '<li>' . get_lang('Time') . ' : ' . claro_html_duration($thisAttemptDetails['time']) . '</li>' . "\n" . '</ul>' . "\n\n"; $out .= "\n" . '<table width="100%" border="0" cellpadding="1" cellspacing="0" class="claroTable">' . "\n\n"; if (!empty($questionList)) { // foreach question $questionIterator = 1; $i = 0; foreach ($questionList as $question) { $out .= '<thead>' . '<tr>' . "\n" . '<th>' . get_lang('Question') . ' ' . $questionIterator . '</th>' . "\n" . '</tr>' . "\n" . '</thead>' . "\n"; $out .= '<tr>' . '<td>' . "\n"; $out .= $question->getQuestionFeedbackHtml(); $out .= '</td>' . "\n" . '</tr>' . "\n\n" . '<tr>' . '<td align="right">' . "\n" . '<strong>' . get_lang('Score') . ' : ' . $questionResult[$i] . '/' . $questionGrade[$i] . '</strong>' . '</td>' . "\n" . '</tr>' . "\n\n"; $questionIterator++; $i++; } } $out .= '</table>' . "\n\n";
} $out .= '</div>' . "\n"; if (!$inLP) { $out .= '</form>' . "\n\n"; } } elseif ($showSubmitForm) { // check if cmdBack or cmdNext can be performed (time limit) $displayForm = true; if (isset($_REQUEST['cmdBack']) || isset($_REQUEST['cmdNext'])) { $timeToCompleteExe = $currentTime; // the time limit is set and the user take too much time to complete exercice if ($exercise->getTimeLimit() > 0 && $exercise->getTimeLimit() < $timeToCompleteExe) { $displayForm = false; unset($_SESSION['exeStartTime']); $contentDialogBox = ''; $contentDialogBox .= get_lang('Your time is %time', array('%time' => claro_html_duration($timeToCompleteExe))) . '<br />' . "\n"; $contentDialogBox .= get_lang('Time is over, results not submitted.'); $dialogBox->error($contentDialogBox); $dialogBox->info('<a href="' . claro_htmlspecialchars(Url::Contextualize('./exercise.php')) . '"><< ' . get_lang('Back') . '</a>'); } } //-- question(s) if (!empty($questionList) && $displayForm) { // form header, table header $out .= '<form id="formExercise" method="post" action="./exercise_submit.php' . ($inLP ? '?calledFrom=CLLP&embedded=true' : '') . '">' . "\n" . claro_form_relay_context() . "\n"; if ($exercise->getDisplayType() == 'SEQUENTIAL') { $out .= '<input type="hidden" name="step" value="' . $step . '" />' . "\n"; } $out .= "\n" . '<table width="100%" border="0" cellpadding="1" cellspacing="0" class="claroTable">' . "\n\n"; // foreach question $questionIterator = 0;
//-- display details : USERS VIEW $sql = "SELECT `U`.`nom`, `U`.`prenom`, `U`.`user_id`,\n MIN(TE.`result`) AS `minimum`,\n MAX(TE.`result`) AS `maximum`,\n AVG(TE.`result`) AS `average`,\n COUNT(TE.`result`) AS `attempts`,\n AVG(TE.`time`) AS `avgTime`\n FROM (`" . $tbl_user . "` AS `U`, `" . $tbl_rel_course_user . "` AS `CU`, `" . $tbl_qwz_exercise . "` AS `QT`)\n LEFT JOIN `" . $tbl_qwz_tracking . "` AS `TE`\n ON `CU`.`user_id` = `TE`.`user_id`\n AND `QT`.`id` = `TE`.`exo_id`\n WHERE `CU`.`user_id` = `U`.`user_id`\n AND `CU`.`code_cours` = '" . claro_sql_escape(claro_get_current_course_id()) . "'\n AND (\n `TE`.`exo_id` = " . (int) $exercise->getId() . "\n OR\n `TE`.`exo_id` IS NULL\n )\n GROUP BY `U`.`user_id`\n ORDER BY `U`.`nom` ASC, `U`.`prenom` ASC"; $exo_users_details = claro_sql_query_fetch_all($sql); $out .= '<p><b>' . get_lang('Statistics by user') . '</b> ' . '<a href="' . claro_htmlspecialchars(Url::Contextualize($_SERVER['PHP_SELF'] . '?exportCsv=2&exId=' . $exId)) . '">[' . get_lang('Export') . ']</a></p>' . "\n"; // display tab header $out .= '<table class="claroTable emphaseLine" width="100%" border="0" cellspacing="2">' . "\n\n" . '<thead>' . "\n" . '<tr align="center" valign="top">' . "\n" . '<th>' . get_lang('Student') . '</th>' . "\n" . '<th>' . get_lang('Worst score') . '</th>' . "\n" . '<th>' . get_lang('Best score') . '</th>' . "\n" . '<th>' . get_lang('Average score') . '</th>' . "\n" . '<th>' . get_lang('Attempts') . '</th>' . "\n" . '<th>' . get_lang('Average Time') . '</th>' . "\n" . '</tr>' . "\n" . '</thead>' . "\n" . '<tbody>' . "\n\n"; // display tab content foreach ($exo_users_details as $exo_users_detail) { if ($exo_users_detail['attempts'] == 0) { $exo_users_detail['minimum'] = '-'; $exo_users_detail['maximum'] = '-'; $displayedAverage = '-'; $displayedAvgTime = '-'; } else { $displayedAverage = round($exo_users_detail['average'] * 100) / 100; $displayedAvgTime = claro_html_duration(floor($exo_users_detail['avgTime'])); } $out .= '<tr>' . "\n" . '<td><a href="' . claro_htmlspecialchars(Url::Contextualize('../tracking/userReport.php?userId=' . $exo_users_detail['user_id'] . '&exId=' . $exercise->getId())) . '">' . "\n" . $exo_users_detail['nom'] . ' ' . $exo_users_detail['prenom'] . '</a></td>' . "\n" . '<td>' . $exo_users_detail['minimum'] . '</td>' . "\n" . '<td>' . $exo_users_detail['maximum'] . '</td>' . "\n" . '<td>' . $displayedAverage . '</td>' . "\n" . '<td>' . $exo_users_detail['attempts'] . '</td>' . "\n" . '<td>' . $displayedAvgTime . '</td>' . "\n" . '</tr>' . "\n\n"; } // foot of table $out .= '</tbody>' . "\n" . '</table>' . "\n\n"; // display details : QUESTIONS VIEW $sql = "SELECT `Q`.`id`, `Q`.`title`, `Q`.`type`, `Q`.`grade`,\n MIN(TED.`result`) AS `minimum`,\n MAX(TED.`result`) AS `maximum`,\n AVG(TED.`result`) AS `average`\n FROM (`" . $tbl_qwz_question . "` AS `Q`, `" . $tbl_qwz_rel_exercise_question . "` AS `RTQ`)\n LEFT JOIN `" . $tbl_qwz_tracking . "` AS `TE`\n ON `TE`.`exo_id` = `RTQ`.`exerciseId`\n LEFT JOIN `" . $tbl_qwz_tracking_questions . "` AS `TED`\n ON `TED`.`exercise_track_id` = `TE`.`id`\n AND `TED`.`question_id` = `Q`.`id`\n WHERE `Q`.`id` = `RTQ`.`questionId`\n AND `RTQ`.`exerciseId` = " . (int) $exercise->getId() . "\n GROUP BY `Q`.`id`\n ORDER BY `RTQ`.`rank` ASC"; $exo_questions_details = claro_sql_query_fetch_all($sql); $out .= '<p><b>' . get_lang('Statistics by question') . '</b> ' . "\n" . '<a href="' . claro_htmlspecialchars(Url::Contextualize($_SERVER['PHP_SELF'] . '?exportCsv=3&exId=' . $exId)) . '">[' . get_lang('Export') . ']</a></p>' . "\n"; // display tab header $out .= '<table class="claroTable emphaseLine" width="100%" border="0" cellspacing="2">' . "\n" . '<thead>' . "\n" . '<tr align="center" valign="top">' . "\n" . '<th>' . get_lang('Question title') . '</th>' . "\n" . '<th>' . get_lang('Worst score') . '</th>' . "\n" . '<th>' . get_lang('Best score') . '</th>' . "\n" . '<th>' . get_lang('Average score') . '</th>' . "\n" . '</tr>' . "\n" . '</thead>' . "\n\n" . '<tbody>' . "\n\n"; // display tab content foreach ($exo_questions_details as $exo_questions_detail) { if ($exo_questions_detail['minimum'] == '') { $exo_questions_detail['minimum'] = 0;