|
@@ -12,6 +12,7 @@ use ChamiloSession as Session;
|
|
|
* @author Olivier Brouckaert <oli.brouckaert@skynet.be> 2003-2004
|
|
|
* @author Hubert Borderiou 2011-10-21
|
|
|
* @author ivantcholakov2009-07-20
|
|
|
+ * @author Julio Montoya
|
|
|
*/
|
|
|
class ExerciseLib
|
|
|
{
|
|
@@ -46,17 +47,22 @@ class ExerciseLib
|
|
|
$show_answers = false,
|
|
|
$show_icon = false
|
|
|
) {
|
|
|
- $course_id = empty($exercise->course_id) ? api_get_course_int_id() : $exercise->course_id;
|
|
|
- $course = api_get_course_info_by_id($course_id);
|
|
|
+ $course_id = $exercise->course_id;
|
|
|
+
|
|
|
+ if (empty($course_id)) {
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+ $course = $exercise->course;
|
|
|
+
|
|
|
// Change false to true in the following line to enable answer hinting
|
|
|
$debug_mark_answer = $show_answers;
|
|
|
// Reads question information
|
|
|
- if (!$objQuestionTmp = Question::read($questionId, $course_id)) {
|
|
|
+ if (!$objQuestionTmp = Question::read($questionId, $course)) {
|
|
|
// Question not found
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- if ($exercise->feedback_type != EXERCISE_FEEDBACK_TYPE_END) {
|
|
|
+ if ($exercise->getFeedbackType() != EXERCISE_FEEDBACK_TYPE_END) {
|
|
|
$show_comment = false;
|
|
|
}
|
|
|
|
|
@@ -113,111 +119,119 @@ class ExerciseLib
|
|
|
// suggestions here, for the sake of comprehensions, while the ones
|
|
|
// on the right side are called answers
|
|
|
$num_suggestions = 0;
|
|
|
- if (in_array($answerType, [MATCHING, DRAGGABLE, MATCHING_DRAGGABLE])) {
|
|
|
- if ($answerType == DRAGGABLE) {
|
|
|
- $isVertical = $objQuestionTmp->extra == 'v';
|
|
|
- $s .= '
|
|
|
- <div class="col-md-12 ui-widget ui-helper-clearfix">
|
|
|
- <div class="clearfix">
|
|
|
- <ul class="exercise-draggable-answer '.($isVertical ? '' : 'list-inline').'"
|
|
|
- id="question-'.$questionId.'" data-question="'.$questionId.'">
|
|
|
- ';
|
|
|
- } else {
|
|
|
- $s .= '<div id="drag'.$questionId.'_question" class="drag_question">
|
|
|
- <table class="data_table">';
|
|
|
- }
|
|
|
|
|
|
- // Iterate through answers
|
|
|
- $x = 1;
|
|
|
- //mark letters for each answer
|
|
|
- $letter = 'A';
|
|
|
- $answer_matching = [];
|
|
|
- $cpt1 = [];
|
|
|
- for ($answerId = 1; $answerId <= $nbrAnswers; $answerId++) {
|
|
|
- $answerCorrect = $objAnswerTmp->isCorrect($answerId);
|
|
|
- $numAnswer = $objAnswerTmp->selectAutoId($answerId);
|
|
|
- if ($answerCorrect == 0) {
|
|
|
- // options (A, B, C, ...) that will be put into the list-box
|
|
|
- // have the "correct" field set to 0 because they are answer
|
|
|
- $cpt1[$x] = $letter;
|
|
|
- $answer_matching[$x] = $objAnswerTmp->selectAnswerByAutoId(
|
|
|
- $numAnswer
|
|
|
- );
|
|
|
- $x++;
|
|
|
- $letter++;
|
|
|
+ switch ($answerType) {
|
|
|
+ case MATCHING:
|
|
|
+ case DRAGGABLE:
|
|
|
+ case MATCHING_DRAGGABLE:
|
|
|
+ if ($answerType == DRAGGABLE) {
|
|
|
+ $isVertical = $objQuestionTmp->extra == 'v';
|
|
|
+ $s .= '
|
|
|
+ <div class="col-md-12 ui-widget ui-helper-clearfix">
|
|
|
+ <div class="clearfix">
|
|
|
+ <ul class="exercise-draggable-answer '.($isVertical ? '' : 'list-inline').'"
|
|
|
+ id="question-'.$questionId.'" data-question="'.$questionId.'">
|
|
|
+ ';
|
|
|
+ } else {
|
|
|
+ $s .= '<div id="drag'.$questionId.'_question" class="drag_question">
|
|
|
+ <table class="data_table">';
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- $i = 1;
|
|
|
- $select_items[0]['id'] = 0;
|
|
|
- $select_items[0]['letter'] = '--';
|
|
|
- $select_items[0]['answer'] = '';
|
|
|
- foreach ($answer_matching as $id => $value) {
|
|
|
- $select_items[$i]['id'] = $value['id_auto'];
|
|
|
- $select_items[$i]['letter'] = $cpt1[$id];
|
|
|
- $select_items[$i]['answer'] = $value['answer'];
|
|
|
- $i++;
|
|
|
- }
|
|
|
+ // Iterate through answers
|
|
|
+ $x = 1;
|
|
|
+ //mark letters for each answer
|
|
|
+ $letter = 'A';
|
|
|
+ $answer_matching = [];
|
|
|
+ $cpt1 = [];
|
|
|
+ for ($answerId = 1; $answerId <= $nbrAnswers; $answerId++) {
|
|
|
+ $answerCorrect = $objAnswerTmp->isCorrect($answerId);
|
|
|
+ $numAnswer = $objAnswerTmp->selectAutoId($answerId);
|
|
|
+ if ($answerCorrect == 0) {
|
|
|
+ // options (A, B, C, ...) that will be put into the list-box
|
|
|
+ // have the "correct" field set to 0 because they are answer
|
|
|
+ $cpt1[$x] = $letter;
|
|
|
+ $answer_matching[$x] = $objAnswerTmp->selectAnswerByAutoId(
|
|
|
+ $numAnswer
|
|
|
+ );
|
|
|
+ $x++;
|
|
|
+ $letter++;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- $user_choice_array_position = [];
|
|
|
- if (!empty($user_choice)) {
|
|
|
- foreach ($user_choice as $item) {
|
|
|
- $user_choice_array_position[$item['position']] = $item['answer'];
|
|
|
+ $i = 1;
|
|
|
+ $select_items[0]['id'] = 0;
|
|
|
+ $select_items[0]['letter'] = '--';
|
|
|
+ $select_items[0]['answer'] = '';
|
|
|
+ foreach ($answer_matching as $id => $value) {
|
|
|
+ $select_items[$i]['id'] = $value['id_auto'];
|
|
|
+ $select_items[$i]['letter'] = $cpt1[$id];
|
|
|
+ $select_items[$i]['answer'] = $value['answer'];
|
|
|
+ $i++;
|
|
|
}
|
|
|
- }
|
|
|
- $num_suggestions = ($nbrAnswers - $x) + 1;
|
|
|
- } elseif ($answerType == FREE_ANSWER) {
|
|
|
- $fck_content = isset($user_choice[0]) && !empty($user_choice[0]['answer']) ? $user_choice[0]['answer'] : null;
|
|
|
- $form = new FormValidator('free_choice_'.$questionId);
|
|
|
- $config = [
|
|
|
- 'ToolbarSet' => 'TestFreeAnswer',
|
|
|
- ];
|
|
|
- $form->addHtmlEditor(
|
|
|
- "choice[".$questionId."]",
|
|
|
- null,
|
|
|
- false,
|
|
|
- false,
|
|
|
- $config
|
|
|
- );
|
|
|
- $form->setDefaults(["choice[".$questionId."]" => $fck_content]);
|
|
|
- $s .= $form->returnForm();
|
|
|
- } elseif ($answerType == ORAL_EXPRESSION) {
|
|
|
- // Add nanog
|
|
|
- if (api_get_setting('enable_record_audio') === 'true') {
|
|
|
- //@todo pass this as a parameter
|
|
|
- global $exercise_stat_info, $exerciseId;
|
|
|
- if (!empty($exercise_stat_info)) {
|
|
|
- $objQuestionTmp->initFile(
|
|
|
- api_get_session_id(),
|
|
|
- api_get_user_id(),
|
|
|
- $exercise_stat_info['exe_exo_id'],
|
|
|
- $exercise_stat_info['exe_id']
|
|
|
- );
|
|
|
- } else {
|
|
|
- $objQuestionTmp->initFile(
|
|
|
- api_get_session_id(),
|
|
|
- api_get_user_id(),
|
|
|
- $exerciseId,
|
|
|
- 'temp_exe'
|
|
|
- );
|
|
|
+
|
|
|
+ $user_choice_array_position = [];
|
|
|
+ if (!empty($user_choice)) {
|
|
|
+ foreach ($user_choice as $item) {
|
|
|
+ $user_choice_array_position[$item['position']] = $item['answer'];
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- echo $objQuestionTmp->returnRecorder();
|
|
|
- }
|
|
|
+ $num_suggestions = ($nbrAnswers - $x) + 1;
|
|
|
+ break;
|
|
|
+ case FREE_ANSWER:
|
|
|
+ $fck_content = isset($user_choice[0]) && !empty($user_choice[0]['answer']) ? $user_choice[0]['answer'] : null;
|
|
|
+ $form = new FormValidator('free_choice_'.$questionId);
|
|
|
+ $config = [
|
|
|
+ 'ToolbarSet' => 'TestFreeAnswer',
|
|
|
+ ];
|
|
|
+ $form->addHtmlEditor(
|
|
|
+ "choice[".$questionId."]",
|
|
|
+ null,
|
|
|
+ false,
|
|
|
+ false,
|
|
|
+ $config
|
|
|
+ );
|
|
|
+ $form->setDefaults(["choice[".$questionId."]" => $fck_content]);
|
|
|
+ $s .= $form->returnForm();
|
|
|
+ break;
|
|
|
+ case ORAL_EXPRESSION:
|
|
|
+ // Add nanog
|
|
|
+ if (api_get_setting('enable_record_audio') === 'true') {
|
|
|
+ //@todo pass this as a parameter
|
|
|
+ global $exercise_stat_info, $exerciseId;
|
|
|
+ if (!empty($exercise_stat_info)) {
|
|
|
+ $objQuestionTmp->initFile(
|
|
|
+ api_get_session_id(),
|
|
|
+ api_get_user_id(),
|
|
|
+ $exercise_stat_info['exe_exo_id'],
|
|
|
+ $exercise_stat_info['exe_id']
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ $objQuestionTmp->initFile(
|
|
|
+ api_get_session_id(),
|
|
|
+ api_get_user_id(),
|
|
|
+ $exerciseId,
|
|
|
+ 'temp_exe'
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ echo $objQuestionTmp->returnRecorder();
|
|
|
+ }
|
|
|
|
|
|
- $form = new FormValidator('free_choice_'.$questionId);
|
|
|
- $config = ['ToolbarSet' => 'TestFreeAnswer'];
|
|
|
+ $form = new FormValidator('free_choice_'.$questionId);
|
|
|
+ $config = ['ToolbarSet' => 'TestFreeAnswer'];
|
|
|
|
|
|
- $form->addHtml('<div id="'.'hide_description_'.$questionId.'_options" style="display: none;">');
|
|
|
- $form->addHtmlEditor(
|
|
|
- "choice[$questionId]",
|
|
|
- null,
|
|
|
- false,
|
|
|
- false,
|
|
|
- $config
|
|
|
- );
|
|
|
- $form->addHtml('</div>');
|
|
|
- $s .= $form->returnForm();
|
|
|
+ $form->addHtml('<div id="'.'hide_description_'.$questionId.'_options" style="display: none;">');
|
|
|
+ $form->addHtmlEditor(
|
|
|
+ "choice[$questionId]",
|
|
|
+ null,
|
|
|
+ false,
|
|
|
+ false,
|
|
|
+ $config
|
|
|
+ );
|
|
|
+ $form->addHtml('</div>');
|
|
|
+ $s .= $form->returnForm();
|
|
|
+ break;
|
|
|
}
|
|
|
|
|
|
// Now navigate through the possible answers, using the max number of
|
|
@@ -295,7 +309,7 @@ class ExerciseLib
|
|
|
RadioValidator(question_id, answer_id);
|
|
|
}
|
|
|
|
|
|
- $(document).ready(function() {
|
|
|
+ $(function() {
|
|
|
var ShowAlert = '';
|
|
|
var typeRadioB = '';
|
|
|
var question_id = $('input[name=question_id]').val();
|
|
@@ -423,7 +437,7 @@ class ExerciseLib
|
|
|
]
|
|
|
)) {
|
|
|
$header = Display::tag('th', get_lang('Options'));
|
|
|
- if ($exercise->feedback_type == EXERCISE_FEEDBACK_TYPE_END) {
|
|
|
+ if ($exercise->getFeedbackType() == EXERCISE_FEEDBACK_TYPE_END) {
|
|
|
$header .= Display::tag('th', get_lang('Feedback'));
|
|
|
}
|
|
|
$s .= '<table class="table table-hover table-striped">';
|
|
@@ -906,9 +920,10 @@ class ExerciseLib
|
|
|
*/
|
|
|
if ($origin !== null) {
|
|
|
global $exe_id;
|
|
|
+ $exe_id = (int) $exe_id;
|
|
|
$trackAttempts = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
|
|
|
- $sql = 'SELECT answer FROM '.$trackAttempts.'
|
|
|
- WHERE exe_id='.$exe_id.' AND question_id='.$questionId;
|
|
|
+ $sql = "SELECT answer FROM $trackAttempts
|
|
|
+ WHERE exe_id = $exe_id AND question_id= $questionId";
|
|
|
$rsLastAttempt = Database::query($sql);
|
|
|
$rowLastAttempt = Database::fetch_array($rsLastAttempt);
|
|
|
$answer = $rowLastAttempt['answer'];
|
|
@@ -993,7 +1008,7 @@ class ExerciseLib
|
|
|
$answer = '';
|
|
|
$i = 0;
|
|
|
foreach ($studentAnswerList as $studentItem) {
|
|
|
- // remove surronding brackets
|
|
|
+ // Remove surronding brackets
|
|
|
$studentResponse = api_substr(
|
|
|
$studentItem,
|
|
|
1,
|
|
@@ -1076,7 +1091,7 @@ class ExerciseLib
|
|
|
$selected = 'selected="selected"';
|
|
|
}
|
|
|
$s .= '<option value="'.$val['id'].'" '.$selected.'>'.$val['letter'].'</option>';
|
|
|
- } // end foreach()
|
|
|
+ }
|
|
|
|
|
|
$s .= '</select></div></td><td width="5%" class="separate"> </td>';
|
|
|
$s .= '<td width="40%" valign="top" >';
|
|
@@ -1093,7 +1108,7 @@ class ExerciseLib
|
|
|
$s .= '</td>';
|
|
|
$s .= '</tr>';
|
|
|
$lines_count++;
|
|
|
- //if the left side of the "matching" has been completely
|
|
|
+ // If the left side of the "matching" has been completely
|
|
|
// shown but the right side still has values to show...
|
|
|
if (($lines_count - 1) == $num_suggestions) {
|
|
|
// if it remains answers to shown at the right side
|
|
@@ -1106,8 +1121,8 @@ class ExerciseLib
|
|
|
$s .= "</td>
|
|
|
</tr>";
|
|
|
$lines_count++;
|
|
|
- } // end while()
|
|
|
- } // end if()
|
|
|
+ }
|
|
|
+ }
|
|
|
$matching_correct_answer++;
|
|
|
}
|
|
|
break;
|
|
@@ -1257,7 +1272,7 @@ HTML;
|
|
|
if (!$freeze) {
|
|
|
$s .= "
|
|
|
<script>
|
|
|
- $(document).on('ready', function() {
|
|
|
+ $(function() {
|
|
|
jsPlumb.ready(function() {
|
|
|
jsPlumb.connect({
|
|
|
source: 'window_$windowId',
|
|
@@ -1309,7 +1324,7 @@ HTML;
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
- } // end for()
|
|
|
+ }
|
|
|
|
|
|
if ($show_comment) {
|
|
|
$s .= '</table>';
|
|
@@ -1329,9 +1344,8 @@ HTML;
|
|
|
|
|
|
if ($answerType == DRAGGABLE) {
|
|
|
$isVertical = $objQuestionTmp->extra == 'v';
|
|
|
-
|
|
|
$s .= "</ul>";
|
|
|
- $s .= "</div>"; //clearfix
|
|
|
+ $s .= "</div>";
|
|
|
$counterAnswer = 1;
|
|
|
$s .= $isVertical ? '' : '<div class="row">';
|
|
|
for ($answerId = 1; $answerId <= $nbrAnswers; $answerId++) {
|
|
@@ -1373,7 +1387,7 @@ HTML;
|
|
|
} elseif ($answerType == HOT_SPOT || $answerType == HOT_SPOT_DELINEATION) {
|
|
|
global $exerciseId, $exe_id;
|
|
|
// Question is a HOT_SPOT
|
|
|
- //checking document/images visibility
|
|
|
+ // Checking document/images visibility
|
|
|
if (api_is_platform_admin() || api_is_course_admin()) {
|
|
|
$doc_id = $objQuestionTmp->getPictureId();
|
|
|
if (is_numeric($doc_id)) {
|
|
@@ -1483,7 +1497,7 @@ HOTSPOT;
|
|
|
$s .= "<div class=\"col-sm-8 col-md-9\">
|
|
|
<div class=\"hotspot-image\"></div>
|
|
|
<script>
|
|
|
- $(document).on('ready', function() {
|
|
|
+ $(function() {
|
|
|
new ".($answerType == HOT_SPOT_DELINEATION ? 'DelineationQuestion' : 'HotspotQuestion')."({
|
|
|
questionId: $questionId,
|
|
|
exerciseId: $exe_id,
|
|
@@ -1667,12 +1681,12 @@ HOTSPOT;
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
- } else {
|
|
|
- return false;
|
|
|
}
|
|
|
- } else {
|
|
|
- return true;
|
|
|
+
|
|
|
+ return false;
|
|
|
}
|
|
|
+
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1777,18 +1791,18 @@ HOTSPOT;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * @param string $in_hotpot_path
|
|
|
+ * @param string $path
|
|
|
*
|
|
|
* @return int
|
|
|
*/
|
|
|
- public static function get_count_exam_hotpotatoes_results($in_hotpot_path)
|
|
|
+ public static function get_count_exam_hotpotatoes_results($path)
|
|
|
{
|
|
|
return self::get_exam_results_hotpotatoes_data(
|
|
|
0,
|
|
|
0,
|
|
|
'',
|
|
|
'',
|
|
|
- $in_hotpot_path,
|
|
|
+ $path,
|
|
|
true,
|
|
|
''
|
|
|
);
|
|
@@ -1823,16 +1837,20 @@ HOTSPOT;
|
|
|
$in_direction = Database::escape_string($in_direction);
|
|
|
$in_column = Database::escape_string($in_column);
|
|
|
$in_number_of_items = intval($in_number_of_items);
|
|
|
- $in_from = intval($in_from);
|
|
|
+ $in_from = (int) $in_from;
|
|
|
|
|
|
$TBL_TRACK_HOTPOTATOES = Database::get_main_table(
|
|
|
TABLE_STATISTIC_TRACK_E_HOTPOTATOES
|
|
|
);
|
|
|
$TBL_USER = Database::get_main_table(TABLE_MAIN_USER);
|
|
|
|
|
|
- $sql = "SELECT *, thp.id AS thp_id FROM $TBL_TRACK_HOTPOTATOES thp
|
|
|
- JOIN $TBL_USER u ON thp.exe_user_id = u.user_id
|
|
|
- WHERE thp.c_id = $courseId AND exe_name LIKE '$in_hotpot_path%'";
|
|
|
+ $sql = "SELECT *, thp.id AS thp_id
|
|
|
+ FROM $TBL_TRACK_HOTPOTATOES thp
|
|
|
+ JOIN $TBL_USER u
|
|
|
+ ON thp.exe_user_id = u.user_id
|
|
|
+ WHERE
|
|
|
+ thp.c_id = $courseId AND
|
|
|
+ exe_name LIKE '$in_hotpot_path%'";
|
|
|
|
|
|
// just count how many answers
|
|
|
if ($in_get_count) {
|
|
@@ -1867,7 +1885,7 @@ HOTSPOT;
|
|
|
'lastname' => $data['lastname'],
|
|
|
'username' => $data['username'],
|
|
|
'group_name' => implode(
|
|
|
- "<br/>",
|
|
|
+ '<br/>',
|
|
|
GroupManager::get_user_group_name($data['user_id'])
|
|
|
),
|
|
|
'exe_date' => $data['exe_date'],
|
|
@@ -1893,11 +1911,10 @@ HOTSPOT;
|
|
|
$courseId,
|
|
|
$sessionId
|
|
|
) {
|
|
|
- $table = Database::get_main_table(
|
|
|
- TABLE_STATISTIC_TRACK_E_HOTPOTATOES
|
|
|
- );
|
|
|
+ $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTPOTATOES);
|
|
|
$exercisePath = Database::escape_string($exercisePath);
|
|
|
$userId = (int) $userId;
|
|
|
+ $courseId = (int) $courseId;
|
|
|
|
|
|
$sql = "SELECT * FROM $table
|
|
|
WHERE
|
|
@@ -1962,6 +1979,9 @@ HOTSPOT;
|
|
|
}
|
|
|
|
|
|
$course_id = $courseInfo['real_id'];
|
|
|
+ $sessionId = api_get_session_id();
|
|
|
+ $exercise_id = (int) $exercise_id;
|
|
|
+
|
|
|
$is_allowedToEdit =
|
|
|
api_is_allowed_to_edit(null, true) ||
|
|
|
api_is_allowed_to_edit(true) ||
|
|
@@ -1982,7 +2002,7 @@ HOTSPOT;
|
|
|
$session_id_and = " AND te.session_id = $sessionId ";
|
|
|
$sessionCondition = " AND ttte.session_id = $sessionId";
|
|
|
}
|
|
|
- $exercise_id = (int) $exercise_id;
|
|
|
+
|
|
|
$exercise_where = '';
|
|
|
if (!empty($exercise_id)) {
|
|
|
$exercise_where .= ' AND te.exe_exo_id = '.$exercise_id.' ';
|
|
@@ -2155,9 +2175,9 @@ HOTSPOT;
|
|
|
|
|
|
// sql for hotpotatoes tests for teacher / tutor view
|
|
|
if ($get_count) {
|
|
|
- $hpsql_select = "SELECT count(username)";
|
|
|
+ $hpsql_select = ' SELECT count(username) ';
|
|
|
} else {
|
|
|
- $hpsql_select = "SELECT
|
|
|
+ $hpsql_select = " SELECT
|
|
|
$first_and_last_name ,
|
|
|
username,
|
|
|
official_code,
|
|
@@ -2540,7 +2560,7 @@ HOTSPOT;
|
|
|
$question_list = explode(',', $exercise_stat_info['data_tracking']);
|
|
|
if (!empty($question_list)) {
|
|
|
foreach ($question_list as $questionId) {
|
|
|
- $objQuestionTmp = Question::read($questionId, $course_id);
|
|
|
+ $objQuestionTmp = Question::read($questionId, $objExercise->course);
|
|
|
// We're inside *one* question. Go through each possible answer for this question
|
|
|
$result = $objExercise->manage_answer(
|
|
|
$exeId,
|
|
@@ -2756,8 +2776,6 @@ HOTSPOT;
|
|
|
*/
|
|
|
public static function convertScoreToPlatformSetting($score, $weight)
|
|
|
{
|
|
|
- $result = ['score' => $score, 'weight' => $weight];
|
|
|
-
|
|
|
$maxNote = api_get_setting('exercise_max_score');
|
|
|
$minNote = api_get_setting('exercise_min_score');
|
|
|
|
|
@@ -2976,7 +2994,7 @@ HOTSPOT;
|
|
|
* @return bool
|
|
|
*/
|
|
|
public static function addScoreModelInput(
|
|
|
- FormValidator &$form,
|
|
|
+ FormValidator $form,
|
|
|
$name,
|
|
|
$weight,
|
|
|
$selected
|
|
@@ -3036,7 +3054,7 @@ HOTSPOT;
|
|
|
spanTag.addClass(optionClass);
|
|
|
}
|
|
|
|
|
|
- $(document).ready( function() {
|
|
|
+ $(function() {
|
|
|
// Loading values
|
|
|
$('.exercise_mark_select').on('loaded.bs.select', function() {
|
|
|
updateSelect($(this));
|
|
@@ -3077,7 +3095,6 @@ EOT;
|
|
|
ICON_SIZE_MEDIUM
|
|
|
);
|
|
|
} else {
|
|
|
- //$html .= Display::return_message(get_lang('YouDidNotReachTheMinimumScore'), 'warning');
|
|
|
$html = get_lang('YouDidNotReachTheMinimumScore');
|
|
|
$icon = Display::return_icon(
|
|
|
'warning.png',
|
|
@@ -3130,35 +3147,6 @@ EOT;
|
|
|
return $return;
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Converts a score/weight values to the platform scale.
|
|
|
- *
|
|
|
- * @param float $score
|
|
|
- * @param float $weight
|
|
|
- *
|
|
|
- * @deprecated seem not to be used
|
|
|
- *
|
|
|
- * @return float the score rounded converted to the new range
|
|
|
- */
|
|
|
- public static function convert_score($score, $weight)
|
|
|
- {
|
|
|
- $maxNote = api_get_setting('exercise_max_score');
|
|
|
- $minNote = api_get_setting('exercise_min_score');
|
|
|
-
|
|
|
- if ($score != '' && $weight != '') {
|
|
|
- if ($maxNote != '' && $minNote != '') {
|
|
|
- if (!empty($weight)) {
|
|
|
- $score = $minNote + ($maxNote - $minNote) * $score / $weight;
|
|
|
- } else {
|
|
|
- $score = $minNote;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- $score_rounded = float_format($score, 1);
|
|
|
-
|
|
|
- return $score_rounded;
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
* Getting all active exercises from a course from a session
|
|
|
* (if a session_id is provided we will show all the exercises in the course +
|
|
@@ -3689,9 +3677,10 @@ EOT;
|
|
|
/**
|
|
|
* Get average score by score (NO Exercises in LPs ).
|
|
|
*
|
|
|
- * @param int exercise id
|
|
|
+ * @param int $exercise_id
|
|
|
* @param int $courseId
|
|
|
- * @param int session id
|
|
|
+ * @param int $session_id
|
|
|
+ * @param int $user_count
|
|
|
*
|
|
|
* @return float Best average score
|
|
|
*/
|
|
@@ -3714,9 +3703,7 @@ EOT;
|
|
|
$avg_score += $score;
|
|
|
}
|
|
|
}
|
|
|
- //We asumme that all exe_weighting
|
|
|
- //$avg_score = show_score( $avg_score / count($user_results) , $result['exe_weighting']);
|
|
|
- //$avg_score = ($avg_score / count($user_results));
|
|
|
+ // We asumme that all exe_weighting
|
|
|
if (!empty($user_count)) {
|
|
|
$avg_score = float_format($avg_score / $user_count, 1) * 100;
|
|
|
} else {
|
|
@@ -3730,9 +3717,9 @@ EOT;
|
|
|
/**
|
|
|
* Get average score by score (NO Exercises in LPs ).
|
|
|
*
|
|
|
- * @param int exercise id
|
|
|
+ * @param int $exercise_id
|
|
|
* @param int $courseId
|
|
|
- * @param int session id
|
|
|
+ * @param int $session_id
|
|
|
*
|
|
|
* @return float Best average score
|
|
|
*/
|
|
@@ -3989,12 +3976,8 @@ EOT;
|
|
|
$course_code,
|
|
|
$session_id
|
|
|
) {
|
|
|
- $track_exercises = Database::get_main_table(
|
|
|
- TABLE_STATISTIC_TRACK_E_EXERCISES
|
|
|
- );
|
|
|
- $track_hotspot = Database::get_main_table(
|
|
|
- TABLE_STATISTIC_TRACK_E_HOTSPOT
|
|
|
- );
|
|
|
+ $track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
|
|
|
+ $track_hotspot = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTSPOT);
|
|
|
$courseUser = Database::get_main_table(TABLE_MAIN_COURSE_USER);
|
|
|
$courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
|
|
|
|
|
@@ -4015,7 +3998,7 @@ EOT;
|
|
|
$courseCondition = "
|
|
|
INNER JOIN $courseUserSession cu
|
|
|
ON cu.c_id = c.id AND cu.user_id = exe_user_id";
|
|
|
- $courseConditionWhere = " AND cu.status = 0 ";
|
|
|
+ $courseConditionWhere = ' AND cu.status = 0 ';
|
|
|
}
|
|
|
|
|
|
$sql = "SELECT DISTINCT exe_user_id
|
|
@@ -4082,7 +4065,7 @@ EOT;
|
|
|
switch ($question_type) {
|
|
|
case FILL_IN_BLANKS:
|
|
|
$answer_condition = '';
|
|
|
- $select_condition = " e.exe_id, answer ";
|
|
|
+ $select_condition = ' e.exe_id, answer ';
|
|
|
break;
|
|
|
case MATCHING:
|
|
|
case MATCHING_DRAGGABLE:
|
|
@@ -4401,24 +4384,50 @@ EOT;
|
|
|
$remainingMessage = ''
|
|
|
) {
|
|
|
$origin = api_get_origin();
|
|
|
+ $courseCode = api_get_course_id();
|
|
|
+ $sessionId = api_get_session_id();
|
|
|
|
|
|
// Getting attempt info
|
|
|
$exercise_stat_info = $objExercise->get_stat_track_exercise_info_by_exe_id($exeId);
|
|
|
|
|
|
// Getting question list
|
|
|
$question_list = [];
|
|
|
+ $studentInfo = [];
|
|
|
if (!empty($exercise_stat_info['data_tracking'])) {
|
|
|
+ $studentInfo = api_get_user_info($exercise_stat_info['exe_user_id']);
|
|
|
$question_list = explode(',', $exercise_stat_info['data_tracking']);
|
|
|
} else {
|
|
|
// Try getting the question list only if save result is off
|
|
|
if ($save_user_result == false) {
|
|
|
$question_list = $objExercise->get_validated_question_list();
|
|
|
}
|
|
|
- if ($objExercise->selectFeedbackType() == EXERCISE_FEEDBACK_TYPE_DIRECT) {
|
|
|
+ if (in_array(
|
|
|
+ $objExercise->getFeedbackType(),
|
|
|
+ [EXERCISE_FEEDBACK_TYPE_DIRECT, EXERCISE_FEEDBACK_TYPE_POPUP]
|
|
|
+ )) {
|
|
|
$question_list = $objExercise->get_validated_question_list();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if ($objExercise->getResultAccess()) {
|
|
|
+ if ($objExercise->hasResultsAccess($exercise_stat_info) === false) {
|
|
|
+ echo Display::return_message(
|
|
|
+ sprintf(get_lang('YouPassedTheLimitOfXMinutesToSeeTheResults'), $objExercise->getResultsAccess())
|
|
|
+ );
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!empty($objExercise->getResultAccess())) {
|
|
|
+ $url = api_get_path(WEB_CODE_PATH).'exercise/overview.php?'.api_get_cidreq().'&exerciseId='.$objExercise->id;
|
|
|
+ echo $objExercise->returnTimeLeftDiv();
|
|
|
+ echo $objExercise->showSimpleTimeControl(
|
|
|
+ $objExercise->getResultAccessTimeDiff($exercise_stat_info),
|
|
|
+ $url
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
$counter = 1;
|
|
|
$total_score = $total_weight = 0;
|
|
|
$exercise_content = null;
|
|
@@ -4426,11 +4435,14 @@ EOT;
|
|
|
// Hide results
|
|
|
$show_results = false;
|
|
|
$show_only_score = false;
|
|
|
- if ($objExercise->results_disabled == RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS) {
|
|
|
- $show_results = true;
|
|
|
- }
|
|
|
|
|
|
- if ($objExercise->results_disabled == RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER) {
|
|
|
+ if (in_array($objExercise->results_disabled,
|
|
|
+ [
|
|
|
+ RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER,
|
|
|
+ RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS,
|
|
|
+ RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS_AND_RANKING,
|
|
|
+ ]
|
|
|
+ )) {
|
|
|
$show_results = true;
|
|
|
}
|
|
|
|
|
@@ -4449,7 +4461,7 @@ EOT;
|
|
|
// Not display expected answer, but score, and feedback
|
|
|
$show_all_but_expected_answer = false;
|
|
|
if ($objExercise->results_disabled == RESULT_DISABLE_SHOW_SCORE_ONLY &&
|
|
|
- $objExercise->feedback_type == EXERCISE_FEEDBACK_TYPE_END
|
|
|
+ $objExercise->getFeedbackType() == EXERCISE_FEEDBACK_TYPE_END
|
|
|
) {
|
|
|
$show_all_but_expected_answer = true;
|
|
|
$show_results = true;
|
|
@@ -4497,7 +4509,9 @@ EOT;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if ($objExercise->results_disabled == RESULT_DISABLE_DONT_SHOW_SCORE_ONLY_IF_USER_FINISHES_ATTEMPTS_SHOW_ALWAYS_FEEDBACK) {
|
|
|
+ if ($objExercise->results_disabled ==
|
|
|
+ RESULT_DISABLE_DONT_SHOW_SCORE_ONLY_IF_USER_FINISHES_ATTEMPTS_SHOW_ALWAYS_FEEDBACK
|
|
|
+ ) {
|
|
|
$show_only_score = false;
|
|
|
$show_results = true;
|
|
|
$show_all_but_expected_answer = false;
|
|
@@ -4510,13 +4524,12 @@ EOT;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if ($show_results || $show_only_score) {
|
|
|
+ if (($show_results || $show_only_score) && $origin !== 'embeddable') {
|
|
|
if (isset($exercise_stat_info['exe_user_id'])) {
|
|
|
- $user_info = api_get_user_info($exercise_stat_info['exe_user_id']);
|
|
|
- if ($user_info) {
|
|
|
+ if (!empty($studentInfo)) {
|
|
|
// Shows exercise header
|
|
|
echo $objExercise->showExerciseResultHeader(
|
|
|
- $user_info,
|
|
|
+ $studentInfo,
|
|
|
$exercise_stat_info
|
|
|
);
|
|
|
}
|
|
@@ -4524,9 +4537,9 @@ EOT;
|
|
|
}
|
|
|
|
|
|
// Display text when test is finished #4074 and for LP #4227
|
|
|
- $end_of_message = $objExercise->selectTextWhenFinished();
|
|
|
- if (!empty($end_of_message)) {
|
|
|
- echo Display::return_message($end_of_message, 'normal', false);
|
|
|
+ $endOfMessage = $objExercise->getTextWhenFinished();
|
|
|
+ if (!empty($endOfMessage)) {
|
|
|
+ echo Display::return_message($endOfMessage, 'normal', false);
|
|
|
echo "<div class='clear'> </div>";
|
|
|
}
|
|
|
|
|
@@ -4539,7 +4552,10 @@ EOT;
|
|
|
$exerciseResultCoordinates = null;
|
|
|
$delineationResults = null;
|
|
|
|
|
|
- if ($objExercise->selectFeedbackType() == EXERCISE_FEEDBACK_TYPE_DIRECT) {
|
|
|
+ if (in_array(
|
|
|
+ $objExercise->getFeedbackType(),
|
|
|
+ [EXERCISE_FEEDBACK_TYPE_DIRECT, EXERCISE_FEEDBACK_TYPE_POPUP]
|
|
|
+ )) {
|
|
|
$loadChoiceFromSession = true;
|
|
|
$fromDatabase = false;
|
|
|
$exerciseResult = Session::read('exerciseResult');
|
|
@@ -4554,7 +4570,7 @@ EOT;
|
|
|
if (!empty($question_list)) {
|
|
|
foreach ($question_list as $questionId) {
|
|
|
// Creates a temporary Question object
|
|
|
- $objQuestionTmp = Question::read($questionId);
|
|
|
+ $objQuestionTmp = Question::read($questionId, $objExercise->course);
|
|
|
// This variable came from exercise_submit_modal.php
|
|
|
ob_start();
|
|
|
$choice = null;
|
|
@@ -4674,6 +4690,7 @@ EOT;
|
|
|
'score' => $my_total_score,
|
|
|
'weight' => $my_total_weight,
|
|
|
'comments' => $comnt,
|
|
|
+ 'user_answered' => $result['user_answered'],
|
|
|
];
|
|
|
}
|
|
|
|
|
@@ -4727,6 +4744,7 @@ EOT;
|
|
|
}
|
|
|
|
|
|
$totalScoreText = null;
|
|
|
+ $certificateBlock = '';
|
|
|
if (($show_results || $show_only_score) && $showTotalScore) {
|
|
|
if ($result['answer_type'] == MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY) {
|
|
|
echo '<h1 style="text-align : center; margin : 20px 0;">'.get_lang('YourResults').'</h1><br />';
|
|
@@ -4740,6 +4758,17 @@ EOT;
|
|
|
true
|
|
|
);
|
|
|
} else {
|
|
|
+ $pluginEvaluation = QuestionOptionsEvaluationPlugin::create();
|
|
|
+
|
|
|
+ if ('true' === $pluginEvaluation->get(QuestionOptionsEvaluationPlugin::SETTING_ENABLE)) {
|
|
|
+ $formula = $pluginEvaluation->getFormulaForExercise($objExercise->selectId());
|
|
|
+
|
|
|
+ if (!empty($formula)) {
|
|
|
+ $total_score = $pluginEvaluation->getResultWithFormula($exeId, $formula);
|
|
|
+ $total_weight = $pluginEvaluation->getMaxScore();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
$totalScoreText .= self::getTotalScoreRibbon(
|
|
|
$objExercise,
|
|
|
$total_score,
|
|
@@ -4749,6 +4778,17 @@ EOT;
|
|
|
);
|
|
|
}
|
|
|
$totalScoreText .= '</div>';
|
|
|
+
|
|
|
+ if (!empty($studentInfo)) {
|
|
|
+ $certificateBlock = self::generateAndShowCertificateBlock(
|
|
|
+ $total_score,
|
|
|
+ $total_weight,
|
|
|
+ $objExercise,
|
|
|
+ $studentInfo['id'],
|
|
|
+ $courseCode,
|
|
|
+ $sessionId
|
|
|
+ );
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if ($result['answer_type'] == MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY) {
|
|
@@ -4783,6 +4823,7 @@ EOT;
|
|
|
);
|
|
|
|
|
|
echo $totalScoreText;
|
|
|
+ echo $certificateBlock;
|
|
|
|
|
|
// Ofaj change BT#11784
|
|
|
if (api_get_configuration_value('quiz_show_description_on_results_page') &&
|
|
@@ -4817,6 +4858,15 @@ EOT;
|
|
|
$exercise_stat_info['exe_duration'],
|
|
|
$question_list
|
|
|
);
|
|
|
+
|
|
|
+ $allowStats = api_get_configuration_value('allow_gradebook_stats');
|
|
|
+ if ($allowStats) {
|
|
|
+ $objExercise->generateStats(
|
|
|
+ $objExercise->selectId(),
|
|
|
+ api_get_course_info(),
|
|
|
+ api_get_session_id()
|
|
|
+ );
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -4835,7 +4885,10 @@ EOT;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (RESULT_DISABLE_RANKING == $objExercise->selectResultsDisabled()) {
|
|
|
+ if (in_array(
|
|
|
+ $objExercise->selectResultsDisabled(),
|
|
|
+ [RESULT_DISABLE_RANKING, RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS_AND_RANKING]
|
|
|
+ )) {
|
|
|
echo Display::page_header(get_lang('Ranking'), null, 'h4');
|
|
|
echo self::displayResultsInRanking(
|
|
|
$objExercise->iId,
|
|
@@ -4871,6 +4924,9 @@ EOT;
|
|
|
$table->setHeaderContents(0, 3, get_lang('Date'), ['class' => 'text-center']);
|
|
|
|
|
|
foreach ($data as $r => $item) {
|
|
|
+ if (!isset($item[1])) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
$selected = $item[1]->getId() == $currentUserId;
|
|
|
|
|
|
foreach ($item as $c => $value) {
|
|
@@ -4987,7 +5043,7 @@ EOT;
|
|
|
$score, $weight, $objExercise->selectPassPercentage()
|
|
|
);
|
|
|
// Color the final test score if pass_percentage activated
|
|
|
- $ribbonTotalSuccessOrError = "";
|
|
|
+ $ribbonTotalSuccessOrError = '';
|
|
|
if (self::isPassPercentageEnabled($objExercise->selectPassPercentage())) {
|
|
|
if ($isSuccess) {
|
|
|
$ribbonTotalSuccessOrError = ' ribbon-total-success';
|
|
@@ -5001,9 +5057,10 @@ EOT;
|
|
|
}
|
|
|
|
|
|
if ($displayChartDegree) {
|
|
|
- $ribbon .= '<h3>'.get_lang('YourTotalScore').": ";
|
|
|
+ $ribbon .= '<h3>'.get_lang('YourTotalScore').': ';
|
|
|
$ribbon .= self::show_score($score, $weight, false, true);
|
|
|
$ribbon .= '</h3>';
|
|
|
+
|
|
|
$ribbon .= '</div>';
|
|
|
}
|
|
|
|
|
@@ -5030,12 +5087,17 @@ EOT;
|
|
|
* @return string
|
|
|
*/
|
|
|
public static function getTotalScoreRibbon(
|
|
|
- $objExercise,
|
|
|
+ Exercise $objExercise,
|
|
|
$score,
|
|
|
$weight,
|
|
|
$checkPassPercentage = false,
|
|
|
$countPendingQuestions = 0
|
|
|
) {
|
|
|
+ $hide = (int) $objExercise->getPageConfigurationAttribute('hide_total_score');
|
|
|
+ if ($hide === 1) {
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+
|
|
|
$passPercentage = $objExercise->selectPassPercentage();
|
|
|
$ribbon = '<div class="title-score">';
|
|
|
if ($checkPassPercentage) {
|
|
@@ -5057,7 +5119,7 @@ EOT;
|
|
|
} else {
|
|
|
$ribbon .= '<div class="total">';
|
|
|
}
|
|
|
- $ribbon .= '<h3>'.get_lang('YourTotalScore').": ";
|
|
|
+ $ribbon .= '<h3>'.get_lang('YourTotalScore').': ';
|
|
|
$ribbon .= self::show_score($score, $weight, false, true);
|
|
|
$ribbon .= '</h3>';
|
|
|
$ribbon .= '</div>';
|
|
@@ -5278,12 +5340,11 @@ EOT;
|
|
|
SELECT COUNT(ea) FROM ChamiloCoreBundle:TrackEAttempt ea
|
|
|
WHERE ea.userId = :user AND ea.cId = :course AND ea.sessionId = :session
|
|
|
AND ea.tms > :time
|
|
|
- GROUP BY ea.questionId
|
|
|
')
|
|
|
->setParameters(['user' => $userId, 'course' => $courseId, 'session' => $sessionId, 'time' => $time])
|
|
|
- ->getResult();
|
|
|
+ ->getSingleScalarResult();
|
|
|
|
|
|
- return count($result);
|
|
|
+ return $result;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -5306,7 +5367,7 @@ EOT;
|
|
|
|
|
|
$midnightTime = ChamiloApi::getServerMidnightTime();
|
|
|
|
|
|
- $answeredQuestionsCount = ExerciseLib::countAnsweredQuestionsByUserAfterTime(
|
|
|
+ $answeredQuestionsCount = self::countAnsweredQuestionsByUserAfterTime(
|
|
|
$midnightTime,
|
|
|
$userId,
|
|
|
$courseId,
|
|
@@ -5315,4 +5376,118 @@ EOT;
|
|
|
|
|
|
return ($answeredQuestionsCount + $numberOfQuestions) > $questionsLimitPerDay;
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Check if an exercise complies with the requirements to be embedded in the mobile app or a video.
|
|
|
+ * By making sure it is set on one question per page and it only contains unique-answer or multiple-answer questions
|
|
|
+ * or unique-answer image. And that the exam does not have immediate feedback.
|
|
|
+ *
|
|
|
+ * @param array $exercise Exercise info
|
|
|
+ *
|
|
|
+ * @throws \Doctrine\ORM\Query\QueryException
|
|
|
+ *
|
|
|
+ * @return bool
|
|
|
+ */
|
|
|
+ public static function isQuizEmbeddable(array $exercise)
|
|
|
+ {
|
|
|
+ $em = Database::getManager();
|
|
|
+
|
|
|
+ if (ONE_PER_PAGE != $exercise['type'] ||
|
|
|
+ in_array($exercise['feedback_type'], [EXERCISE_FEEDBACK_TYPE_DIRECT, EXERCISE_FEEDBACK_TYPE_POPUP])
|
|
|
+ ) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ $countAll = $em
|
|
|
+ ->createQuery('SELECT COUNT(qq)
|
|
|
+ FROM ChamiloCourseBundle:CQuizQuestion qq
|
|
|
+ INNER JOIN ChamiloCourseBundle:CQuizRelQuestion qrq
|
|
|
+ WITH qq.iid = qrq.questionId
|
|
|
+ WHERE qrq.exerciceId = :id'
|
|
|
+ )
|
|
|
+ ->setParameter('id', $exercise['iid'])
|
|
|
+ ->getSingleScalarResult();
|
|
|
+
|
|
|
+ $countOfAllowed = $em
|
|
|
+ ->createQuery('SELECT COUNT(qq)
|
|
|
+ FROM ChamiloCourseBundle:CQuizQuestion qq
|
|
|
+ INNER JOIN ChamiloCourseBundle:CQuizRelQuestion qrq
|
|
|
+ WITH qq.iid = qrq.questionId
|
|
|
+ WHERE qrq.exerciceId = :id AND qq.type IN (:types)'
|
|
|
+ )
|
|
|
+ ->setParameters(
|
|
|
+ [
|
|
|
+ 'id' => $exercise['iid'],
|
|
|
+ 'types' => [UNIQUE_ANSWER, MULTIPLE_ANSWER, UNIQUE_ANSWER_IMAGE],
|
|
|
+ ]
|
|
|
+ )
|
|
|
+ ->getSingleScalarResult();
|
|
|
+
|
|
|
+ return $countAll === $countOfAllowed;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Generate a certificate linked to current quiz and.
|
|
|
+ * Return the HTML block with links to download and view the certificate.
|
|
|
+ *
|
|
|
+ * @param float $totalScore
|
|
|
+ * @param float $totalWeight
|
|
|
+ * @param Exercise $objExercise
|
|
|
+ * @param int $studentId
|
|
|
+ * @param string $courseCode
|
|
|
+ * @param int $sessionId
|
|
|
+ *
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ public static function generateAndShowCertificateBlock(
|
|
|
+ $totalScore,
|
|
|
+ $totalWeight,
|
|
|
+ Exercise $objExercise,
|
|
|
+ $studentId,
|
|
|
+ $courseCode,
|
|
|
+ $sessionId = 0
|
|
|
+ ) {
|
|
|
+ if (!api_get_configuration_value('quiz_generate_certificate_ending') ||
|
|
|
+ !self::isSuccessExerciseResult($totalScore, $totalWeight, $objExercise->selectPassPercentage())
|
|
|
+ ) {
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+
|
|
|
+ /** @var Category $category */
|
|
|
+ $category = Category::load(null, null, $courseCode, null, null, $sessionId, 'ORDER By id');
|
|
|
+
|
|
|
+ if (empty($category)) {
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+
|
|
|
+ /** @var Category $category */
|
|
|
+ $category = $category[0];
|
|
|
+ $categoryId = $category->get_id();
|
|
|
+ $link = LinkFactory::load(
|
|
|
+ null,
|
|
|
+ null,
|
|
|
+ $objExercise->selectId(),
|
|
|
+ null,
|
|
|
+ $courseCode,
|
|
|
+ $categoryId
|
|
|
+ );
|
|
|
+
|
|
|
+ if (empty($link)) {
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+
|
|
|
+ $resourceDeletedMessage = $category->show_message_resource_delete($courseCode);
|
|
|
+
|
|
|
+ if (false !== $resourceDeletedMessage || api_is_allowed_to_edit() || api_is_excluded_user_type()) {
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+
|
|
|
+ $certificate = Category::generateUserCertificate($categoryId, $studentId);
|
|
|
+
|
|
|
+ if (!is_array($certificate)) {
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+
|
|
|
+ return Category::getDownloadCertificateBlock($certificate);
|
|
|
+ }
|
|
|
}
|