|
1
|
|
|
<?php |
|
2
|
|
|
/* For licensing terms, see /license.txt */ |
|
3
|
|
|
|
|
4
|
|
|
use ChamiloSession as Session; |
|
5
|
|
|
|
|
6
|
|
|
/** |
|
7
|
|
|
* Class ExerciseLib |
|
8
|
|
|
* shows a question and its answers |
|
9
|
|
|
* @author Olivier Brouckaert <[email protected]> |
|
10
|
|
|
* @author Hubert Borderiou 2011-10-21 |
|
11
|
|
|
* @author ivantcholakov2009-07-20 |
|
12
|
|
|
* |
|
13
|
|
|
*/ |
|
14
|
|
|
class ExerciseLib |
|
15
|
|
|
{ |
|
16
|
|
|
/** |
|
17
|
|
|
* Shows a question |
|
18
|
|
|
* |
|
19
|
|
|
* @param int $questionId $questionId question id |
|
20
|
|
|
* @param bool $only_questions if true only show the questions, no exercise title |
|
21
|
|
|
* @param bool $origin i.e = learnpath |
|
22
|
|
|
* @param string $current_item current item from the list of questions |
|
23
|
|
|
* @param bool $show_title |
|
24
|
|
|
* @param bool $freeze |
|
25
|
|
|
* @param array $user_choice |
|
26
|
|
|
* @param bool $show_comment |
|
27
|
|
|
* @param null $exercise_feedback |
|
28
|
|
|
* @param bool $show_answers |
|
29
|
|
|
* @return bool|int |
|
30
|
|
|
*/ |
|
31
|
|
|
public static function showQuestion( |
|
32
|
|
|
$questionId, |
|
33
|
|
|
$only_questions = false, |
|
34
|
|
|
$origin = false, |
|
35
|
|
|
$current_item = '', |
|
36
|
|
|
$show_title = true, |
|
37
|
|
|
$freeze = false, |
|
38
|
|
|
$user_choice = array(), |
|
39
|
|
|
$show_comment = false, |
|
40
|
|
|
$exercise_feedback = null, |
|
41
|
|
|
$show_answers = false |
|
42
|
|
|
) { |
|
43
|
|
|
$course_id = api_get_course_int_id(); |
|
44
|
|
|
$course = api_get_course_info_by_id($course_id); |
|
45
|
|
|
// Change false to true in the following line to enable answer hinting |
|
46
|
|
|
$debug_mark_answer = $show_answers; |
|
47
|
|
|
|
|
48
|
|
|
// Reads question information |
|
49
|
|
|
if (!$objQuestionTmp = Question::read($questionId)) { |
|
50
|
|
|
// Question not found |
|
51
|
|
|
return false; |
|
52
|
|
|
} |
|
53
|
|
|
|
|
54
|
|
|
if ($exercise_feedback != EXERCISE_FEEDBACK_TYPE_END) { |
|
55
|
|
|
$show_comment = false; |
|
56
|
|
|
} |
|
57
|
|
|
|
|
58
|
|
|
$answerType = $objQuestionTmp->selectType(); |
|
59
|
|
|
$pictureName = $objQuestionTmp->getPictureFilename(); |
|
60
|
|
|
$s = ''; |
|
61
|
|
|
|
|
62
|
|
|
if ($answerType != HOT_SPOT && $answerType != HOT_SPOT_DELINEATION && $answerType != ANNOTATION) { |
|
63
|
|
|
// Question is not a hotspot |
|
64
|
|
|
if (!$only_questions) { |
|
65
|
|
|
$questionDescription = $objQuestionTmp->selectDescription(); |
|
66
|
|
|
if ($show_title) { |
|
67
|
|
|
TestCategory::displayCategoryAndTitle($objQuestionTmp->id); |
|
68
|
|
|
$titleToDisplay = null; |
|
69
|
|
|
if ($answerType == READING_COMPREHENSION) { |
|
70
|
|
|
// In READING_COMPREHENSION, the title of the question |
|
71
|
|
|
// contains the question itself, which can only be |
|
72
|
|
|
// shown at the end of the given time, so hide for now |
|
73
|
|
|
$titleToDisplay = Display::div( |
|
74
|
|
|
$current_item.'. '.get_lang('ReadingComprehension'), |
|
75
|
|
|
['class' => 'question_title'] |
|
76
|
|
|
); |
|
77
|
|
|
} else { |
|
78
|
|
|
$titleToDisplay = $objQuestionTmp->getTitleToDisplay($current_item); |
|
79
|
|
|
} |
|
80
|
|
|
echo $titleToDisplay; |
|
81
|
|
|
} |
|
82
|
|
|
if (!empty($questionDescription) && $answerType != READING_COMPREHENSION) { |
|
83
|
|
|
echo Display::div( |
|
84
|
|
|
$questionDescription, |
|
85
|
|
|
array('class' => 'question_description') |
|
86
|
|
|
); |
|
87
|
|
|
} |
|
88
|
|
|
} |
|
89
|
|
|
|
|
90
|
|
|
if (in_array($answerType, array(FREE_ANSWER, ORAL_EXPRESSION)) && |
|
91
|
|
|
$freeze |
|
92
|
|
|
) { |
|
93
|
|
|
return ''; |
|
94
|
|
|
} |
|
95
|
|
|
|
|
96
|
|
|
echo '<div class="question_options">'; |
|
97
|
|
|
// construction of the Answer object (also gets all answers details) |
|
98
|
|
|
$objAnswerTmp = new Answer($questionId); |
|
99
|
|
|
$nbrAnswers = $objAnswerTmp->selectNbrAnswers(); |
|
100
|
|
|
$quiz_question_options = Question::readQuestionOption( |
|
101
|
|
|
$questionId, |
|
102
|
|
|
$course_id |
|
103
|
|
|
); |
|
104
|
|
|
|
|
105
|
|
|
// For "matching" type here, we need something a little bit special |
|
106
|
|
|
// because the match between the suggestions and the answers cannot be |
|
107
|
|
|
// done easily (suggestions and answers are in the same table), so we |
|
108
|
|
|
// have to go through answers first (elems with "correct" value to 0). |
|
109
|
|
|
$select_items = array(); |
|
110
|
|
|
//This will contain the number of answers on the left side. We call them |
|
111
|
|
|
// suggestions here, for the sake of comprehensions, while the ones |
|
112
|
|
|
// on the right side are called answers |
|
113
|
|
|
$num_suggestions = 0; |
|
114
|
|
|
if (in_array($answerType, [MATCHING, DRAGGABLE, MATCHING_DRAGGABLE])) { |
|
115
|
|
|
if ($answerType == DRAGGABLE) { |
|
116
|
|
|
$isVertical = $objQuestionTmp->extra == 'v'; |
|
117
|
|
|
$s .= ' |
|
118
|
|
|
<div class="col-md-12 ui-widget ui-helper-clearfix"> |
|
119
|
|
|
<div class="clearfix"> |
|
120
|
|
|
<ul class="exercise-draggable-answer '.($isVertical ? '' : 'list-inline').'" |
|
121
|
|
|
id="question-'.$questionId.'" data-question="'.$questionId.'"> |
|
122
|
|
|
'; |
|
123
|
|
|
} else { |
|
124
|
|
|
$s .= '<div id="drag'.$questionId.'_question" class="drag_question"> |
|
125
|
|
|
<table class="data_table">'; |
|
126
|
|
|
} |
|
127
|
|
|
|
|
128
|
|
|
// Iterate through answers |
|
129
|
|
|
$x = 1; |
|
130
|
|
|
//mark letters for each answer |
|
131
|
|
|
$letter = 'A'; |
|
132
|
|
|
$answer_matching = array(); |
|
133
|
|
|
$cpt1 = array(); |
|
134
|
|
|
for ($answerId = 1; $answerId <= $nbrAnswers; $answerId++) { |
|
135
|
|
|
$answerCorrect = $objAnswerTmp->isCorrect($answerId); |
|
136
|
|
|
$numAnswer = $objAnswerTmp->selectAutoId($answerId); |
|
137
|
|
|
if ($answerCorrect == 0) { |
|
138
|
|
|
// options (A, B, C, ...) that will be put into the list-box |
|
139
|
|
|
// have the "correct" field set to 0 because they are answer |
|
140
|
|
|
$cpt1[$x] = $letter; |
|
141
|
|
|
$answer_matching[$x] = $objAnswerTmp->selectAnswerByAutoId( |
|
142
|
|
|
$numAnswer |
|
143
|
|
|
); |
|
144
|
|
|
$x++; |
|
145
|
|
|
$letter++; |
|
146
|
|
|
} |
|
147
|
|
|
} |
|
148
|
|
|
|
|
149
|
|
|
$i = 1; |
|
150
|
|
|
$select_items[0]['id'] = 0; |
|
151
|
|
|
$select_items[0]['letter'] = '--'; |
|
152
|
|
|
$select_items[0]['answer'] = ''; |
|
153
|
|
|
foreach ($answer_matching as $id => $value) { |
|
154
|
|
|
$select_items[$i]['id'] = $value['id_auto']; |
|
155
|
|
|
$select_items[$i]['letter'] = $cpt1[$id]; |
|
156
|
|
|
$select_items[$i]['answer'] = $value['answer']; |
|
157
|
|
|
$i++; |
|
158
|
|
|
} |
|
159
|
|
|
|
|
160
|
|
|
$user_choice_array_position = array(); |
|
161
|
|
|
if (!empty($user_choice)) { |
|
162
|
|
|
foreach ($user_choice as $item) { |
|
163
|
|
|
$user_choice_array_position[$item['position']] = $item['answer']; |
|
164
|
|
|
} |
|
165
|
|
|
} |
|
166
|
|
|
$num_suggestions = ($nbrAnswers - $x) + 1; |
|
167
|
|
|
} elseif ($answerType == FREE_ANSWER) { |
|
168
|
|
|
$fck_content = isset($user_choice[0]) && !empty($user_choice[0]['answer']) ? $user_choice[0]['answer'] : null; |
|
169
|
|
|
$form = new FormValidator('free_choice_'.$questionId); |
|
170
|
|
|
$config = array( |
|
171
|
|
|
'ToolbarSet' => 'TestFreeAnswer' |
|
172
|
|
|
); |
|
173
|
|
|
$form->addHtmlEditor( |
|
174
|
|
|
"choice[".$questionId."]", |
|
175
|
|
|
null, |
|
176
|
|
|
false, |
|
177
|
|
|
false, |
|
178
|
|
|
$config |
|
179
|
|
|
); |
|
180
|
|
|
$form->setDefaults( |
|
181
|
|
|
array("choice[".$questionId."]" => $fck_content) |
|
182
|
|
|
); |
|
183
|
|
|
$s .= $form->returnForm(); |
|
184
|
|
|
} elseif ($answerType == ORAL_EXPRESSION) { |
|
185
|
|
|
// Add nanog |
|
186
|
|
|
if (api_get_setting('enable_record_audio') == 'true') { |
|
187
|
|
|
//@todo pass this as a parameter |
|
188
|
|
|
global $exercise_stat_info, $exerciseId, $exe_id; |
|
189
|
|
|
|
|
190
|
|
|
if (!empty($exercise_stat_info)) { |
|
191
|
|
|
$objQuestionTmp->initFile( |
|
192
|
|
|
api_get_session_id(), |
|
193
|
|
|
api_get_user_id(), |
|
194
|
|
|
$exercise_stat_info['exe_exo_id'], |
|
195
|
|
|
$exercise_stat_info['exe_id'] |
|
196
|
|
|
); |
|
197
|
|
|
} else { |
|
198
|
|
|
$objQuestionTmp->initFile( |
|
199
|
|
|
api_get_session_id(), |
|
200
|
|
|
api_get_user_id(), |
|
201
|
|
|
$exerciseId, |
|
202
|
|
|
'temp_exe' |
|
203
|
|
|
); |
|
204
|
|
|
} |
|
205
|
|
|
|
|
206
|
|
|
echo $objQuestionTmp->returnRecorder(); |
|
207
|
|
|
} |
|
208
|
|
|
|
|
209
|
|
|
$form = new FormValidator('free_choice_'.$questionId); |
|
210
|
|
|
$config = array( |
|
211
|
|
|
'ToolbarSet' => 'TestFreeAnswer' |
|
212
|
|
|
); |
|
213
|
|
|
$form->addHtmlEditor( |
|
214
|
|
|
"choice[".$questionId."]", |
|
215
|
|
|
null, |
|
216
|
|
|
false, |
|
217
|
|
|
false, |
|
218
|
|
|
$config |
|
219
|
|
|
); |
|
220
|
|
|
$s .= $form->returnForm(); |
|
221
|
|
|
} |
|
222
|
|
|
|
|
223
|
|
|
// Now navigate through the possible answers, using the max number of |
|
224
|
|
|
// answers for the question as a limiter |
|
225
|
|
|
$lines_count = 1; // a counter for matching-type answers |
|
226
|
|
|
if ($answerType == MULTIPLE_ANSWER_TRUE_FALSE || |
|
227
|
|
|
$answerType == MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE |
|
228
|
|
|
) { |
|
229
|
|
|
$header = Display::tag('th', get_lang('Options')); |
|
230
|
|
|
foreach ($objQuestionTmp->options as $item) { |
|
231
|
|
|
if ($answerType == MULTIPLE_ANSWER_TRUE_FALSE) { |
|
232
|
|
|
if (in_array($item, $objQuestionTmp->options)) { |
|
|
|
|
|
|
233
|
|
|
$header .= Display::tag('th', get_lang($item)); |
|
234
|
|
|
} else { |
|
235
|
|
|
$header .= Display::tag('th', $item); |
|
236
|
|
|
} |
|
237
|
|
|
} else { |
|
238
|
|
|
$header .= Display::tag('th', $item); |
|
239
|
|
|
} |
|
240
|
|
|
} |
|
241
|
|
|
if ($show_comment) { |
|
242
|
|
|
$header .= Display::tag('th', get_lang('Feedback')); |
|
243
|
|
|
} |
|
244
|
|
|
$s .= '<table class="table table-hover table-striped">'; |
|
245
|
|
|
$s .= Display::tag( |
|
246
|
|
|
'tr', |
|
247
|
|
|
$header, |
|
248
|
|
|
array('style' => 'text-align:left;') |
|
249
|
|
|
); |
|
250
|
|
|
} |
|
251
|
|
|
|
|
252
|
|
|
if ($show_comment) { |
|
253
|
|
|
if (in_array( |
|
254
|
|
|
$answerType, |
|
255
|
|
|
array( |
|
256
|
|
|
MULTIPLE_ANSWER, |
|
257
|
|
|
MULTIPLE_ANSWER_COMBINATION, |
|
258
|
|
|
UNIQUE_ANSWER, |
|
259
|
|
|
UNIQUE_ANSWER_IMAGE, |
|
260
|
|
|
UNIQUE_ANSWER_NO_OPTION, |
|
261
|
|
|
GLOBAL_MULTIPLE_ANSWER, |
|
262
|
|
|
) |
|
263
|
|
|
)) { |
|
264
|
|
|
$header = Display::tag('th', get_lang('Options')); |
|
265
|
|
|
if ($exercise_feedback == EXERCISE_FEEDBACK_TYPE_END) { |
|
266
|
|
|
$header .= Display::tag('th', get_lang('Feedback')); |
|
267
|
|
|
} |
|
268
|
|
|
$s .= '<table class="table table-hover table-striped">'; |
|
269
|
|
|
$s .= Display::tag( |
|
270
|
|
|
'tr', |
|
271
|
|
|
$header, |
|
272
|
|
|
array('style' => 'text-align:left;') |
|
273
|
|
|
); |
|
274
|
|
|
} |
|
275
|
|
|
} |
|
276
|
|
|
|
|
277
|
|
|
$matching_correct_answer = 0; |
|
278
|
|
|
$user_choice_array = array(); |
|
279
|
|
|
if (!empty($user_choice)) { |
|
280
|
|
|
foreach ($user_choice as $item) { |
|
281
|
|
|
$user_choice_array[] = $item['answer']; |
|
282
|
|
|
} |
|
283
|
|
|
} |
|
284
|
|
|
|
|
285
|
|
|
$hidingClass = ''; |
|
286
|
|
|
if ($answerType == READING_COMPREHENSION) { |
|
287
|
|
|
$objQuestionTmp->processText( |
|
288
|
|
|
$objQuestionTmp->selectDescription() |
|
289
|
|
|
); |
|
290
|
|
|
$hidingClass = 'hide-reading-answers'; |
|
291
|
|
|
} |
|
292
|
|
|
if ($answerType == READING_COMPREHENSION) { |
|
293
|
|
|
$s .= Display::div( |
|
294
|
|
|
$objQuestionTmp->selectTitle(), |
|
295
|
|
|
['class' => 'question_title '.$hidingClass] |
|
296
|
|
|
); |
|
297
|
|
|
} |
|
298
|
|
|
|
|
299
|
|
|
for ($answerId = 1; $answerId <= $nbrAnswers; $answerId++) { |
|
300
|
|
|
$answer = $objAnswerTmp->selectAnswer($answerId); |
|
301
|
|
|
$answerCorrect = $objAnswerTmp->isCorrect($answerId); |
|
302
|
|
|
$numAnswer = $objAnswerTmp->selectAutoId($answerId); |
|
303
|
|
|
$comment = $objAnswerTmp->selectComment($answerId); |
|
304
|
|
|
$attributes = array(); |
|
305
|
|
|
|
|
306
|
|
|
switch ($answerType) { |
|
307
|
|
|
case UNIQUE_ANSWER: |
|
308
|
|
|
//no break |
|
309
|
|
|
case UNIQUE_ANSWER_NO_OPTION: |
|
310
|
|
|
//no break |
|
311
|
|
|
case UNIQUE_ANSWER_IMAGE: |
|
312
|
|
|
//no break |
|
313
|
|
|
case READING_COMPREHENSION: |
|
314
|
|
|
$input_id = 'choice-'.$questionId.'-'.$answerId; |
|
315
|
|
|
|
|
316
|
|
|
if (isset($user_choice[0]['answer']) && $user_choice[0]['answer'] == $numAnswer) { |
|
317
|
|
|
$attributes = array( |
|
318
|
|
|
'id' => $input_id, |
|
319
|
|
|
'checked' => 1, |
|
320
|
|
|
'selected' => 1 |
|
321
|
|
|
); |
|
322
|
|
|
} else { |
|
323
|
|
|
$attributes = array('id' => $input_id); |
|
324
|
|
|
} |
|
325
|
|
|
|
|
326
|
|
|
if ($debug_mark_answer) { |
|
327
|
|
|
if ($answerCorrect) { |
|
328
|
|
|
$attributes['checked'] = 1; |
|
329
|
|
|
$attributes['selected'] = 1; |
|
330
|
|
|
} |
|
331
|
|
|
} |
|
332
|
|
|
|
|
333
|
|
|
if ($show_comment) { |
|
334
|
|
|
$s .= '<tr><td>'; |
|
335
|
|
|
} |
|
336
|
|
|
|
|
337
|
|
|
if ($answerType == UNIQUE_ANSWER_IMAGE) { |
|
338
|
|
|
if ($show_comment) { |
|
339
|
|
|
if (empty($comment)) { |
|
340
|
|
|
$s .= '<div id="answer'.$questionId.$numAnswer.'" ' |
|
341
|
|
|
. 'class="exercise-unique-answer-image" style="text-align: center">'; |
|
342
|
|
|
} else { |
|
343
|
|
|
$s .= '<div id="answer'.$questionId.$numAnswer.'" ' |
|
344
|
|
|
. 'class="exercise-unique-answer-image col-xs-6 col-sm-12" style="text-align: center">'; |
|
345
|
|
|
} |
|
346
|
|
|
} else { |
|
347
|
|
|
$s .= '<div id="answer'.$questionId.$numAnswer.'" ' |
|
348
|
|
|
. 'class="exercise-unique-answer-image col-xs-6 col-md-3" style="text-align: center">'; |
|
349
|
|
|
} |
|
350
|
|
|
} |
|
351
|
|
|
|
|
352
|
|
|
$answer = Security::remove_XSS($answer, STUDENT); |
|
353
|
|
|
$s .= Display::input( |
|
354
|
|
|
'hidden', |
|
355
|
|
|
'choice2['.$questionId.']', |
|
356
|
|
|
'0' |
|
357
|
|
|
); |
|
358
|
|
|
|
|
359
|
|
|
$answer_input = null; |
|
360
|
|
|
|
|
361
|
|
|
if ($answerType == UNIQUE_ANSWER_IMAGE) { |
|
362
|
|
|
$attributes['style'] = 'display: none;'; |
|
363
|
|
|
$answer = '<div class="thumbnail">'.$answer.'</div>'; |
|
364
|
|
|
} |
|
365
|
|
|
|
|
366
|
|
|
$answer_input .= '<label class="radio '.$hidingClass.'">'; |
|
367
|
|
|
$answer_input .= Display::input( |
|
368
|
|
|
'radio', |
|
369
|
|
|
'choice['.$questionId.']', |
|
370
|
|
|
$numAnswer, |
|
371
|
|
|
$attributes |
|
372
|
|
|
); |
|
373
|
|
|
$answer_input .= $answer; |
|
374
|
|
|
$answer_input .= '</label>'; |
|
375
|
|
|
|
|
376
|
|
|
if ($answerType == UNIQUE_ANSWER_IMAGE) { |
|
377
|
|
|
$answer_input .= "</div>"; |
|
378
|
|
|
} |
|
379
|
|
|
|
|
380
|
|
|
if ($show_comment) { |
|
381
|
|
|
$s .= $answer_input; |
|
382
|
|
|
$s .= '</td>'; |
|
383
|
|
|
$s .= '<td>'; |
|
384
|
|
|
$s .= $comment; |
|
385
|
|
|
$s .= '</td>'; |
|
386
|
|
|
$s .= '</tr>'; |
|
387
|
|
|
} else { |
|
388
|
|
|
$s .= $answer_input; |
|
389
|
|
|
} |
|
390
|
|
|
break; |
|
391
|
|
|
case MULTIPLE_ANSWER: |
|
392
|
|
|
//no break |
|
393
|
|
|
case MULTIPLE_ANSWER_TRUE_FALSE: |
|
394
|
|
|
//no break |
|
395
|
|
|
case GLOBAL_MULTIPLE_ANSWER: |
|
396
|
|
|
$input_id = 'choice-'.$questionId.'-'.$answerId; |
|
397
|
|
|
$answer = Security::remove_XSS($answer, STUDENT); |
|
398
|
|
|
|
|
399
|
|
|
if (in_array($numAnswer, $user_choice_array)) { |
|
400
|
|
|
$attributes = array( |
|
401
|
|
|
'id' => $input_id, |
|
402
|
|
|
'checked' => 1, |
|
403
|
|
|
'selected' => 1 |
|
404
|
|
|
); |
|
405
|
|
|
} else { |
|
406
|
|
|
$attributes = array('id' => $input_id); |
|
407
|
|
|
} |
|
408
|
|
|
|
|
409
|
|
|
if ($debug_mark_answer) { |
|
410
|
|
|
if ($answerCorrect) { |
|
411
|
|
|
$attributes['checked'] = 1; |
|
412
|
|
|
$attributes['selected'] = 1; |
|
413
|
|
|
} |
|
414
|
|
|
} |
|
415
|
|
|
|
|
416
|
|
|
if ($answerType == MULTIPLE_ANSWER || $answerType == GLOBAL_MULTIPLE_ANSWER) { |
|
417
|
|
|
$s .= '<input type="hidden" name="choice2['.$questionId.']" value="0" />'; |
|
418
|
|
|
|
|
419
|
|
|
$answer_input = '<label class="checkbox">'; |
|
420
|
|
|
$answer_input .= Display::input( |
|
421
|
|
|
'checkbox', |
|
422
|
|
|
'choice['.$questionId.']['.$numAnswer.']', |
|
423
|
|
|
$numAnswer, |
|
424
|
|
|
$attributes |
|
425
|
|
|
); |
|
426
|
|
|
$answer_input .= $answer; |
|
427
|
|
|
$answer_input .= '</label>'; |
|
428
|
|
|
|
|
429
|
|
|
if ($show_comment) { |
|
430
|
|
|
$s .= '<tr><td>'; |
|
431
|
|
|
$s .= $answer_input; |
|
432
|
|
|
$s .= '</td>'; |
|
433
|
|
|
$s .= '<td>'; |
|
434
|
|
|
$s .= $comment; |
|
435
|
|
|
$s .= '</td>'; |
|
436
|
|
|
$s .= '</tr>'; |
|
437
|
|
|
} else { |
|
438
|
|
|
$s .= $answer_input; |
|
439
|
|
|
} |
|
440
|
|
|
} elseif ($answerType == MULTIPLE_ANSWER_TRUE_FALSE) { |
|
441
|
|
|
$my_choice = array(); |
|
442
|
|
|
if (!empty($user_choice_array)) { |
|
443
|
|
|
foreach ($user_choice_array as $item) { |
|
444
|
|
|
$item = explode(':', $item); |
|
445
|
|
|
$my_choice[$item[0]] = $item[1]; |
|
446
|
|
|
} |
|
447
|
|
|
} |
|
448
|
|
|
|
|
449
|
|
|
$s .= '<tr>'; |
|
450
|
|
|
$s .= Display::tag('td', $answer); |
|
451
|
|
|
|
|
452
|
|
|
if (!empty($quiz_question_options)) { |
|
453
|
|
|
foreach ($quiz_question_options as $id => $item) { |
|
454
|
|
|
if (isset($my_choice[$numAnswer]) && $id == $my_choice[$numAnswer]) { |
|
455
|
|
|
$attributes = array( |
|
456
|
|
|
'checked' => 1, |
|
457
|
|
|
'selected' => 1 |
|
458
|
|
|
); |
|
459
|
|
|
} else { |
|
460
|
|
|
$attributes = array(); |
|
461
|
|
|
} |
|
462
|
|
|
|
|
463
|
|
|
if ($debug_mark_answer) { |
|
464
|
|
|
if ($id == $answerCorrect) { |
|
465
|
|
|
$attributes['checked'] = 1; |
|
466
|
|
|
$attributes['selected'] = 1; |
|
467
|
|
|
} |
|
468
|
|
|
} |
|
469
|
|
|
$s .= Display::tag( |
|
470
|
|
|
'td', |
|
471
|
|
|
Display::input( |
|
472
|
|
|
'radio', |
|
473
|
|
|
'choice['.$questionId.']['.$numAnswer.']', |
|
474
|
|
|
$id, |
|
475
|
|
|
$attributes |
|
476
|
|
|
), |
|
477
|
|
|
array('style' => '') |
|
478
|
|
|
); |
|
479
|
|
|
} |
|
480
|
|
|
} |
|
481
|
|
|
|
|
482
|
|
|
if ($show_comment) { |
|
483
|
|
|
$s .= '<td>'; |
|
484
|
|
|
$s .= $comment; |
|
485
|
|
|
$s .= '</td>'; |
|
486
|
|
|
} |
|
487
|
|
|
$s .= '</tr>'; |
|
488
|
|
|
} |
|
489
|
|
|
break; |
|
490
|
|
|
case MULTIPLE_ANSWER_COMBINATION: |
|
491
|
|
|
// multiple answers |
|
492
|
|
|
$input_id = 'choice-'.$questionId.'-'.$answerId; |
|
493
|
|
|
|
|
494
|
|
|
if (in_array($numAnswer, $user_choice_array)) { |
|
495
|
|
|
$attributes = array( |
|
496
|
|
|
'id' => $input_id, |
|
497
|
|
|
'checked' => 1, |
|
498
|
|
|
'selected' => 1 |
|
499
|
|
|
); |
|
500
|
|
|
} else { |
|
501
|
|
|
$attributes = array('id' => $input_id); |
|
502
|
|
|
} |
|
503
|
|
|
|
|
504
|
|
|
if ($debug_mark_answer) { |
|
505
|
|
|
if ($answerCorrect) { |
|
506
|
|
|
$attributes['checked'] = 1; |
|
507
|
|
|
$attributes['selected'] = 1; |
|
508
|
|
|
} |
|
509
|
|
|
} |
|
510
|
|
|
|
|
511
|
|
|
$answer = Security::remove_XSS($answer, STUDENT); |
|
512
|
|
|
$answer_input = '<input type="hidden" name="choice2['.$questionId.']" value="0" />'; |
|
513
|
|
|
$answer_input .= '<label class="checkbox">'; |
|
514
|
|
|
$answer_input .= Display::input( |
|
515
|
|
|
'checkbox', |
|
516
|
|
|
'choice['.$questionId.']['.$numAnswer.']', |
|
517
|
|
|
1, |
|
518
|
|
|
$attributes |
|
519
|
|
|
); |
|
520
|
|
|
$answer_input .= $answer; |
|
521
|
|
|
$answer_input .= '</label>'; |
|
522
|
|
|
|
|
523
|
|
|
if ($show_comment) { |
|
524
|
|
|
$s .= '<tr>'; |
|
525
|
|
|
$s .= '<td>'; |
|
526
|
|
|
$s .= $answer_input; |
|
527
|
|
|
$s .= '</td>'; |
|
528
|
|
|
$s .= '<td>'; |
|
529
|
|
|
$s .= $comment; |
|
530
|
|
|
$s .= '</td>'; |
|
531
|
|
|
$s .= '</tr>'; |
|
532
|
|
|
} else { |
|
533
|
|
|
$s .= $answer_input; |
|
534
|
|
|
} |
|
535
|
|
|
break; |
|
536
|
|
|
case MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE: |
|
537
|
|
|
$s .= '<input type="hidden" name="choice2['.$questionId.']" value="0" />'; |
|
538
|
|
|
|
|
539
|
|
|
$my_choice = array(); |
|
540
|
|
|
if (!empty($user_choice_array)) { |
|
541
|
|
|
foreach ($user_choice_array as $item) { |
|
542
|
|
|
$item = explode(':', $item); |
|
543
|
|
|
if (isset($item[1]) && isset($item[0])) { |
|
544
|
|
|
$my_choice[$item[0]] = $item[1]; |
|
545
|
|
|
} |
|
546
|
|
|
} |
|
547
|
|
|
} |
|
548
|
|
|
$answer = Security::remove_XSS($answer, STUDENT); |
|
549
|
|
|
$s .= '<tr>'; |
|
550
|
|
|
$s .= Display::tag('td', $answer); |
|
551
|
|
|
foreach ($objQuestionTmp->options as $key => $item) { |
|
552
|
|
|
if (isset($my_choice[$numAnswer]) && $key == $my_choice[$numAnswer]) { |
|
553
|
|
|
$attributes = array( |
|
554
|
|
|
'checked' => 1, |
|
555
|
|
|
'selected' => 1 |
|
556
|
|
|
); |
|
557
|
|
|
} else { |
|
558
|
|
|
$attributes = array(); |
|
559
|
|
|
} |
|
560
|
|
|
|
|
561
|
|
|
if ($debug_mark_answer) { |
|
562
|
|
|
if ($key == $answerCorrect) { |
|
563
|
|
|
$attributes['checked'] = 1; |
|
564
|
|
|
$attributes['selected'] = 1; |
|
565
|
|
|
} |
|
566
|
|
|
} |
|
567
|
|
|
$s .= Display::tag( |
|
568
|
|
|
'td', |
|
569
|
|
|
Display::input( |
|
570
|
|
|
'radio', |
|
571
|
|
|
'choice['.$questionId.']['.$numAnswer.']', |
|
572
|
|
|
$key, |
|
573
|
|
|
$attributes |
|
574
|
|
|
) |
|
575
|
|
|
); |
|
576
|
|
|
} |
|
577
|
|
|
|
|
578
|
|
|
if ($show_comment) { |
|
579
|
|
|
$s .= '<td>'; |
|
580
|
|
|
$s .= $comment; |
|
581
|
|
|
$s .= '</td>'; |
|
582
|
|
|
} |
|
583
|
|
|
$s .= '</tr>'; |
|
584
|
|
|
break; |
|
585
|
|
|
case FILL_IN_BLANKS: |
|
586
|
|
|
// display the question, with field empty, for student to fill it, |
|
587
|
|
|
// or filled to display the answer in the Question preview of the exercise/admin.php page |
|
588
|
|
|
$displayForStudent = true; |
|
589
|
|
|
$listAnswerInfo = FillBlanks::getAnswerInfo($answer); |
|
590
|
|
|
|
|
591
|
|
|
list($answer) = explode('::', $answer); |
|
|
|
|
|
|
592
|
|
|
// Correct answers |
|
593
|
|
|
$correctAnswerList = $listAnswerInfo['tabwords']; |
|
594
|
|
|
|
|
595
|
|
|
// Student's answer |
|
596
|
|
|
$studentAnswerList = array(); |
|
597
|
|
|
if (isset($user_choice[0]['answer'])) { |
|
598
|
|
|
$arrayStudentAnswer = FillBlanks::getAnswerInfo($user_choice[0]['answer'], true); |
|
599
|
|
|
$studentAnswerList = $arrayStudentAnswer['studentanswer']; |
|
600
|
|
|
} |
|
601
|
|
|
|
|
602
|
|
|
// If the question must be shown with the answer (in page exercise/admin.php) for teacher preview |
|
603
|
|
|
// set the student-answer to the correct answer |
|
604
|
|
|
if ($debug_mark_answer) { |
|
605
|
|
|
$studentAnswerList = $correctAnswerList; |
|
606
|
|
|
$displayForStudent = false; |
|
607
|
|
|
} |
|
608
|
|
|
|
|
609
|
|
|
if (!empty($correctAnswerList) && !empty($studentAnswerList)) { |
|
610
|
|
|
$answer = ''; |
|
611
|
|
|
for ($i = 0; $i < count($listAnswerInfo['commonwords']) - 1; $i++) { |
|
612
|
|
|
// display the common word |
|
613
|
|
|
$answer .= $listAnswerInfo['commonwords'][$i]; |
|
614
|
|
|
// display the blank word |
|
615
|
|
|
$correctItem = $listAnswerInfo['tabwords'][$i]; |
|
616
|
|
|
if (isset($studentAnswerList[$i])) { |
|
617
|
|
|
// If student already started this test and answered this question, |
|
618
|
|
|
// fill the blank with his previous answers |
|
619
|
|
|
// may be "" if student viewed the question, but did not fill the blanks |
|
620
|
|
|
$correctItem = $studentAnswerList[$i]; |
|
621
|
|
|
} |
|
622
|
|
|
$attributes['style'] = "width:".$listAnswerInfo['tabinputsize'][$i]."px"; |
|
623
|
|
|
$answer .= FillBlanks::getFillTheBlankHtml( |
|
624
|
|
|
$current_item, |
|
625
|
|
|
$questionId, |
|
626
|
|
|
$correctItem, |
|
627
|
|
|
$attributes, |
|
628
|
|
|
$answer, |
|
629
|
|
|
$listAnswerInfo, |
|
630
|
|
|
$displayForStudent, |
|
631
|
|
|
$i |
|
632
|
|
|
); |
|
633
|
|
|
} |
|
634
|
|
|
// display the last common word |
|
635
|
|
|
$answer .= $listAnswerInfo['commonwords'][$i]; |
|
636
|
|
|
} else { |
|
637
|
|
|
// display empty [input] with the right width for student to fill it |
|
638
|
|
|
$answer = ''; |
|
639
|
|
|
for ($i = 0; $i < count($listAnswerInfo['commonwords']) - 1; $i++) { |
|
640
|
|
|
// display the common words |
|
641
|
|
|
$answer .= $listAnswerInfo['commonwords'][$i]; |
|
642
|
|
|
// display the blank word |
|
643
|
|
|
$attributes["style"] = "width:".$listAnswerInfo['tabinputsize'][$i]."px"; |
|
644
|
|
|
$answer .= FillBlanks::getFillTheBlankHtml( |
|
645
|
|
|
$current_item, |
|
646
|
|
|
$questionId, |
|
647
|
|
|
'', |
|
648
|
|
|
$attributes, |
|
649
|
|
|
$answer, |
|
650
|
|
|
$listAnswerInfo, |
|
651
|
|
|
$displayForStudent, |
|
652
|
|
|
$i |
|
653
|
|
|
); |
|
654
|
|
|
} |
|
655
|
|
|
// display the last common word |
|
656
|
|
|
$answer .= $listAnswerInfo['commonwords'][$i]; |
|
657
|
|
|
} |
|
658
|
|
|
$s .= $answer; |
|
659
|
|
|
break; |
|
660
|
|
|
case CALCULATED_ANSWER: |
|
661
|
|
|
/* |
|
662
|
|
|
* In the CALCULATED_ANSWER test |
|
663
|
|
|
* you mustn't have [ and ] in the textarea |
|
664
|
|
|
* you mustn't have @@ in the textarea |
|
665
|
|
|
* the text to find mustn't be empty or contains only spaces |
|
666
|
|
|
* the text to find mustn't contains HTML tags |
|
667
|
|
|
* the text to find mustn't contains char " |
|
668
|
|
|
*/ |
|
669
|
|
|
if ($origin !== null) { |
|
670
|
|
|
global $exe_id; |
|
671
|
|
|
$trackAttempts = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
|
672
|
|
|
$sql = 'SELECT answer FROM '.$trackAttempts.' |
|
673
|
|
|
WHERE exe_id=' . $exe_id.' AND question_id='.$questionId; |
|
674
|
|
|
$rsLastAttempt = Database::query($sql); |
|
675
|
|
|
$rowLastAttempt = Database::fetch_array($rsLastAttempt); |
|
676
|
|
|
$answer = $rowLastAttempt['answer']; |
|
677
|
|
|
if (empty($answer)) { |
|
678
|
|
|
$_SESSION['calculatedAnswerId'][$questionId] = mt_rand( |
|
679
|
|
|
1, |
|
680
|
|
|
$nbrAnswers |
|
681
|
|
|
); |
|
682
|
|
|
$answer = $objAnswerTmp->selectAnswer( |
|
683
|
|
|
$_SESSION['calculatedAnswerId'][$questionId] |
|
684
|
|
|
); |
|
685
|
|
|
} |
|
686
|
|
|
} |
|
687
|
|
|
|
|
688
|
|
|
list($answer) = explode('@@', $answer); |
|
689
|
|
|
// $correctAnswerList array of array with correct anwsers 0=> [0=>[\p] 1=>[plop]] |
|
690
|
|
|
api_preg_match_all( |
|
691
|
|
|
'/\[[^]]+\]/', |
|
692
|
|
|
$answer, |
|
693
|
|
|
$correctAnswerList |
|
694
|
|
|
); |
|
695
|
|
|
|
|
696
|
|
|
// get student answer to display it if student go back to previous calculated answer question in a test |
|
697
|
|
|
if (isset($user_choice[0]['answer'])) { |
|
698
|
|
|
api_preg_match_all( |
|
699
|
|
|
'/\[[^]]+\]/', |
|
700
|
|
|
$answer, |
|
701
|
|
|
$studentAnswerList |
|
702
|
|
|
); |
|
703
|
|
|
$studentAnswerListTobecleaned = $studentAnswerList[0]; |
|
704
|
|
|
$studentAnswerList = array(); |
|
705
|
|
|
|
|
706
|
|
|
for ($i = 0; $i < count( |
|
707
|
|
|
$studentAnswerListTobecleaned |
|
708
|
|
|
); $i++) { |
|
709
|
|
|
$answerCorrected = $studentAnswerListTobecleaned[$i]; |
|
710
|
|
|
$answerCorrected = api_preg_replace( |
|
711
|
|
|
'| / <font color="green"><b>.*$|', |
|
712
|
|
|
'', |
|
713
|
|
|
$answerCorrected |
|
714
|
|
|
); |
|
715
|
|
|
$answerCorrected = api_preg_replace( |
|
716
|
|
|
'/^\[/', |
|
717
|
|
|
'', |
|
718
|
|
|
$answerCorrected |
|
719
|
|
|
); |
|
720
|
|
|
$answerCorrected = api_preg_replace( |
|
721
|
|
|
'|^<font color="red"><s>|', |
|
722
|
|
|
'', |
|
723
|
|
|
$answerCorrected |
|
724
|
|
|
); |
|
725
|
|
|
$answerCorrected = api_preg_replace( |
|
726
|
|
|
'|</s></font>$|', |
|
727
|
|
|
'', |
|
728
|
|
|
$answerCorrected |
|
729
|
|
|
); |
|
730
|
|
|
$answerCorrected = '['.$answerCorrected.']'; |
|
731
|
|
|
$studentAnswerList[] = $answerCorrected; |
|
732
|
|
|
} |
|
733
|
|
|
} |
|
734
|
|
|
|
|
735
|
|
|
// If display preview of answer in test view for exemple, set the student answer to the correct answers |
|
736
|
|
|
if ($debug_mark_answer) { |
|
737
|
|
|
// contain the rights answers surronded with brackets |
|
738
|
|
|
$studentAnswerList = $correctAnswerList[0]; |
|
739
|
|
|
} |
|
740
|
|
|
|
|
741
|
|
|
/* |
|
742
|
|
|
Split the response by bracket |
|
743
|
|
|
tabComments is an array with text surrounding the text to find |
|
744
|
|
|
we add a space before and after the answerQuestion to be sure to |
|
745
|
|
|
have a block of text before and after [xxx] patterns |
|
746
|
|
|
so we have n text to find ([xxx]) and n+1 block of texts before, |
|
747
|
|
|
between and after the text to find |
|
748
|
|
|
*/ |
|
749
|
|
|
$tabComments = api_preg_split( |
|
750
|
|
|
'/\[[^]]+\]/', |
|
751
|
|
|
' '.$answer.' ' |
|
752
|
|
|
); |
|
753
|
|
|
if (!empty($correctAnswerList) && !empty($studentAnswerList)) { |
|
754
|
|
|
$answer = ""; |
|
755
|
|
|
$i = 0; |
|
756
|
|
|
foreach ($studentAnswerList as $studentItem) { |
|
757
|
|
|
// remove surronding brackets |
|
758
|
|
|
$studentResponse = api_substr( |
|
759
|
|
|
$studentItem, |
|
760
|
|
|
1, |
|
761
|
|
|
api_strlen($studentItem) - 2 |
|
762
|
|
|
); |
|
763
|
|
|
$size = strlen($studentItem); |
|
764
|
|
|
$attributes['class'] = self::detectInputAppropriateClass( |
|
765
|
|
|
$size |
|
766
|
|
|
); |
|
767
|
|
|
|
|
768
|
|
|
$answer .= $tabComments[$i]. |
|
769
|
|
|
Display::input( |
|
770
|
|
|
'text', |
|
771
|
|
|
"choice[$questionId][]", |
|
772
|
|
|
$studentResponse, |
|
773
|
|
|
$attributes |
|
774
|
|
|
); |
|
775
|
|
|
$i++; |
|
776
|
|
|
} |
|
777
|
|
|
$answer .= $tabComments[$i]; |
|
778
|
|
|
} else { |
|
779
|
|
|
// display exercise with empty input fields |
|
780
|
|
|
// every [xxx] are replaced with an empty input field |
|
781
|
|
|
foreach ($correctAnswerList[0] as $item) { |
|
782
|
|
|
$size = strlen($item); |
|
783
|
|
|
$attributes['class'] = self::detectInputAppropriateClass( |
|
784
|
|
|
$size |
|
785
|
|
|
); |
|
786
|
|
|
$answer = str_replace( |
|
787
|
|
|
$item, |
|
788
|
|
|
Display::input( |
|
789
|
|
|
'text', |
|
790
|
|
|
"choice[$questionId][]", |
|
791
|
|
|
'', |
|
792
|
|
|
$attributes |
|
793
|
|
|
), |
|
794
|
|
|
$answer |
|
795
|
|
|
); |
|
796
|
|
|
} |
|
797
|
|
|
} |
|
798
|
|
|
if ($origin !== null) { |
|
799
|
|
|
$s = $answer; |
|
800
|
|
|
break; |
|
801
|
|
|
} else { |
|
802
|
|
|
$s .= $answer; |
|
803
|
|
|
} |
|
804
|
|
|
break; |
|
805
|
|
|
case MATCHING: |
|
806
|
|
|
// matching type, showing suggestions and answers |
|
807
|
|
|
// TODO: replace $answerId by $numAnswer |
|
808
|
|
|
if ($answerCorrect != 0) { |
|
809
|
|
|
// only show elements to be answered (not the contents of |
|
810
|
|
|
// the select boxes, who are correct = 0) |
|
811
|
|
|
$s .= '<tr><td width="45%" valign="top">'; |
|
812
|
|
|
$parsed_answer = $answer; |
|
813
|
|
|
// Left part questions |
|
814
|
|
|
$s .= '<p class="indent">'.$lines_count.'. '.$parsed_answer.'</p></td>'; |
|
815
|
|
|
// Middle part (matches selects) |
|
816
|
|
|
// Id of select is # question + # of option |
|
817
|
|
|
$s .= '<td width="10%" valign="top" align="center"> |
|
818
|
|
|
<div class="select-matching"> |
|
819
|
|
|
<select id="choice_id_'.$current_item.'_'.$lines_count.'" name="choice['.$questionId.']['.$numAnswer.']">'; |
|
820
|
|
|
|
|
821
|
|
|
// fills the list-box |
|
822
|
|
|
foreach ($select_items as $key => $val) { |
|
823
|
|
|
// set $debug_mark_answer to true at function start to |
|
824
|
|
|
// show the correct answer with a suffix '-x' |
|
825
|
|
|
$selected = ''; |
|
826
|
|
|
if ($debug_mark_answer) { |
|
827
|
|
|
if ($val['id'] == $answerCorrect) { |
|
828
|
|
|
$selected = 'selected="selected"'; |
|
829
|
|
|
} |
|
830
|
|
|
} |
|
831
|
|
|
//$user_choice_array_position |
|
832
|
|
|
if (isset($user_choice_array_position[$numAnswer]) && $val['id'] == $user_choice_array_position[$numAnswer]) { |
|
833
|
|
|
$selected = 'selected="selected"'; |
|
834
|
|
|
} |
|
835
|
|
|
$s .= '<option value="'.$val['id'].'" '.$selected.'>'.$val['letter'].'</option>'; |
|
836
|
|
|
|
|
837
|
|
|
} // end foreach() |
|
838
|
|
|
|
|
839
|
|
|
$s .= '</select></div></td><td width="5%" class="separate"> </td>'; |
|
840
|
|
|
$s .= '<td width="40%" valign="top" >'; |
|
841
|
|
|
if (isset($select_items[$lines_count])) { |
|
842
|
|
|
$s .= '<div class="text-right"><p class="indent">'.$select_items[$lines_count]['letter'].'. '.$select_items[$lines_count]['answer'].'</p></div>'; |
|
843
|
|
|
} else { |
|
844
|
|
|
$s .= ' '; |
|
845
|
|
|
} |
|
846
|
|
|
$s .= '</td>'; |
|
847
|
|
|
$s .= '</tr>'; |
|
848
|
|
|
$lines_count++; |
|
849
|
|
|
//if the left side of the "matching" has been completely |
|
850
|
|
|
// shown but the right side still has values to show... |
|
851
|
|
|
if (($lines_count - 1) == $num_suggestions) { |
|
852
|
|
|
// if it remains answers to shown at the right side |
|
853
|
|
|
while (isset($select_items[$lines_count])) { |
|
854
|
|
|
$s .= '<tr> |
|
855
|
|
|
<td colspan="2"></td> |
|
856
|
|
|
<td valign="top">'; |
|
857
|
|
|
$s .= '<b>'.$select_items[$lines_count]['letter'].'.</b> '.$select_items[$lines_count]['answer']; |
|
858
|
|
|
$s .= "</td> |
|
859
|
|
|
</tr>"; |
|
860
|
|
|
$lines_count++; |
|
861
|
|
|
} // end while() |
|
862
|
|
|
} // end if() |
|
863
|
|
|
$matching_correct_answer++; |
|
864
|
|
|
} |
|
865
|
|
|
break; |
|
866
|
|
|
case DRAGGABLE: |
|
867
|
|
|
if ($answerCorrect) { |
|
868
|
|
|
$parsed_answer = $answer; |
|
869
|
|
|
/*$lines_count = ''; |
|
870
|
|
|
$data = $objAnswerTmp->getAnswerByAutoId($numAnswer); |
|
871
|
|
|
$data = $objAnswerTmp->getAnswerByAutoId($data['correct']); |
|
872
|
|
|
$lines_count = $data['answer'];*/ |
|
873
|
|
|
$windowId = $questionId.'_'.$lines_count; |
|
874
|
|
|
$s .= '<li class="touch-items" id="'.$windowId.'">'; |
|
875
|
|
|
$s .= Display::div( |
|
876
|
|
|
$parsed_answer, |
|
877
|
|
|
[ |
|
878
|
|
|
'id' => "window_$windowId", |
|
879
|
|
|
'class' => "window{$questionId}_question_draggable exercise-draggable-answer-option" |
|
880
|
|
|
] |
|
881
|
|
|
); |
|
882
|
|
|
|
|
883
|
|
|
$draggableSelectOptions = []; |
|
884
|
|
|
$selectedValue = 0; |
|
885
|
|
|
$selectedIndex = 0; |
|
886
|
|
|
|
|
887
|
|
View Code Duplication |
if ($user_choice) { |
|
888
|
|
|
foreach ($user_choice as $chosen) { |
|
889
|
|
|
if ($answerCorrect != $chosen['answer']) { |
|
890
|
|
|
continue; |
|
891
|
|
|
} |
|
892
|
|
|
|
|
893
|
|
|
$selectedValue = $chosen['answer']; |
|
894
|
|
|
} |
|
895
|
|
|
} |
|
896
|
|
|
|
|
897
|
|
|
foreach ($select_items as $key => $select_item) { |
|
898
|
|
|
$draggableSelectOptions[$select_item['id']] = $select_item['letter']; |
|
899
|
|
|
} |
|
900
|
|
|
|
|
901
|
|
|
foreach ($draggableSelectOptions as $value => $text) { |
|
902
|
|
|
if ($value == $selectedValue) { |
|
903
|
|
|
break; |
|
904
|
|
|
} |
|
905
|
|
|
$selectedIndex++; |
|
906
|
|
|
} |
|
907
|
|
|
|
|
908
|
|
|
$s .= Display::select( |
|
909
|
|
|
"choice[$questionId][$numAnswer]", |
|
910
|
|
|
$draggableSelectOptions, |
|
911
|
|
|
$selectedValue, |
|
912
|
|
|
[ |
|
913
|
|
|
'id' => "window_{$windowId}_select", |
|
914
|
|
|
'class' => 'select_option hidden', |
|
915
|
|
|
], |
|
916
|
|
|
false |
|
917
|
|
|
); |
|
918
|
|
|
|
|
919
|
|
|
if ($selectedValue && $selectedIndex) { |
|
920
|
|
|
$s .= " |
|
921
|
|
|
<script> |
|
922
|
|
|
$(function() { |
|
923
|
|
|
DraggableAnswer.deleteItem( |
|
924
|
|
|
$('#{$questionId}_$lines_count'), |
|
925
|
|
|
$('#drop_{$questionId}_{$selectedIndex}') |
|
926
|
|
|
); |
|
927
|
|
|
}); |
|
928
|
|
|
</script> |
|
929
|
|
|
"; |
|
930
|
|
|
} |
|
931
|
|
|
|
|
932
|
|
|
if (isset($select_items[$lines_count])) { |
|
933
|
|
|
$s .= Display::div( |
|
934
|
|
|
Display::tag( |
|
935
|
|
|
'b', |
|
936
|
|
|
$select_items[$lines_count]['letter'] |
|
937
|
|
|
).$select_items[$lines_count]['answer'], |
|
938
|
|
|
[ |
|
939
|
|
|
'id' => "window_{$windowId}_answer", |
|
940
|
|
|
'class' => 'hidden' |
|
941
|
|
|
] |
|
942
|
|
|
); |
|
943
|
|
|
} else { |
|
944
|
|
|
$s .= ' '; |
|
945
|
|
|
} |
|
946
|
|
|
|
|
947
|
|
|
$lines_count++; |
|
948
|
|
|
|
|
949
|
|
|
if (($lines_count - 1) == $num_suggestions) { |
|
950
|
|
|
while (isset($select_items[$lines_count])) { |
|
951
|
|
|
$s .= Display::tag('b', $select_items[$lines_count]['letter']); |
|
952
|
|
|
$s .= $select_items[$lines_count]['answer']; |
|
953
|
|
|
$lines_count++; |
|
954
|
|
|
} |
|
955
|
|
|
} |
|
956
|
|
|
|
|
957
|
|
|
$matching_correct_answer++; |
|
958
|
|
|
|
|
959
|
|
|
$s .= '</li>'; |
|
960
|
|
|
} |
|
961
|
|
|
break; |
|
962
|
|
|
case MATCHING_DRAGGABLE: |
|
963
|
|
|
if ($answerId == 1) { |
|
964
|
|
|
echo $objAnswerTmp->getJs(); |
|
965
|
|
|
} |
|
966
|
|
|
|
|
967
|
|
|
if ($answerCorrect != 0) { |
|
968
|
|
|
$parsed_answer = $answer; |
|
969
|
|
|
$windowId = "{$questionId}_{$lines_count}"; |
|
970
|
|
|
|
|
971
|
|
|
$s .= <<<HTML |
|
972
|
|
|
<tr> |
|
973
|
|
|
<td widht="45%"> |
|
974
|
|
|
<div id="window_{$windowId}" class="window window_left_question window{$questionId}_question"> |
|
975
|
|
|
<strong>$lines_count.</strong> $parsed_answer |
|
976
|
|
|
</div> |
|
977
|
|
|
</td> |
|
978
|
|
|
<td width="10%"> |
|
979
|
|
|
HTML; |
|
980
|
|
|
|
|
981
|
|
|
$draggableSelectOptions = []; |
|
982
|
|
|
$selectedValue = 0; |
|
983
|
|
|
$selectedIndex = 0; |
|
984
|
|
|
|
|
985
|
|
View Code Duplication |
if ($user_choice) { |
|
986
|
|
|
foreach ($user_choice as $chosen) { |
|
987
|
|
|
if ($answerCorrect != $chosen['answer']) { |
|
988
|
|
|
continue; |
|
989
|
|
|
} |
|
990
|
|
|
$selectedValue = $chosen['answer']; |
|
991
|
|
|
} |
|
992
|
|
|
} |
|
993
|
|
|
|
|
994
|
|
|
foreach ($select_items as $key => $select_item) { |
|
995
|
|
|
$draggableSelectOptions[$select_item['id']] = $select_item['letter']; |
|
996
|
|
|
} |
|
997
|
|
|
|
|
998
|
|
|
foreach ($draggableSelectOptions as $value => $text) { |
|
999
|
|
|
if ($value == $selectedValue) { |
|
1000
|
|
|
break; |
|
1001
|
|
|
} |
|
1002
|
|
|
$selectedIndex++; |
|
1003
|
|
|
} |
|
1004
|
|
|
|
|
1005
|
|
|
$s .= Display::select( |
|
1006
|
|
|
"choice[$questionId][$numAnswer]", |
|
1007
|
|
|
$draggableSelectOptions, |
|
1008
|
|
|
$selectedValue, |
|
1009
|
|
|
[ |
|
1010
|
|
|
'id' => "window_{$windowId}_select", |
|
1011
|
|
|
'class' => 'hidden' |
|
1012
|
|
|
], |
|
1013
|
|
|
false |
|
1014
|
|
|
); |
|
1015
|
|
|
|
|
1016
|
|
|
if (!empty($answerCorrect) && !empty($selectedValue)) { |
|
1017
|
|
|
// Show connect if is not freeze (question preview) |
|
1018
|
|
|
if (!$freeze) { |
|
1019
|
|
|
$s .= " |
|
1020
|
|
|
<script> |
|
1021
|
|
|
$(document).on('ready', function () { |
|
1022
|
|
|
jsPlumb.ready(function() { |
|
1023
|
|
|
jsPlumb.connect({ |
|
1024
|
|
|
source: 'window_$windowId', |
|
1025
|
|
|
target: 'window_{$questionId}_{$selectedIndex}_answer', |
|
1026
|
|
|
endpoint: ['Blank', {radius: 15}], |
|
1027
|
|
|
anchors: ['RightMiddle', 'LeftMiddle'], |
|
1028
|
|
|
paintStyle: {strokeStyle: '#8A8888', lineWidth: 8}, |
|
1029
|
|
|
connector: [ |
|
1030
|
|
|
MatchingDraggable.connectorType, |
|
1031
|
|
|
{curvines: MatchingDraggable.curviness} |
|
1032
|
|
|
] |
|
1033
|
|
|
}); |
|
1034
|
|
|
}); |
|
1035
|
|
|
}); |
|
1036
|
|
|
</script> |
|
1037
|
|
|
"; |
|
1038
|
|
|
} |
|
1039
|
|
|
} |
|
1040
|
|
|
|
|
1041
|
|
|
$s .= <<<HTML |
|
1042
|
|
|
</td> |
|
1043
|
|
|
<td width="45%"> |
|
1044
|
|
|
HTML; |
|
1045
|
|
|
|
|
1046
|
|
View Code Duplication |
if (isset($select_items[$lines_count])) { |
|
1047
|
|
|
$s .= <<<HTML |
|
1048
|
|
|
<div id="window_{$windowId}_answer" class="window window_right_question"> |
|
1049
|
|
|
<strong>{$select_items[$lines_count]['letter']}.</strong> {$select_items[$lines_count]['answer']} |
|
1050
|
|
|
</div> |
|
1051
|
|
|
HTML; |
|
1052
|
|
|
} else { |
|
1053
|
|
|
$s .= ' '; |
|
1054
|
|
|
} |
|
1055
|
|
|
|
|
1056
|
|
|
$s .= '</td></tr>'; |
|
1057
|
|
|
|
|
1058
|
|
|
$lines_count++; |
|
1059
|
|
|
|
|
1060
|
|
View Code Duplication |
if (($lines_count - 1) == $num_suggestions) { |
|
1061
|
|
|
while (isset($select_items[$lines_count])) { |
|
1062
|
|
|
$s .= <<<HTML |
|
1063
|
|
|
<tr> |
|
1064
|
|
|
<td colspan="2"></td> |
|
1065
|
|
|
<td> |
|
1066
|
|
|
<strong>{$select_items[$lines_count]['letter']}</strong> |
|
1067
|
|
|
{$select_items[$lines_count]['answer']} |
|
1068
|
|
|
</td> |
|
1069
|
|
|
</tr> |
|
1070
|
|
|
HTML; |
|
1071
|
|
|
$lines_count++; |
|
1072
|
|
|
} |
|
1073
|
|
|
} |
|
1074
|
|
|
$matching_correct_answer++; |
|
1075
|
|
|
} |
|
1076
|
|
|
break; |
|
1077
|
|
|
} |
|
1078
|
|
|
} // end for() |
|
1079
|
|
|
|
|
1080
|
|
|
if ($show_comment) { |
|
1081
|
|
|
$s .= '</table>'; |
|
1082
|
|
|
} elseif (in_array( |
|
1083
|
|
|
$answerType, |
|
1084
|
|
|
[ |
|
1085
|
|
|
MATCHING, |
|
1086
|
|
|
MATCHING_DRAGGABLE, |
|
1087
|
|
|
UNIQUE_ANSWER_NO_OPTION, |
|
1088
|
|
|
MULTIPLE_ANSWER_TRUE_FALSE, |
|
1089
|
|
|
MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE, |
|
1090
|
|
|
] |
|
1091
|
|
|
)) { |
|
1092
|
|
|
$s .= '</table>'; |
|
1093
|
|
|
} |
|
1094
|
|
|
|
|
1095
|
|
|
if ($answerType == DRAGGABLE) { |
|
1096
|
|
|
$isVertical = $objQuestionTmp->extra == 'v'; |
|
1097
|
|
|
|
|
1098
|
|
|
$s .= "</ul>"; |
|
1099
|
|
|
$s .= "</div>"; //clearfix |
|
1100
|
|
|
$counterAnswer = 1; |
|
1101
|
|
|
$s .= $isVertical ? '' : '<div class="row">'; |
|
1102
|
|
|
|
|
1103
|
|
|
for ($answerId = 1; $answerId <= $nbrAnswers; $answerId++) { |
|
1104
|
|
|
$answerCorrect = $objAnswerTmp->isCorrect($answerId); |
|
1105
|
|
|
$windowId = $questionId.'_'.$counterAnswer; |
|
1106
|
|
|
if ($answerCorrect) { |
|
1107
|
|
|
$s .= $isVertical ? '<div class="row">' : ''; |
|
1108
|
|
|
$s .= ' |
|
1109
|
|
|
<div class="'.($isVertical ? 'col-md-12' : 'col-xs-12 col-sm-4 col-md-3 col-lg-2').'"> |
|
1110
|
|
|
<div id="drop_'.$windowId.'" class="droppable"> </div> |
|
1111
|
|
|
</div> |
|
1112
|
|
|
'; |
|
1113
|
|
|
$s .= $isVertical ? '</div>' : ''; |
|
1114
|
|
|
|
|
1115
|
|
|
$counterAnswer++; |
|
1116
|
|
|
} |
|
1117
|
|
|
} |
|
1118
|
|
|
|
|
1119
|
|
|
$s .= $isVertical ? '' : '</div>'; // row |
|
1120
|
|
|
$s .= '</div>'; // col-md-12 ui-widget ui-helper-clearfix |
|
1121
|
|
|
} |
|
1122
|
|
|
|
|
1123
|
|
|
if (in_array($answerType, [MATCHING, MATCHING_DRAGGABLE])) { |
|
1124
|
|
|
$s .= '</div>'; //drag_question |
|
1125
|
|
|
} |
|
1126
|
|
|
|
|
1127
|
|
|
$s .= '</div>'; //question_options row |
|
1128
|
|
|
|
|
1129
|
|
|
// destruction of the Answer object |
|
1130
|
|
|
unset($objAnswerTmp); |
|
1131
|
|
|
|
|
1132
|
|
|
// destruction of the Question object |
|
1133
|
|
|
unset($objQuestionTmp); |
|
1134
|
|
|
|
|
1135
|
|
|
if ($origin == 'export') { |
|
1136
|
|
|
return $s; |
|
1137
|
|
|
} |
|
1138
|
|
|
|
|
1139
|
|
|
echo $s; |
|
1140
|
|
|
} elseif ($answerType == HOT_SPOT || $answerType == HOT_SPOT_DELINEATION) { |
|
1141
|
|
|
global $exerciseId, $exe_id; |
|
1142
|
|
|
// Question is a HOT_SPOT |
|
1143
|
|
|
//checking document/images visibility |
|
1144
|
|
|
if (api_is_platform_admin() || api_is_course_admin()) { |
|
1145
|
|
|
$doc_id = $objQuestionTmp->getPictureId(); |
|
1146
|
|
View Code Duplication |
if (is_numeric($doc_id)) { |
|
1147
|
|
|
$images_folder_visibility = api_get_item_visibility( |
|
1148
|
|
|
$course, |
|
1149
|
|
|
'document', |
|
1150
|
|
|
$doc_id, |
|
1151
|
|
|
api_get_session_id() |
|
1152
|
|
|
); |
|
1153
|
|
|
if (!$images_folder_visibility) { |
|
1154
|
|
|
//This message is shown only to the course/platform admin if the image is set to visibility = false |
|
1155
|
|
|
echo Display::return_message( |
|
1156
|
|
|
get_lang('ChangeTheVisibilityOfTheCurrentImage'), |
|
1157
|
|
|
'warning' |
|
1158
|
|
|
); |
|
1159
|
|
|
} |
|
1160
|
|
|
} |
|
1161
|
|
|
} |
|
1162
|
|
|
$questionName = $objQuestionTmp->selectTitle(); |
|
1163
|
|
|
$questionDescription = $objQuestionTmp->selectDescription(); |
|
1164
|
|
|
|
|
1165
|
|
|
// Get the answers, make a list |
|
1166
|
|
|
$objAnswerTmp = new Answer($questionId); |
|
1167
|
|
|
$nbrAnswers = $objAnswerTmp->selectNbrAnswers(); |
|
1168
|
|
|
|
|
1169
|
|
|
// get answers of hotpost |
|
1170
|
|
|
$answers_hotspot = array(); |
|
1171
|
|
|
for ($answerId = 1; $answerId <= $nbrAnswers; $answerId++) { |
|
1172
|
|
|
$answers = $objAnswerTmp->selectAnswerByAutoId( |
|
1173
|
|
|
$objAnswerTmp->selectAutoId($answerId) |
|
1174
|
|
|
); |
|
1175
|
|
|
$answers_hotspot[$answers['id']] = $objAnswerTmp->selectAnswer( |
|
1176
|
|
|
$answerId |
|
1177
|
|
|
); |
|
1178
|
|
|
} |
|
1179
|
|
|
|
|
1180
|
|
|
$answerList = ''; |
|
1181
|
|
|
$hotspotColor = 0; |
|
1182
|
|
|
if ($answerType != HOT_SPOT_DELINEATION) { |
|
1183
|
|
|
$answerList = ' |
|
1184
|
|
|
<div class="well well-sm"> |
|
1185
|
|
|
<h5 class="page-header">' . get_lang('HotspotZones').'</h5> |
|
1186
|
|
|
<ol> |
|
1187
|
|
|
'; |
|
1188
|
|
|
|
|
1189
|
|
|
if (!empty($answers_hotspot)) { |
|
1190
|
|
|
Session::write("hotspot_ordered$questionId", array_keys($answers_hotspot)); |
|
1191
|
|
|
foreach ($answers_hotspot as $value) { |
|
1192
|
|
|
$answerList .= "<li>"; |
|
1193
|
|
|
if ($freeze) { |
|
1194
|
|
|
$answerList .= '<span class="hotspot-color-'.$hotspotColor |
|
1195
|
|
|
.' fa fa-square" aria-hidden="true"></span>'.PHP_EOL; |
|
1196
|
|
|
} |
|
1197
|
|
|
$answerList .= $value; |
|
1198
|
|
|
$answerList .= "</li>"; |
|
1199
|
|
|
$hotspotColor++; |
|
1200
|
|
|
} |
|
1201
|
|
|
} |
|
1202
|
|
|
|
|
1203
|
|
|
$answerList .= ' |
|
1204
|
|
|
</ul> |
|
1205
|
|
|
</div> |
|
1206
|
|
|
'; |
|
1207
|
|
|
|
|
1208
|
|
|
if ($freeze) { |
|
1209
|
|
|
$relPath = api_get_path(WEB_CODE_PATH); |
|
1210
|
|
|
echo " |
|
1211
|
|
|
<div class=\"row\"> |
|
1212
|
|
|
<div class=\"col-sm-9\"> |
|
1213
|
|
|
<div id=\"hotspot-preview-$questionId\"></div> |
|
1214
|
|
|
</div> |
|
1215
|
|
|
<div class=\"col-sm-3\"> |
|
1216
|
|
|
$answerList |
|
1217
|
|
|
</div> |
|
1218
|
|
|
</div> |
|
1219
|
|
|
<script> |
|
1220
|
|
|
new ".($answerType == HOT_SPOT ? "HotspotQuestion" : "DelineationQuestion")."({ |
|
1221
|
|
|
questionId: $questionId, |
|
1222
|
|
|
exerciseId: $exerciseId, |
|
1223
|
|
|
selector: '#hotspot-preview-$questionId', |
|
1224
|
|
|
for: 'preview', |
|
1225
|
|
|
relPath: '$relPath' |
|
1226
|
|
|
}); |
|
1227
|
|
|
</script> |
|
1228
|
|
|
"; |
|
1229
|
|
|
return; |
|
1230
|
|
|
} |
|
1231
|
|
|
} |
|
1232
|
|
|
|
|
1233
|
|
|
if (!$only_questions) { |
|
1234
|
|
|
if ($show_title) { |
|
1235
|
|
|
TestCategory::displayCategoryAndTitle($objQuestionTmp->id); |
|
1236
|
|
|
|
|
1237
|
|
|
echo $objQuestionTmp->getTitleToDisplay($current_item); |
|
1238
|
|
|
} |
|
1239
|
|
|
//@todo I need to the get the feedback type |
|
1240
|
|
|
echo <<<HOTSPOT |
|
1241
|
|
|
<input type="hidden" name="hidden_hotspot_id" value="$questionId" /> |
|
1242
|
|
|
<div class="exercise_questions"> |
|
1243
|
|
|
$questionDescription |
|
1244
|
|
|
<div class="row"> |
|
1245
|
|
|
HOTSPOT; |
|
1246
|
|
|
} |
|
1247
|
|
|
|
|
1248
|
|
|
$relPath = api_get_path(WEB_CODE_PATH); |
|
1249
|
|
|
$s .= " |
|
1250
|
|
|
<div class=\"col-sm-8 col-md-9\"> |
|
1251
|
|
|
<div class=\"hotspot-image\"></div> |
|
1252
|
|
|
<script> |
|
1253
|
|
|
$(document).on('ready', function () { |
|
1254
|
|
|
new " . ($answerType == HOT_SPOT_DELINEATION ? 'DelineationQuestion' : 'HotspotQuestion')."({ |
|
1255
|
|
|
questionId: $questionId, |
|
1256
|
|
|
exerciseId: $exe_id, |
|
1257
|
|
|
selector: '#question_div_' + $questionId + ' .hotspot-image', |
|
1258
|
|
|
for: 'user', |
|
1259
|
|
|
relPath: '$relPath' |
|
1260
|
|
|
}); |
|
1261
|
|
|
}); |
|
1262
|
|
|
</script> |
|
1263
|
|
|
</div> |
|
1264
|
|
|
<div class=\"col-sm-4 col-md-3\"> |
|
1265
|
|
|
$answerList |
|
1266
|
|
|
</div> |
|
1267
|
|
|
"; |
|
1268
|
|
|
|
|
1269
|
|
|
echo <<<HOTSPOT |
|
1270
|
|
|
$s |
|
1271
|
|
|
</div> |
|
1272
|
|
|
</div> |
|
1273
|
|
|
HOTSPOT; |
|
1274
|
|
|
} elseif ($answerType == ANNOTATION) { |
|
1275
|
|
|
global $exe_id; |
|
1276
|
|
|
$relPath = api_get_path(WEB_CODE_PATH); |
|
1277
|
|
|
if (api_is_platform_admin() || api_is_course_admin()) { |
|
1278
|
|
|
$docId = DocumentManager::get_document_id($course, '/images/'.$pictureName); |
|
1279
|
|
View Code Duplication |
if ($docId) { |
|
|
|
|
|
|
1280
|
|
|
$images_folder_visibility = api_get_item_visibility( |
|
1281
|
|
|
$course, |
|
1282
|
|
|
'document', |
|
1283
|
|
|
$docId, |
|
1284
|
|
|
api_get_session_id() |
|
1285
|
|
|
); |
|
1286
|
|
|
|
|
1287
|
|
|
if (!$images_folder_visibility) { |
|
1288
|
|
|
echo Display::return_message(get_lang('ChangeTheVisibilityOfTheCurrentImage'), 'warning'); |
|
1289
|
|
|
} |
|
1290
|
|
|
} |
|
1291
|
|
|
|
|
1292
|
|
|
if ($freeze) { |
|
1293
|
|
|
echo Display::img( |
|
1294
|
|
|
api_get_path(WEB_COURSE_PATH).$course['path'].'/document/images/'.$pictureName, |
|
1295
|
|
|
$objQuestionTmp->selectTitle(), |
|
1296
|
|
|
['width' => '600px'] |
|
1297
|
|
|
); |
|
1298
|
|
|
|
|
1299
|
|
|
return 0; |
|
1300
|
|
|
} |
|
1301
|
|
|
} |
|
1302
|
|
|
|
|
1303
|
|
|
if (!$only_questions) { |
|
1304
|
|
|
if ($show_title) { |
|
1305
|
|
|
TestCategory::displayCategoryAndTitle($objQuestionTmp->id); |
|
1306
|
|
|
echo $objQuestionTmp->getTitleToDisplay($current_item); |
|
1307
|
|
|
} |
|
1308
|
|
|
echo ' |
|
1309
|
|
|
<input type="hidden" name="hidden_hotspot_id" value="'.$questionId.'" /> |
|
1310
|
|
|
<div class="exercise_questions"> |
|
1311
|
|
|
'.$objQuestionTmp->selectDescription().' |
|
1312
|
|
|
<div class="row"> |
|
1313
|
|
|
<div class="col-sm-8 col-md-9"> |
|
1314
|
|
|
<div id="annotation-canvas-'.$questionId.'" class="annotation-canvas center-block"> |
|
1315
|
|
|
</div> |
|
1316
|
|
|
<script> |
|
1317
|
|
|
AnnotationQuestion({ |
|
1318
|
|
|
questionId: '.$questionId.', |
|
1319
|
|
|
exerciseId: '.$exe_id.', |
|
1320
|
|
|
relPath: \''.$relPath.'\' |
|
1321
|
|
|
}); |
|
1322
|
|
|
</script> |
|
1323
|
|
|
</div> |
|
1324
|
|
|
<div class="col-sm-4 col-md-3"> |
|
1325
|
|
|
<div class="well well-sm" id="annotation-toolbar-'.$questionId.'"> |
|
1326
|
|
|
<div class="btn-toolbar"> |
|
1327
|
|
|
<div class="btn-group" data-toggle="buttons"> |
|
1328
|
|
|
<label class="btn btn-default active" |
|
1329
|
|
|
aria-label="'.get_lang('AddAnnotationPath').'"> |
|
1330
|
|
|
<input type="radio" value="0" name="'.$questionId.'-options" autocomplete="off" checked> |
|
1331
|
|
|
<span class="fa fa-pencil" aria-hidden="true"></span> |
|
1332
|
|
|
</label> |
|
1333
|
|
|
<label class="btn btn-default" |
|
1334
|
|
|
aria-label="'.get_lang('AddAnnotationText').'"> |
|
1335
|
|
|
<input type="radio" value="1" name="'.$questionId.'-options" autocomplete="off"> |
|
1336
|
|
|
<span class="fa fa-font fa-fw" aria-hidden="true"></span> |
|
1337
|
|
|
</label> |
|
1338
|
|
|
</div> |
|
1339
|
|
|
</div> |
|
1340
|
|
|
<ul class="list-unstyled"></ul> |
|
1341
|
|
|
</div> |
|
1342
|
|
|
</div> |
|
1343
|
|
|
</div> |
|
1344
|
|
|
</div> |
|
1345
|
|
|
'; |
|
1346
|
|
|
} |
|
1347
|
|
|
|
|
1348
|
|
|
$objAnswerTmp = new Answer($questionId); |
|
1349
|
|
|
$nbrAnswers = $objAnswerTmp->selectNbrAnswers(); |
|
1350
|
|
|
|
|
1351
|
|
|
unset($objAnswerTmp, $objQuestionTmp); |
|
1352
|
|
|
|
|
1353
|
|
|
} |
|
1354
|
|
|
return $nbrAnswers; |
|
1355
|
|
|
} |
|
1356
|
|
|
|
|
1357
|
|
|
/** |
|
1358
|
|
|
* @param int $exe_id |
|
1359
|
|
|
* @return array |
|
1360
|
|
|
*/ |
|
1361
|
|
|
public static function get_exercise_track_exercise_info($exe_id) |
|
1362
|
|
|
{ |
|
1363
|
|
|
$TBL_EXERCICES = Database::get_course_table(TABLE_QUIZ_TEST); |
|
1364
|
|
|
$TBL_TRACK_EXERCICES = Database::get_main_table( |
|
1365
|
|
|
TABLE_STATISTIC_TRACK_E_EXERCISES |
|
1366
|
|
|
); |
|
1367
|
|
|
$TBL_COURSE = Database::get_main_table(TABLE_MAIN_COURSE); |
|
1368
|
|
|
$exe_id = intval($exe_id); |
|
1369
|
|
|
$result = array(); |
|
1370
|
|
|
if (!empty($exe_id)) { |
|
1371
|
|
|
$sql = " SELECT q.*, tee.* |
|
1372
|
|
|
FROM $TBL_EXERCICES as q |
|
1373
|
|
|
INNER JOIN $TBL_TRACK_EXERCICES as tee |
|
1374
|
|
|
ON q.id = tee.exe_exo_id |
|
1375
|
|
|
INNER JOIN $TBL_COURSE c |
|
1376
|
|
|
ON c.id = tee.c_id |
|
1377
|
|
|
WHERE tee.exe_id = $exe_id |
|
1378
|
|
|
AND q.c_id = c.id"; |
|
1379
|
|
|
|
|
1380
|
|
|
$res_fb_type = Database::query($sql); |
|
1381
|
|
|
$result = Database::fetch_array($res_fb_type, 'ASSOC'); |
|
1382
|
|
|
} |
|
1383
|
|
|
|
|
1384
|
|
|
return $result; |
|
1385
|
|
|
} |
|
1386
|
|
|
|
|
1387
|
|
|
/** |
|
1388
|
|
|
* Validates the time control key |
|
1389
|
|
|
* @param int $exercise_id |
|
1390
|
|
|
* @param int $lp_id |
|
1391
|
|
|
* @param int $lp_item_id |
|
1392
|
|
|
* @return bool |
|
1393
|
|
|
*/ |
|
1394
|
|
|
public static function exercise_time_control_is_valid( |
|
1395
|
|
|
$exercise_id, |
|
1396
|
|
|
$lp_id = 0, |
|
1397
|
|
|
$lp_item_id = 0 |
|
1398
|
|
|
) { |
|
1399
|
|
|
$course_id = api_get_course_int_id(); |
|
1400
|
|
|
$exercise_id = intval($exercise_id); |
|
1401
|
|
|
$TBL_EXERCICES = Database::get_course_table(TABLE_QUIZ_TEST); |
|
1402
|
|
|
$sql = "SELECT expired_time FROM $TBL_EXERCICES |
|
1403
|
|
|
WHERE c_id = $course_id AND id = $exercise_id"; |
|
1404
|
|
|
$result = Database::query($sql); |
|
1405
|
|
|
$row = Database::fetch_array($result, 'ASSOC'); |
|
1406
|
|
|
if (!empty($row['expired_time'])) { |
|
1407
|
|
|
$current_expired_time_key = self::get_time_control_key( |
|
1408
|
|
|
$exercise_id, |
|
1409
|
|
|
$lp_id, |
|
1410
|
|
|
$lp_item_id |
|
1411
|
|
|
); |
|
1412
|
|
|
if (isset($_SESSION['expired_time'][$current_expired_time_key])) { |
|
1413
|
|
|
$current_time = time(); |
|
1414
|
|
|
$expired_time = api_strtotime( |
|
1415
|
|
|
$_SESSION['expired_time'][$current_expired_time_key], |
|
1416
|
|
|
'UTC' |
|
1417
|
|
|
); |
|
1418
|
|
|
$total_time_allowed = $expired_time + 30; |
|
1419
|
|
|
if ($total_time_allowed < $current_time) { |
|
1420
|
|
|
return false; |
|
1421
|
|
|
} |
|
1422
|
|
|
return true; |
|
1423
|
|
|
} else { |
|
1424
|
|
|
return false; |
|
1425
|
|
|
} |
|
1426
|
|
|
} else { |
|
1427
|
|
|
return true; |
|
1428
|
|
|
} |
|
1429
|
|
|
} |
|
1430
|
|
|
|
|
1431
|
|
|
/** |
|
1432
|
|
|
* Deletes the time control token |
|
1433
|
|
|
* |
|
1434
|
|
|
* @param int $exercise_id |
|
1435
|
|
|
* @param int $lp_id |
|
1436
|
|
|
* @param int $lp_item_id |
|
1437
|
|
|
*/ |
|
1438
|
|
|
public static function exercise_time_control_delete( |
|
1439
|
|
|
$exercise_id, |
|
1440
|
|
|
$lp_id = 0, |
|
1441
|
|
|
$lp_item_id = 0 |
|
1442
|
|
|
) { |
|
1443
|
|
|
$current_expired_time_key = self::get_time_control_key( |
|
1444
|
|
|
$exercise_id, |
|
1445
|
|
|
$lp_id, |
|
1446
|
|
|
$lp_item_id |
|
1447
|
|
|
); |
|
1448
|
|
|
unset($_SESSION['expired_time'][$current_expired_time_key]); |
|
1449
|
|
|
} |
|
1450
|
|
|
|
|
1451
|
|
|
/** |
|
1452
|
|
|
* Generates the time control key |
|
1453
|
|
|
*/ |
|
1454
|
|
|
public static function get_time_control_key( |
|
1455
|
|
|
$exercise_id, |
|
1456
|
|
|
$lp_id = 0, |
|
1457
|
|
|
$lp_item_id = 0 |
|
1458
|
|
|
) { |
|
1459
|
|
|
$exercise_id = intval($exercise_id); |
|
1460
|
|
|
$lp_id = intval($lp_id); |
|
1461
|
|
|
$lp_item_id = intval($lp_item_id); |
|
1462
|
|
|
return |
|
1463
|
|
|
api_get_course_int_id().'_'. |
|
1464
|
|
|
api_get_session_id().'_'. |
|
1465
|
|
|
$exercise_id.'_'. |
|
1466
|
|
|
api_get_user_id().'_'. |
|
1467
|
|
|
$lp_id.'_'. |
|
1468
|
|
|
$lp_item_id; |
|
1469
|
|
|
} |
|
1470
|
|
|
|
|
1471
|
|
|
/** |
|
1472
|
|
|
* Get session time control |
|
1473
|
|
|
* |
|
1474
|
|
|
* @param int $exercise_id |
|
1475
|
|
|
* @param int $lp_id |
|
1476
|
|
|
* @param int $lp_item_id |
|
1477
|
|
|
* @return int |
|
1478
|
|
|
*/ |
|
1479
|
|
|
public static function get_session_time_control_key( |
|
1480
|
|
|
$exercise_id, |
|
1481
|
|
|
$lp_id = 0, |
|
1482
|
|
|
$lp_item_id = 0 |
|
1483
|
|
|
) { |
|
1484
|
|
|
$return_value = 0; |
|
1485
|
|
|
$time_control_key = self::get_time_control_key( |
|
1486
|
|
|
$exercise_id, |
|
1487
|
|
|
$lp_id, |
|
1488
|
|
|
$lp_item_id |
|
1489
|
|
|
); |
|
1490
|
|
|
if (isset($_SESSION['expired_time']) && isset($_SESSION['expired_time'][$time_control_key])) { |
|
1491
|
|
|
$return_value = $_SESSION['expired_time'][$time_control_key]; |
|
1492
|
|
|
} |
|
1493
|
|
|
return $return_value; |
|
1494
|
|
|
} |
|
1495
|
|
|
|
|
1496
|
|
|
/** |
|
1497
|
|
|
* Gets count of exam results |
|
1498
|
|
|
* @todo this function should be moved in a library + no global calls |
|
1499
|
|
|
*/ |
|
1500
|
|
|
public static function get_count_exam_results($exercise_id, $extra_where_conditions) |
|
1501
|
|
|
{ |
|
1502
|
|
|
$count = self::get_exam_results_data( |
|
1503
|
|
|
null, |
|
1504
|
|
|
null, |
|
1505
|
|
|
null, |
|
1506
|
|
|
null, |
|
1507
|
|
|
$exercise_id, |
|
1508
|
|
|
$extra_where_conditions, |
|
1509
|
|
|
true |
|
1510
|
|
|
); |
|
1511
|
|
|
return $count; |
|
1512
|
|
|
} |
|
1513
|
|
|
|
|
1514
|
|
|
/** |
|
1515
|
|
|
* @param string $in_hotpot_path |
|
1516
|
|
|
* @return int |
|
1517
|
|
|
*/ |
|
1518
|
|
|
public static function get_count_exam_hotpotatoes_results($in_hotpot_path) |
|
1519
|
|
|
{ |
|
1520
|
|
|
return self::get_exam_results_hotpotatoes_data( |
|
1521
|
|
|
0, |
|
1522
|
|
|
0, |
|
1523
|
|
|
'', |
|
1524
|
|
|
'', |
|
1525
|
|
|
$in_hotpot_path, |
|
1526
|
|
|
true, |
|
1527
|
|
|
'' |
|
1528
|
|
|
); |
|
1529
|
|
|
} |
|
1530
|
|
|
|
|
1531
|
|
|
/** |
|
1532
|
|
|
* @param int $in_from |
|
1533
|
|
|
* @param int $in_number_of_items |
|
1534
|
|
|
* @param int $in_column |
|
1535
|
|
|
* @param int $in_direction |
|
1536
|
|
|
* @param string $in_hotpot_path |
|
1537
|
|
|
* @param bool $in_get_count |
|
1538
|
|
|
* @param null $where_condition |
|
1539
|
|
|
* @return array|int |
|
1540
|
|
|
*/ |
|
1541
|
|
|
public static function get_exam_results_hotpotatoes_data( |
|
1542
|
|
|
$in_from, |
|
1543
|
|
|
$in_number_of_items, |
|
1544
|
|
|
$in_column, |
|
1545
|
|
|
$in_direction, |
|
1546
|
|
|
$in_hotpot_path, |
|
1547
|
|
|
$in_get_count = false, |
|
1548
|
|
|
$where_condition = null |
|
1549
|
|
|
) { |
|
1550
|
|
|
$courseId = api_get_course_int_id(); |
|
1551
|
|
|
// by default in_column = 1 If parameters given, it is the name of the column witch is the bdd field name |
|
1552
|
|
|
if ($in_column == 1) { |
|
1553
|
|
|
$in_column = 'firstname'; |
|
1554
|
|
|
} |
|
1555
|
|
|
$in_hotpot_path = Database::escape_string($in_hotpot_path); |
|
1556
|
|
|
$in_direction = Database::escape_string($in_direction); |
|
1557
|
|
|
$in_column = Database::escape_string($in_column); |
|
1558
|
|
|
$in_number_of_items = intval($in_number_of_items); |
|
1559
|
|
|
$in_from = intval($in_from); |
|
1560
|
|
|
|
|
1561
|
|
|
$TBL_TRACK_HOTPOTATOES = Database::get_main_table( |
|
1562
|
|
|
TABLE_STATISTIC_TRACK_E_HOTPOTATOES |
|
1563
|
|
|
); |
|
1564
|
|
|
$TBL_USER = Database::get_main_table(TABLE_MAIN_USER); |
|
1565
|
|
|
|
|
1566
|
|
|
$sql = "SELECT * FROM $TBL_TRACK_HOTPOTATOES thp |
|
1567
|
|
|
JOIN $TBL_USER u ON thp.exe_user_id = u.user_id |
|
1568
|
|
|
WHERE thp.c_id = $courseId AND exe_name LIKE '$in_hotpot_path%'"; |
|
1569
|
|
|
|
|
1570
|
|
|
// just count how many answers |
|
1571
|
|
|
if ($in_get_count) { |
|
1572
|
|
|
$res = Database::query($sql); |
|
1573
|
|
|
return Database::num_rows($res); |
|
1574
|
|
|
} |
|
1575
|
|
|
// get a number of sorted results |
|
1576
|
|
|
$sql .= " $where_condition |
|
1577
|
|
|
ORDER BY $in_column $in_direction |
|
1578
|
|
|
LIMIT $in_from, $in_number_of_items"; |
|
1579
|
|
|
|
|
1580
|
|
|
$res = Database::query($sql); |
|
1581
|
|
|
$result = array(); |
|
1582
|
|
|
$apiIsAllowedToEdit = api_is_allowed_to_edit(); |
|
1583
|
|
|
$urlBase = api_get_path(WEB_CODE_PATH). |
|
1584
|
|
|
'exercise/hotpotatoes_exercise_report.php?action=delete&'. |
|
1585
|
|
|
api_get_cidreq().'&id='; |
|
1586
|
|
|
while ($data = Database::fetch_array($res)) { |
|
1587
|
|
|
$actions = null; |
|
1588
|
|
|
|
|
1589
|
|
|
if ($apiIsAllowedToEdit) { |
|
1590
|
|
|
$url = $urlBase.$data['id'].'&path='.$data['exe_name']; |
|
1591
|
|
|
$actions = Display::url( |
|
1592
|
|
|
Display::return_icon('delete.png', get_lang('Delete')), |
|
1593
|
|
|
$url |
|
1594
|
|
|
); |
|
1595
|
|
|
} |
|
1596
|
|
|
|
|
1597
|
|
|
$result[] = array( |
|
1598
|
|
|
'firstname' => $data['firstname'], |
|
1599
|
|
|
'lastname' => $data['lastname'], |
|
1600
|
|
|
'username' => $data['username'], |
|
1601
|
|
|
'group_name' => implode( |
|
1602
|
|
|
"<br/>", |
|
1603
|
|
|
GroupManager::get_user_group_name($data['user_id']) |
|
1604
|
|
|
), |
|
1605
|
|
|
'exe_date' => $data['exe_date'], |
|
1606
|
|
|
'score' => $data['exe_result'].' / '.$data['exe_weighting'], |
|
1607
|
|
|
'actions' => $actions, |
|
1608
|
|
|
); |
|
1609
|
|
|
} |
|
1610
|
|
|
|
|
1611
|
|
|
return $result; |
|
1612
|
|
|
} |
|
1613
|
|
|
|
|
1614
|
|
|
/** |
|
1615
|
|
|
* @param string $exercisePath |
|
1616
|
|
|
* @param int $userId |
|
1617
|
|
|
* @param int $courseId |
|
1618
|
|
|
* @param int $sessionId |
|
1619
|
|
|
* |
|
1620
|
|
|
* @return array |
|
1621
|
|
|
*/ |
|
1622
|
|
View Code Duplication |
public static function getLatestHotPotatoResult( |
|
1623
|
|
|
$exercisePath, |
|
1624
|
|
|
$userId, |
|
1625
|
|
|
$courseId, |
|
1626
|
|
|
$sessionId |
|
1627
|
|
|
) { |
|
1628
|
|
|
$table = Database::get_main_table( |
|
1629
|
|
|
TABLE_STATISTIC_TRACK_E_HOTPOTATOES |
|
1630
|
|
|
); |
|
1631
|
|
|
$exercisePath = Database::escape_string($exercisePath); |
|
1632
|
|
|
$userId = intval($userId); |
|
1633
|
|
|
|
|
1634
|
|
|
$sql = "SELECT * FROM $table |
|
1635
|
|
|
WHERE |
|
1636
|
|
|
c_id = $courseId AND |
|
1637
|
|
|
exe_name LIKE '$exercisePath%' AND |
|
1638
|
|
|
exe_user_id = $userId |
|
1639
|
|
|
ORDER BY id |
|
1640
|
|
|
LIMIT 1"; |
|
1641
|
|
|
$result = Database::query($sql); |
|
1642
|
|
|
$attempt = array(); |
|
1643
|
|
|
if (Database::num_rows($result)) { |
|
1644
|
|
|
$attempt = Database::fetch_array($result, 'ASSOC'); |
|
1645
|
|
|
} |
|
1646
|
|
|
return $attempt; |
|
1647
|
|
|
} |
|
1648
|
|
|
|
|
1649
|
|
|
/** |
|
1650
|
|
|
* Gets the exam'data results |
|
1651
|
|
|
* @todo this function should be moved in a library + no global calls |
|
1652
|
|
|
* @param int $from |
|
1653
|
|
|
* @param int $number_of_items |
|
1654
|
|
|
* @param int $column |
|
1655
|
|
|
* @param string $direction |
|
1656
|
|
|
* @param int $exercise_id |
|
1657
|
|
|
* @param null $extra_where_conditions |
|
1658
|
|
|
* @param bool $get_count |
|
1659
|
|
|
* @param string $courseCode |
|
1660
|
|
|
* @return array |
|
1661
|
|
|
*/ |
|
1662
|
|
|
public static function get_exam_results_data( |
|
1663
|
|
|
$from, |
|
1664
|
|
|
$number_of_items, |
|
1665
|
|
|
$column, |
|
1666
|
|
|
$direction, |
|
1667
|
|
|
$exercise_id, |
|
1668
|
|
|
$extra_where_conditions = null, |
|
1669
|
|
|
$get_count = false, |
|
1670
|
|
|
$courseCode = null |
|
1671
|
|
|
) { |
|
1672
|
|
|
//@todo replace all this globals |
|
1673
|
|
|
global $documentPath, $filter; |
|
1674
|
|
|
|
|
1675
|
|
|
$courseCode = empty($courseCode) ? api_get_course_id() : $courseCode; |
|
1676
|
|
|
$courseInfo = api_get_course_info($courseCode); |
|
1677
|
|
|
$course_id = $courseInfo['real_id']; |
|
1678
|
|
|
$sessionId = api_get_session_id(); |
|
1679
|
|
|
$is_allowedToEdit = api_is_allowed_to_edit(null, true) || api_is_allowed_to_edit(true) || api_is_drh() || api_is_student_boss(); |
|
1680
|
|
|
|
|
1681
|
|
|
$TBL_USER = Database::get_main_table(TABLE_MAIN_USER); |
|
1682
|
|
|
$TBL_EXERCICES = Database::get_course_table(TABLE_QUIZ_TEST); |
|
1683
|
|
|
$TBL_GROUP_REL_USER = Database::get_course_table(TABLE_GROUP_USER); |
|
1684
|
|
|
$TBL_GROUP = Database::get_course_table(TABLE_GROUP); |
|
1685
|
|
|
$TBL_TRACK_EXERCICES = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
|
1686
|
|
|
$TBL_TRACK_HOTPOTATOES = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTPOTATOES); |
|
1687
|
|
|
$TBL_TRACK_ATTEMPT_RECORDING = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING); |
|
1688
|
|
|
|
|
1689
|
|
|
$session_id_and = ' AND te.session_id = '.$sessionId.' '; |
|
1690
|
|
|
$exercise_id = intval($exercise_id); |
|
1691
|
|
|
|
|
1692
|
|
|
$exercise_where = ''; |
|
1693
|
|
|
if (!empty($exercise_id)) { |
|
1694
|
|
|
$exercise_where .= ' AND te.exe_exo_id = '.$exercise_id.' '; |
|
1695
|
|
|
} |
|
1696
|
|
|
|
|
1697
|
|
|
$hotpotatoe_where = ''; |
|
1698
|
|
|
if (!empty($_GET['path'])) { |
|
1699
|
|
|
$hotpotatoe_path = Database::escape_string($_GET['path']); |
|
1700
|
|
|
$hotpotatoe_where .= ' AND exe_name = "'.$hotpotatoe_path.'" '; |
|
1701
|
|
|
} |
|
1702
|
|
|
|
|
1703
|
|
|
// sql for chamilo-type tests for teacher / tutor view |
|
1704
|
|
|
$sql_inner_join_tbl_track_exercices = " |
|
1705
|
|
|
( |
|
1706
|
|
|
SELECT DISTINCT ttte.*, if(tr.exe_id,1, 0) as revised |
|
1707
|
|
|
FROM $TBL_TRACK_EXERCICES ttte LEFT JOIN $TBL_TRACK_ATTEMPT_RECORDING tr |
|
1708
|
|
|
ON (ttte.exe_id = tr.exe_id) |
|
1709
|
|
|
WHERE |
|
1710
|
|
|
c_id = $course_id AND |
|
1711
|
|
|
exe_exo_id = $exercise_id AND |
|
1712
|
|
|
ttte.session_id = ".$sessionId." |
|
1713
|
|
|
)"; |
|
1714
|
|
|
|
|
1715
|
|
|
if ($is_allowedToEdit) { |
|
1716
|
|
|
//@todo fix to work with COURSE_RELATION_TYPE_RRHH in both queries |
|
1717
|
|
|
// Hack in order to filter groups |
|
1718
|
|
|
$sql_inner_join_tbl_user = ''; |
|
1719
|
|
|
if (strpos($extra_where_conditions, 'group_id')) { |
|
1720
|
|
|
$sql_inner_join_tbl_user = " |
|
1721
|
|
|
( |
|
1722
|
|
|
SELECT |
|
1723
|
|
|
u.user_id, |
|
1724
|
|
|
firstname, |
|
1725
|
|
|
lastname, |
|
1726
|
|
|
official_code, |
|
1727
|
|
|
email, |
|
1728
|
|
|
username, |
|
1729
|
|
|
g.name as group_name, |
|
1730
|
|
|
g.id as group_id |
|
1731
|
|
|
FROM $TBL_USER u |
|
1732
|
|
|
INNER JOIN $TBL_GROUP_REL_USER gru |
|
1733
|
|
|
ON (gru.user_id = u.user_id AND gru.c_id=".$course_id.") |
|
1734
|
|
|
INNER JOIN $TBL_GROUP g |
|
1735
|
|
|
ON (gru.group_id = g.id AND g.c_id=".$course_id.") |
|
1736
|
|
|
)"; |
|
1737
|
|
|
} |
|
1738
|
|
|
|
|
1739
|
|
|
if (strpos($extra_where_conditions, 'group_all')) { |
|
1740
|
|
|
$extra_where_conditions = str_replace( |
|
1741
|
|
|
"AND ( group_id = 'group_all' )", |
|
1742
|
|
|
'', |
|
1743
|
|
|
$extra_where_conditions |
|
1744
|
|
|
); |
|
1745
|
|
|
$extra_where_conditions = str_replace( |
|
1746
|
|
|
"AND group_id = 'group_all'", |
|
1747
|
|
|
'', |
|
1748
|
|
|
$extra_where_conditions |
|
1749
|
|
|
); |
|
1750
|
|
|
$extra_where_conditions = str_replace( |
|
1751
|
|
|
"group_id = 'group_all' AND", |
|
1752
|
|
|
'', |
|
1753
|
|
|
$extra_where_conditions |
|
1754
|
|
|
); |
|
1755
|
|
|
|
|
1756
|
|
|
$sql_inner_join_tbl_user = " |
|
1757
|
|
|
( |
|
1758
|
|
|
SELECT |
|
1759
|
|
|
u.user_id, |
|
1760
|
|
|
firstname, |
|
1761
|
|
|
lastname, |
|
1762
|
|
|
official_code, |
|
1763
|
|
|
email, |
|
1764
|
|
|
username, |
|
1765
|
|
|
'' as group_name, |
|
1766
|
|
|
'' as group_id |
|
1767
|
|
|
FROM $TBL_USER u |
|
1768
|
|
|
)"; |
|
1769
|
|
|
$sql_inner_join_tbl_user = null; |
|
1770
|
|
|
} |
|
1771
|
|
|
|
|
1772
|
|
|
if (strpos($extra_where_conditions, 'group_none')) { |
|
1773
|
|
|
$extra_where_conditions = str_replace( |
|
1774
|
|
|
"AND ( group_id = 'group_none' )", |
|
1775
|
|
|
"AND ( group_id is null )", |
|
1776
|
|
|
$extra_where_conditions |
|
1777
|
|
|
); |
|
1778
|
|
|
$extra_where_conditions = str_replace( |
|
1779
|
|
|
"AND group_id = 'group_none'", |
|
1780
|
|
|
"AND ( group_id is null )", |
|
1781
|
|
|
$extra_where_conditions |
|
1782
|
|
|
); |
|
1783
|
|
|
$sql_inner_join_tbl_user = " |
|
1784
|
|
|
( |
|
1785
|
|
|
SELECT |
|
1786
|
|
|
u.user_id, |
|
1787
|
|
|
firstname, |
|
1788
|
|
|
lastname, |
|
1789
|
|
|
official_code, |
|
1790
|
|
|
email, |
|
1791
|
|
|
username, |
|
1792
|
|
|
g.name as group_name, |
|
1793
|
|
|
g.id as group_id |
|
1794
|
|
|
FROM $TBL_USER u |
|
1795
|
|
|
LEFT OUTER JOIN $TBL_GROUP_REL_USER gru |
|
1796
|
|
|
ON ( gru.user_id = u.user_id AND gru.c_id=".$course_id." ) |
|
1797
|
|
|
LEFT OUTER JOIN $TBL_GROUP g |
|
1798
|
|
|
ON (gru.group_id = g.id AND g.c_id = ".$course_id.") |
|
1799
|
|
|
)"; |
|
1800
|
|
|
} |
|
1801
|
|
|
|
|
1802
|
|
|
// All |
|
1803
|
|
|
$is_empty_sql_inner_join_tbl_user = false; |
|
1804
|
|
|
if (empty($sql_inner_join_tbl_user)) { |
|
1805
|
|
|
$is_empty_sql_inner_join_tbl_user = true; |
|
1806
|
|
|
$sql_inner_join_tbl_user = " |
|
1807
|
|
|
( |
|
1808
|
|
|
SELECT u.user_id, firstname, lastname, email, username, ' ' as group_name, '' as group_id, official_code |
|
1809
|
|
|
FROM $TBL_USER u |
|
1810
|
|
|
WHERE u.status NOT IN(".api_get_users_status_ignored_in_reports('string').") |
|
1811
|
|
|
)"; |
|
1812
|
|
|
} |
|
1813
|
|
|
|
|
1814
|
|
|
$sqlFromOption = " , $TBL_GROUP_REL_USER AS gru "; |
|
1815
|
|
|
$sqlWhereOption = " AND gru.c_id = ".$course_id." AND gru.user_id = user.user_id "; |
|
1816
|
|
|
$first_and_last_name = api_is_western_name_order() ? "firstname, lastname" : "lastname, firstname"; |
|
1817
|
|
|
|
|
1818
|
|
|
if ($get_count) { |
|
1819
|
|
|
$sql_select = "SELECT count(te.exe_id) "; |
|
1820
|
|
|
} else { |
|
1821
|
|
|
$sql_select = "SELECT DISTINCT |
|
1822
|
|
|
user_id, |
|
1823
|
|
|
$first_and_last_name, |
|
1824
|
|
|
official_code, |
|
1825
|
|
|
ce.title, |
|
1826
|
|
|
username, |
|
1827
|
|
|
te.exe_result, |
|
1828
|
|
|
te.exe_weighting, |
|
1829
|
|
|
te.exe_date, |
|
1830
|
|
|
te.exe_id, |
|
1831
|
|
|
email as exemail, |
|
1832
|
|
|
te.start_date, |
|
1833
|
|
|
ce.expired_time, |
|
1834
|
|
|
steps_counter, |
|
1835
|
|
|
exe_user_id, |
|
1836
|
|
|
te.exe_duration, |
|
1837
|
|
|
te.status as completion_status, |
|
1838
|
|
|
propagate_neg, |
|
1839
|
|
|
revised, |
|
1840
|
|
|
group_name, |
|
1841
|
|
|
group_id, |
|
1842
|
|
|
orig_lp_id, |
|
1843
|
|
|
te.user_ip"; |
|
1844
|
|
|
} |
|
1845
|
|
|
|
|
1846
|
|
|
$sql = " $sql_select |
|
1847
|
|
|
FROM $TBL_EXERCICES AS ce |
|
1848
|
|
|
INNER JOIN $sql_inner_join_tbl_track_exercices AS te |
|
1849
|
|
|
ON (te.exe_exo_id = ce.id) |
|
1850
|
|
|
INNER JOIN $sql_inner_join_tbl_user AS user |
|
1851
|
|
|
ON (user.user_id = exe_user_id) |
|
1852
|
|
|
WHERE |
|
1853
|
|
|
te.c_id = ".$course_id." $session_id_and AND |
|
1854
|
|
|
ce.active <>-1 AND |
|
1855
|
|
|
ce.c_id = ".$course_id." |
|
1856
|
|
|
$exercise_where |
|
1857
|
|
|
$extra_where_conditions |
|
1858
|
|
|
"; |
|
1859
|
|
|
|
|
1860
|
|
|
// sql for hotpotatoes tests for teacher / tutor view |
|
1861
|
|
|
if ($get_count) { |
|
1862
|
|
|
$hpsql_select = "SELECT count(username)"; |
|
1863
|
|
|
} else { |
|
1864
|
|
|
$hpsql_select = "SELECT |
|
1865
|
|
|
$first_and_last_name , |
|
1866
|
|
|
username, |
|
1867
|
|
|
official_code, |
|
1868
|
|
|
tth.exe_name, |
|
1869
|
|
|
tth.exe_result , |
|
1870
|
|
|
tth.exe_weighting, |
|
1871
|
|
|
tth.exe_date"; |
|
1872
|
|
|
} |
|
1873
|
|
|
|
|
1874
|
|
|
$hpsql = " $hpsql_select |
|
1875
|
|
|
FROM |
|
1876
|
|
|
$TBL_TRACK_HOTPOTATOES tth, |
|
1877
|
|
|
$TBL_USER user |
|
1878
|
|
|
$sqlFromOption |
|
1879
|
|
|
WHERE |
|
1880
|
|
|
user.user_id=tth.exe_user_id |
|
1881
|
|
|
AND tth.c_id = ".$course_id." |
|
1882
|
|
|
$hotpotatoe_where |
|
1883
|
|
|
$sqlWhereOption |
|
1884
|
|
|
AND user.status NOT IN(".api_get_users_status_ignored_in_reports('string').") |
|
1885
|
|
|
ORDER BY |
|
1886
|
|
|
tth.c_id ASC, |
|
1887
|
|
|
tth.exe_date DESC"; |
|
1888
|
|
|
} |
|
1889
|
|
|
|
|
1890
|
|
|
if ($get_count) { |
|
1891
|
|
|
$resx = Database::query($sql); |
|
1892
|
|
|
$rowx = Database::fetch_row($resx, 'ASSOC'); |
|
1893
|
|
|
|
|
1894
|
|
|
return $rowx[0]; |
|
1895
|
|
|
} |
|
1896
|
|
|
|
|
1897
|
|
|
$teacher_list = CourseManager::get_teacher_list_from_course_code( |
|
1898
|
|
|
$courseCode |
|
1899
|
|
|
); |
|
1900
|
|
|
$teacher_id_list = array(); |
|
1901
|
|
|
if (!empty($teacher_list)) { |
|
1902
|
|
|
foreach ($teacher_list as $teacher) { |
|
1903
|
|
|
$teacher_id_list[] = $teacher['user_id']; |
|
1904
|
|
|
} |
|
1905
|
|
|
} |
|
1906
|
|
|
|
|
1907
|
|
|
$list_info = array(); |
|
1908
|
|
|
|
|
1909
|
|
|
// Simple exercises |
|
1910
|
|
|
if (empty($hotpotatoe_where)) { |
|
1911
|
|
|
$column = !empty($column) ? Database::escape_string($column) : null; |
|
1912
|
|
|
$from = intval($from); |
|
1913
|
|
|
$number_of_items = intval($number_of_items); |
|
1914
|
|
|
|
|
1915
|
|
|
if (!empty($column)) { |
|
1916
|
|
|
$sql .= " ORDER BY $column $direction "; |
|
1917
|
|
|
} |
|
1918
|
|
|
$sql .= " LIMIT $from, $number_of_items"; |
|
1919
|
|
|
|
|
1920
|
|
|
$results = array(); |
|
1921
|
|
|
$resx = Database::query($sql); |
|
1922
|
|
|
while ($rowx = Database::fetch_array($resx, 'ASSOC')) { |
|
1923
|
|
|
$results[] = $rowx; |
|
1924
|
|
|
} |
|
1925
|
|
|
|
|
1926
|
|
|
$group_list = GroupManager::get_group_list(null, $courseCode); |
|
1927
|
|
|
$clean_group_list = array(); |
|
1928
|
|
|
|
|
1929
|
|
|
if (!empty($group_list)) { |
|
1930
|
|
|
foreach ($group_list as $group) { |
|
1931
|
|
|
$clean_group_list[$group['id']] = $group['name']; |
|
1932
|
|
|
} |
|
1933
|
|
|
} |
|
1934
|
|
|
|
|
1935
|
|
|
$lp_list_obj = new LearnpathList(api_get_user_id()); |
|
1936
|
|
|
$lp_list = $lp_list_obj->get_flat_list(); |
|
1937
|
|
|
|
|
1938
|
|
|
$oldIds = array_column($lp_list, 'lp_old_id', 'iid'); |
|
1939
|
|
|
|
|
1940
|
|
|
if (is_array($results)) { |
|
1941
|
|
|
$users_array_id = array(); |
|
1942
|
|
|
$from_gradebook = false; |
|
1943
|
|
|
if (isset($_GET['gradebook']) && $_GET['gradebook'] == 'view') { |
|
1944
|
|
|
$from_gradebook = true; |
|
1945
|
|
|
} |
|
1946
|
|
|
$sizeof = count($results); |
|
1947
|
|
|
$user_list_id = array(); |
|
1948
|
|
|
$locked = api_resource_is_locked_by_gradebook( |
|
1949
|
|
|
$exercise_id, |
|
1950
|
|
|
LINK_EXERCISE |
|
1951
|
|
|
); |
|
1952
|
|
|
|
|
1953
|
|
|
$timeNow = strtotime(api_get_utc_datetime()); |
|
1954
|
|
|
// Looping results |
|
1955
|
|
|
for ($i = 0; $i < $sizeof; $i++) { |
|
1956
|
|
|
$revised = $results[$i]['revised']; |
|
1957
|
|
|
if ($results[$i]['completion_status'] == 'incomplete') { |
|
1958
|
|
|
// If the exercise was incomplete, we need to determine |
|
1959
|
|
|
// if it is still into the time allowed, or if its |
|
1960
|
|
|
// allowed time has expired and it can be closed |
|
1961
|
|
|
// (it's "unclosed") |
|
1962
|
|
|
$minutes = $results[$i]['expired_time']; |
|
1963
|
|
|
if ($minutes == 0) { |
|
1964
|
|
|
// There's no time limit, so obviously the attempt |
|
1965
|
|
|
// can still be "ongoing", but the teacher should |
|
1966
|
|
|
// be able to choose to close it, so mark it as |
|
1967
|
|
|
// "unclosed" instead of "ongoing" |
|
1968
|
|
|
$revised = 2; |
|
1969
|
|
|
} else { |
|
1970
|
|
|
$allowedSeconds = $minutes * 60; |
|
1971
|
|
|
$timeAttemptStarted = strtotime($results[$i]['start_date']); |
|
1972
|
|
|
$secondsSinceStart = $timeNow - $timeAttemptStarted; |
|
1973
|
|
|
if ($secondsSinceStart > $allowedSeconds) { |
|
1974
|
|
|
$revised = 2; // mark as "unclosed" |
|
1975
|
|
|
} else { |
|
1976
|
|
|
$revised = 3; // mark as "ongoing" |
|
1977
|
|
|
} |
|
1978
|
|
|
} |
|
1979
|
|
|
} |
|
1980
|
|
|
|
|
1981
|
|
|
if ($from_gradebook && ($is_allowedToEdit)) { |
|
1982
|
|
|
if (in_array( |
|
1983
|
|
|
$results[$i]['username'].$results[$i]['firstname'].$results[$i]['lastname'], |
|
1984
|
|
|
$users_array_id |
|
1985
|
|
|
)) { |
|
1986
|
|
|
continue; |
|
1987
|
|
|
} |
|
1988
|
|
|
$users_array_id[] = $results[$i]['username'].$results[$i]['firstname'].$results[$i]['lastname']; |
|
1989
|
|
|
} |
|
1990
|
|
|
|
|
1991
|
|
|
$lp_obj = isset($results[$i]['orig_lp_id']) && isset($lp_list[$results[$i]['orig_lp_id']]) ? $lp_list[$results[$i]['orig_lp_id']] : null; |
|
1992
|
|
|
if (empty($lp_obj)) { |
|
1993
|
|
|
// Try to get the old id (id instead of iid) |
|
1994
|
|
|
$lpNewId = isset($results[$i]['orig_lp_id']) && isset($oldIds[$results[$i]['orig_lp_id']]) ? $oldIds[$results[$i]['orig_lp_id']] : null; |
|
1995
|
|
|
if ($lpNewId) { |
|
1996
|
|
|
$lp_obj = isset($lp_list[$lpNewId]) ? $lp_list[$lpNewId] : null; |
|
1997
|
|
|
} |
|
1998
|
|
|
} |
|
1999
|
|
|
$lp_name = null; |
|
2000
|
|
|
if ($lp_obj) { |
|
2001
|
|
|
$url = api_get_path(WEB_CODE_PATH).'lp/lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.$results[$i]['orig_lp_id']; |
|
2002
|
|
|
$lp_name = Display::url( |
|
2003
|
|
|
$lp_obj['lp_name'], |
|
2004
|
|
|
$url, |
|
2005
|
|
|
array('target' => '_blank') |
|
2006
|
|
|
); |
|
2007
|
|
|
} |
|
2008
|
|
|
|
|
2009
|
|
|
// Add all groups by user |
|
2010
|
|
|
$group_name_list = null; |
|
2011
|
|
|
if ($is_empty_sql_inner_join_tbl_user) { |
|
2012
|
|
|
$group_list = GroupManager::get_group_ids( |
|
2013
|
|
|
api_get_course_int_id(), |
|
2014
|
|
|
$results[$i]['user_id'] |
|
2015
|
|
|
); |
|
2016
|
|
|
|
|
2017
|
|
|
foreach ($group_list as $id) { |
|
2018
|
|
|
$group_name_list .= $clean_group_list[$id].'<br/>'; |
|
2019
|
|
|
} |
|
2020
|
|
|
$results[$i]['group_name'] = $group_name_list; |
|
2021
|
|
|
} |
|
2022
|
|
|
|
|
2023
|
|
|
$results[$i]['exe_duration'] = !empty($results[$i]['exe_duration']) ? round($results[$i]['exe_duration'] / 60) : 0; |
|
2024
|
|
|
|
|
2025
|
|
|
$user_list_id[] = $results[$i]['exe_user_id']; |
|
2026
|
|
|
$id = $results[$i]['exe_id']; |
|
2027
|
|
|
$dt = api_convert_and_format_date($results[$i]['exe_weighting']); |
|
2028
|
|
|
|
|
2029
|
|
|
// we filter the results if we have the permission to |
|
2030
|
|
|
if (isset($results[$i]['results_disabled'])) { |
|
2031
|
|
|
$result_disabled = intval( |
|
2032
|
|
|
$results[$i]['results_disabled'] |
|
2033
|
|
|
); |
|
2034
|
|
|
} else { |
|
2035
|
|
|
$result_disabled = 0; |
|
2036
|
|
|
} |
|
2037
|
|
|
|
|
2038
|
|
|
if ($result_disabled == 0) { |
|
2039
|
|
|
$my_res = $results[$i]['exe_result']; |
|
2040
|
|
|
$my_total = $results[$i]['exe_weighting']; |
|
2041
|
|
|
|
|
2042
|
|
|
$results[$i]['start_date'] = api_get_local_time( |
|
2043
|
|
|
$results[$i]['start_date'] |
|
2044
|
|
|
); |
|
2045
|
|
|
$results[$i]['exe_date'] = api_get_local_time( |
|
2046
|
|
|
$results[$i]['exe_date'] |
|
2047
|
|
|
); |
|
2048
|
|
|
|
|
2049
|
|
|
if (!$results[$i]['propagate_neg'] && $my_res < 0) { |
|
2050
|
|
|
$my_res = 0; |
|
2051
|
|
|
} |
|
2052
|
|
|
|
|
2053
|
|
|
$score = self::show_score($my_res, $my_total); |
|
2054
|
|
|
|
|
2055
|
|
|
$actions = '<div class="pull-right">'; |
|
2056
|
|
|
if ($is_allowedToEdit) { |
|
2057
|
|
|
if (isset($teacher_id_list)) { |
|
2058
|
|
|
if (in_array( |
|
2059
|
|
|
$results[$i]['exe_user_id'], |
|
2060
|
|
|
$teacher_id_list |
|
2061
|
|
|
)) { |
|
2062
|
|
|
$actions .= Display::return_icon( |
|
2063
|
|
|
'teacher.png', |
|
2064
|
|
|
get_lang('Teacher') |
|
2065
|
|
|
); |
|
2066
|
|
|
} |
|
2067
|
|
|
} |
|
2068
|
|
|
$revisedLabel = ''; |
|
2069
|
|
|
switch ($revised) { |
|
2070
|
|
|
case 0: |
|
2071
|
|
|
$actions .= "<a href='exercise_show.php?".api_get_cidreq()."&action=qualify&id=$id'>". |
|
2072
|
|
|
Display:: return_icon( |
|
2073
|
|
|
'quiz.png', |
|
2074
|
|
|
get_lang('Qualify') |
|
2075
|
|
|
); |
|
2076
|
|
|
$actions .= '</a>'; |
|
2077
|
|
|
$revisedLabel = Display::label( |
|
2078
|
|
|
get_lang('NotValidated'), |
|
2079
|
|
|
'info' |
|
2080
|
|
|
); |
|
2081
|
|
|
break; |
|
2082
|
|
View Code Duplication |
case 1: |
|
2083
|
|
|
$actions .= "<a href='exercise_show.php?".api_get_cidreq()."&action=edit&id=$id'>". |
|
2084
|
|
|
Display:: return_icon( |
|
2085
|
|
|
'edit.png', |
|
2086
|
|
|
get_lang('Edit'), |
|
2087
|
|
|
array(), |
|
2088
|
|
|
ICON_SIZE_SMALL |
|
2089
|
|
|
); |
|
2090
|
|
|
$actions .= '</a>'; |
|
2091
|
|
|
$revisedLabel = Display::label( |
|
2092
|
|
|
get_lang('Validated'), |
|
2093
|
|
|
'success' |
|
2094
|
|
|
); |
|
2095
|
|
|
break; |
|
2096
|
|
|
case 2: //finished but not marked as such |
|
2097
|
|
|
$actions .= '<a href="exercise_report.php?' |
|
2098
|
|
|
. api_get_cidreq() |
|
2099
|
|
|
. '&exerciseId=' |
|
2100
|
|
|
. $exercise_id |
|
2101
|
|
|
. '&a=close&id=' |
|
2102
|
|
|
. $id |
|
2103
|
|
|
. '">'. |
|
2104
|
|
|
Display:: return_icon( |
|
2105
|
|
|
'lock.png', |
|
2106
|
|
|
get_lang('MarkAttemptAsClosed'), |
|
2107
|
|
|
array(), |
|
2108
|
|
|
ICON_SIZE_SMALL |
|
2109
|
|
|
); |
|
2110
|
|
|
$actions .= '</a>'; |
|
2111
|
|
|
$revisedLabel = Display::label( |
|
2112
|
|
|
get_lang('Unclosed'), |
|
2113
|
|
|
'warning' |
|
2114
|
|
|
); |
|
2115
|
|
|
break; |
|
2116
|
|
View Code Duplication |
case 3: //still ongoing |
|
2117
|
|
|
$actions .= "". |
|
2118
|
|
|
Display:: return_icon( |
|
2119
|
|
|
'clock.png', |
|
2120
|
|
|
get_lang('AttemptStillOngoingPleaseWait'), |
|
2121
|
|
|
array(), |
|
2122
|
|
|
ICON_SIZE_SMALL |
|
2123
|
|
|
); |
|
2124
|
|
|
$actions .= ''; |
|
2125
|
|
|
$revisedLabel = Display::label( |
|
2126
|
|
|
get_lang('Ongoing'), |
|
2127
|
|
|
'danger' |
|
2128
|
|
|
); |
|
2129
|
|
|
break; |
|
2130
|
|
|
} |
|
2131
|
|
|
|
|
2132
|
|
|
if ($filter == 2) { |
|
2133
|
|
|
$actions .= ' <a href="exercise_history.php?'.api_get_cidreq().'&exe_id='.$id.'">'. |
|
2134
|
|
|
Display:: return_icon( |
|
2135
|
|
|
'history.png', |
|
2136
|
|
|
get_lang('ViewHistoryChange') |
|
2137
|
|
|
).'</a>'; |
|
2138
|
|
|
} |
|
2139
|
|
|
|
|
2140
|
|
|
//Admin can always delete the attempt |
|
2141
|
|
|
if (($locked == false || api_is_platform_admin()) && !api_is_student_boss()) { |
|
2142
|
|
|
$ip = TrackingUserLog::get_ip_from_user_event( |
|
2143
|
|
|
$results[$i]['exe_user_id'], |
|
2144
|
|
|
api_get_utc_datetime(), |
|
2145
|
|
|
false |
|
2146
|
|
|
); |
|
2147
|
|
|
$actions .= '<a href="http://www.whatsmyip.org/ip-geo-location/?ip='.$ip.'" target="_blank">' |
|
2148
|
|
|
. Display::return_icon('info.png', $ip) |
|
2149
|
|
|
.'</a>'; |
|
2150
|
|
|
|
|
2151
|
|
|
|
|
2152
|
|
|
$recalculateUrl = api_get_path(WEB_CODE_PATH).'exercise/recalculate.php?'. |
|
2153
|
|
|
api_get_cidreq().'&'. |
|
2154
|
|
|
http_build_query([ |
|
2155
|
|
|
'id' => $id, |
|
2156
|
|
|
'exercise' => $exercise_id, |
|
2157
|
|
|
'user' => $results[$i]['exe_user_id'] |
|
2158
|
|
|
]); |
|
2159
|
|
|
$actions .= Display::url( |
|
2160
|
|
|
Display::return_icon('reload.png', get_lang('RecalculateResults')), |
|
2161
|
|
|
$recalculateUrl, |
|
2162
|
|
|
[ |
|
2163
|
|
|
'data-exercise' => $exercise_id, |
|
2164
|
|
|
'data-user' => $results[$i]['exe_user_id'], |
|
2165
|
|
|
'data-id' => $id, |
|
2166
|
|
|
'class' => 'exercise-recalculate' |
|
2167
|
|
|
] |
|
2168
|
|
|
); |
|
2169
|
|
|
|
|
2170
|
|
|
$delete_link = '<a href="exercise_report.php?'.api_get_cidreq().'&filter_by_user='.intval($_GET['filter_by_user']).'&filter='.$filter.'&exerciseId='.$exercise_id.'&delete=delete&did='.$id.'" |
|
2171
|
|
|
onclick="javascript:if(!confirm(\'' . sprintf( |
|
2172
|
|
|
get_lang('DeleteAttempt'), |
|
2173
|
|
|
$results[$i]['username'], |
|
2174
|
|
|
$dt |
|
2175
|
|
|
).'\')) return false;">'.Display:: return_icon( |
|
2176
|
|
|
'delete.png', |
|
2177
|
|
|
get_lang('Delete') |
|
2178
|
|
|
).'</a>'; |
|
2179
|
|
|
$delete_link = utf8_encode($delete_link); |
|
2180
|
|
|
|
|
2181
|
|
|
if (api_is_drh() && !api_is_platform_admin()) { |
|
2182
|
|
|
$delete_link = null; |
|
2183
|
|
|
} |
|
2184
|
|
|
if ($revised == 3) { |
|
2185
|
|
|
$delete_link = null; |
|
2186
|
|
|
} |
|
2187
|
|
|
$actions .= $delete_link; |
|
2188
|
|
|
} |
|
2189
|
|
|
|
|
2190
|
|
|
} else { |
|
2191
|
|
|
$attempt_url = api_get_path(WEB_CODE_PATH).'exercise/result.php?'.api_get_cidreq().'&id='.$results[$i]['exe_id'].'&id_session='.$sessionId; |
|
2192
|
|
|
$attempt_link = Display::url( |
|
2193
|
|
|
get_lang('Show'), |
|
2194
|
|
|
$attempt_url, |
|
2195
|
|
|
[ |
|
2196
|
|
|
'class' => 'ajax btn btn-default', |
|
2197
|
|
|
'data-title' => get_lang('Show') |
|
2198
|
|
|
] |
|
2199
|
|
|
); |
|
2200
|
|
|
$actions .= $attempt_link; |
|
2201
|
|
|
} |
|
2202
|
|
|
$actions .= '</div>'; |
|
2203
|
|
|
|
|
2204
|
|
|
$results[$i]['id'] = $results[$i]['exe_id']; |
|
2205
|
|
|
|
|
2206
|
|
|
if ($is_allowedToEdit) { |
|
2207
|
|
|
$results[$i]['status'] = $revisedLabel; |
|
2208
|
|
|
$results[$i]['score'] = $score; |
|
2209
|
|
|
$results[$i]['lp'] = $lp_name; |
|
2210
|
|
|
$results[$i]['actions'] = $actions; |
|
2211
|
|
|
$list_info[] = $results[$i]; |
|
2212
|
|
|
} else { |
|
2213
|
|
|
$results[$i]['status'] = $revisedLabel; |
|
2214
|
|
|
$results[$i]['score'] = $score; |
|
2215
|
|
|
$results[$i]['actions'] = $actions; |
|
2216
|
|
|
$list_info[] = $results[$i]; |
|
2217
|
|
|
} |
|
2218
|
|
|
} |
|
2219
|
|
|
} |
|
2220
|
|
|
} |
|
2221
|
|
|
} else { |
|
2222
|
|
|
$hpresults = StatsUtils::getManyResultsXCol($hpsql, 6); |
|
2223
|
|
|
// Print HotPotatoes test results. |
|
2224
|
|
|
if (is_array($hpresults)) { |
|
2225
|
|
|
for ($i = 0; $i < sizeof($hpresults); $i++) { |
|
2226
|
|
|
$hp_title = GetQuizName($hpresults[$i][3], $documentPath); |
|
2227
|
|
|
if ($hp_title == '') { |
|
2228
|
|
|
$hp_title = basename($hpresults[$i][3]); |
|
2229
|
|
|
} |
|
2230
|
|
|
|
|
2231
|
|
|
$hp_date = api_get_local_time( |
|
2232
|
|
|
$hpresults[$i][6], |
|
2233
|
|
|
null, |
|
2234
|
|
|
date_default_timezone_get() |
|
2235
|
|
|
); |
|
2236
|
|
|
$hp_result = round(($hpresults[$i][4] / ($hpresults[$i][5] != 0 ? $hpresults[$i][5] : 1)) * 100, 2) |
|
2237
|
|
|
.'% ('.$hpresults[$i][4].' / '.$hpresults[$i][5].')'; |
|
2238
|
|
|
if ($is_allowedToEdit) { |
|
2239
|
|
|
$list_info[] = array( |
|
2240
|
|
|
$hpresults[$i][0], |
|
2241
|
|
|
$hpresults[$i][1], |
|
2242
|
|
|
$hpresults[$i][2], |
|
2243
|
|
|
'', |
|
2244
|
|
|
$hp_title, |
|
2245
|
|
|
'-', |
|
2246
|
|
|
$hp_date, |
|
2247
|
|
|
$hp_result, |
|
2248
|
|
|
'-' |
|
2249
|
|
|
); |
|
2250
|
|
|
} else { |
|
2251
|
|
|
$list_info[] = array( |
|
2252
|
|
|
$hp_title, |
|
2253
|
|
|
'-', |
|
2254
|
|
|
$hp_date, |
|
2255
|
|
|
$hp_result, |
|
2256
|
|
|
'-' |
|
2257
|
|
|
); |
|
2258
|
|
|
} |
|
2259
|
|
|
} |
|
2260
|
|
|
} |
|
2261
|
|
|
} |
|
2262
|
|
|
|
|
2263
|
|
|
return $list_info; |
|
2264
|
|
|
} |
|
2265
|
|
|
|
|
2266
|
|
|
/** |
|
2267
|
|
|
* Converts the score with the exercise_max_note and exercise_min_score |
|
2268
|
|
|
* the platform settings + formats the results using the float_format function |
|
2269
|
|
|
* |
|
2270
|
|
|
* @param float $score |
|
2271
|
|
|
* @param float $weight |
|
2272
|
|
|
* @param bool $show_percentage show percentage or not |
|
2273
|
|
|
* @param bool $use_platform_settings use or not the platform settings |
|
2274
|
|
|
* @param bool $show_only_percentage |
|
2275
|
|
|
* @return string an html with the score modified |
|
2276
|
|
|
*/ |
|
2277
|
|
|
public static function show_score( |
|
2278
|
|
|
$score, |
|
2279
|
|
|
$weight, |
|
2280
|
|
|
$show_percentage = true, |
|
2281
|
|
|
$use_platform_settings = true, |
|
2282
|
|
|
$show_only_percentage = false |
|
2283
|
|
|
) { |
|
2284
|
|
|
if (is_null($score) && is_null($weight)) { |
|
2285
|
|
|
return '-'; |
|
2286
|
|
|
} |
|
2287
|
|
|
|
|
2288
|
|
|
$max_note = api_get_setting('exercise_max_score'); |
|
2289
|
|
|
$min_note = api_get_setting('exercise_min_score'); |
|
2290
|
|
|
|
|
2291
|
|
View Code Duplication |
if ($use_platform_settings) { |
|
2292
|
|
|
if ($max_note != '' && $min_note != '') { |
|
2293
|
|
|
if (!empty($weight) && intval($weight) != 0) { |
|
2294
|
|
|
$score = $min_note + ($max_note - $min_note) * $score / $weight; |
|
2295
|
|
|
} else { |
|
2296
|
|
|
$score = $min_note; |
|
2297
|
|
|
} |
|
2298
|
|
|
$weight = $max_note; |
|
2299
|
|
|
} |
|
2300
|
|
|
} |
|
2301
|
|
|
$percentage = (100 * $score) / ($weight != 0 ? $weight : 1); |
|
2302
|
|
|
|
|
2303
|
|
|
// Formats values |
|
2304
|
|
|
$percentage = float_format($percentage, 1); |
|
2305
|
|
|
$score = float_format($score, 1); |
|
2306
|
|
|
$weight = float_format($weight, 1); |
|
2307
|
|
|
|
|
2308
|
|
|
$html = null; |
|
2309
|
|
|
if ($show_percentage) { |
|
2310
|
|
|
$parent = '('.$score.' / '.$weight.')'; |
|
2311
|
|
|
$html = $percentage."% $parent"; |
|
2312
|
|
|
if ($show_only_percentage) { |
|
2313
|
|
|
$html = $percentage."% "; |
|
2314
|
|
|
} |
|
2315
|
|
|
} else { |
|
2316
|
|
|
$html = $score.' / '.$weight; |
|
2317
|
|
|
} |
|
2318
|
|
|
$html = Display::span($html, array('class' => 'score_exercise')); |
|
2319
|
|
|
|
|
2320
|
|
|
return $html; |
|
2321
|
|
|
} |
|
2322
|
|
|
|
|
2323
|
|
|
/** |
|
2324
|
|
|
* @param float $score |
|
2325
|
|
|
* @param float $weight |
|
2326
|
|
|
* @param string $pass_percentage |
|
2327
|
|
|
* @return bool |
|
2328
|
|
|
*/ |
|
2329
|
|
|
public static function isSuccessExerciseResult($score, $weight, $pass_percentage) |
|
2330
|
|
|
{ |
|
2331
|
|
|
$percentage = float_format( |
|
2332
|
|
|
($score / ($weight != 0 ? $weight : 1)) * 100, |
|
2333
|
|
|
1 |
|
2334
|
|
|
); |
|
2335
|
|
|
if (isset($pass_percentage) && !empty($pass_percentage)) { |
|
2336
|
|
|
if ($percentage >= $pass_percentage) { |
|
2337
|
|
|
return true; |
|
2338
|
|
|
} |
|
2339
|
|
|
} |
|
2340
|
|
|
return false; |
|
2341
|
|
|
} |
|
2342
|
|
|
|
|
2343
|
|
|
/** |
|
2344
|
|
|
* @param float $score |
|
2345
|
|
|
* @param float $weight |
|
2346
|
|
|
* @param string $pass_percentage |
|
2347
|
|
|
* @return string |
|
2348
|
|
|
*/ |
|
2349
|
|
|
public static function showSuccessMessage($score, $weight, $pass_percentage) |
|
2350
|
|
|
{ |
|
2351
|
|
|
$res = ''; |
|
2352
|
|
|
if (self::isPassPercentageEnabled($pass_percentage)) { |
|
2353
|
|
|
$isSuccess = self::isSuccessExerciseResult( |
|
2354
|
|
|
$score, |
|
2355
|
|
|
$weight, |
|
2356
|
|
|
$pass_percentage |
|
2357
|
|
|
); |
|
2358
|
|
|
|
|
2359
|
|
|
if ($isSuccess) { |
|
2360
|
|
|
$html = get_lang('CongratulationsYouPassedTheTest'); |
|
2361
|
|
|
$icon = Display::return_icon( |
|
2362
|
|
|
'completed.png', |
|
2363
|
|
|
get_lang('Correct'), |
|
2364
|
|
|
array(), |
|
2365
|
|
|
ICON_SIZE_MEDIUM |
|
2366
|
|
|
); |
|
2367
|
|
|
} else { |
|
2368
|
|
|
//$html .= Display::return_message(get_lang('YouDidNotReachTheMinimumScore'), 'warning'); |
|
2369
|
|
|
$html = get_lang('YouDidNotReachTheMinimumScore'); |
|
2370
|
|
|
$icon = Display::return_icon( |
|
2371
|
|
|
'warning.png', |
|
2372
|
|
|
get_lang('Wrong'), |
|
2373
|
|
|
array(), |
|
2374
|
|
|
ICON_SIZE_MEDIUM |
|
2375
|
|
|
); |
|
2376
|
|
|
} |
|
2377
|
|
|
$html = Display::tag('h4', $html); |
|
2378
|
|
|
$html .= Display::tag( |
|
2379
|
|
|
'h5', |
|
2380
|
|
|
$icon, |
|
2381
|
|
|
array('style' => 'width:40px; padding:2px 10px 0px 0px') |
|
2382
|
|
|
); |
|
2383
|
|
|
$res = $html; |
|
2384
|
|
|
} |
|
2385
|
|
|
return $res; |
|
2386
|
|
|
} |
|
2387
|
|
|
|
|
2388
|
|
|
/** |
|
2389
|
|
|
* Return true if pass_pourcentage activated (we use the pass pourcentage feature |
|
2390
|
|
|
* return false if pass_percentage = 0 (we don't use the pass pourcentage feature |
|
2391
|
|
|
* @param $value |
|
2392
|
|
|
* @return boolean |
|
2393
|
|
|
* In this version, pass_percentage and show_success_message are disabled if |
|
2394
|
|
|
* pass_percentage is set to 0 |
|
2395
|
|
|
*/ |
|
2396
|
|
|
public static function isPassPercentageEnabled($value) |
|
2397
|
|
|
{ |
|
2398
|
|
|
return $value > 0; |
|
2399
|
|
|
} |
|
2400
|
|
|
|
|
2401
|
|
|
/** |
|
2402
|
|
|
* Converts a numeric value in a percentage example 0.66666 to 66.67 % |
|
2403
|
|
|
* @param $value |
|
2404
|
|
|
* @return float Converted number |
|
2405
|
|
|
*/ |
|
2406
|
|
|
public static function convert_to_percentage($value) |
|
2407
|
|
|
{ |
|
2408
|
|
|
$return = '-'; |
|
2409
|
|
|
if ($value != '') { |
|
2410
|
|
|
$return = float_format($value * 100, 1).' %'; |
|
2411
|
|
|
} |
|
2412
|
|
|
return $return; |
|
2413
|
|
|
} |
|
2414
|
|
|
|
|
2415
|
|
|
/** |
|
2416
|
|
|
* Converts a score/weight values to the platform scale |
|
2417
|
|
|
* @param float $score |
|
2418
|
|
|
* @param float $weight |
|
2419
|
|
|
* @deprecated seem not to be used |
|
2420
|
|
|
* @return float the score rounded converted to the new range |
|
2421
|
|
|
*/ |
|
2422
|
|
|
public static function convert_score($score, $weight) |
|
2423
|
|
|
{ |
|
2424
|
|
|
$max_note = api_get_setting('exercise_max_score'); |
|
2425
|
|
|
$min_note = api_get_setting('exercise_min_score'); |
|
2426
|
|
|
|
|
2427
|
|
View Code Duplication |
if ($score != '' && $weight != '') { |
|
2428
|
|
|
if ($max_note != '' && $min_note != '') { |
|
2429
|
|
|
if (!empty($weight)) { |
|
2430
|
|
|
$score = $min_note + ($max_note - $min_note) * $score / $weight; |
|
2431
|
|
|
} else { |
|
2432
|
|
|
$score = $min_note; |
|
2433
|
|
|
} |
|
2434
|
|
|
} |
|
2435
|
|
|
} |
|
2436
|
|
|
$score_rounded = float_format($score, 1); |
|
2437
|
|
|
|
|
2438
|
|
|
return $score_rounded; |
|
2439
|
|
|
} |
|
2440
|
|
|
|
|
2441
|
|
|
/** |
|
2442
|
|
|
* Getting all active exercises from a course from a session |
|
2443
|
|
|
* (if a session_id is provided we will show all the exercises in the course + |
|
2444
|
|
|
* all exercises in the session) |
|
2445
|
|
|
* @param array $course_info |
|
2446
|
|
|
* @param int $session_id |
|
2447
|
|
|
* @param boolean $check_publication_dates |
|
2448
|
|
|
* @param string $search Search exercise name |
|
2449
|
|
|
* @param boolean $search_all_sessions Search exercises in all sessions |
|
2450
|
|
|
* @param int 0 = only inactive exercises |
|
2451
|
|
|
* 1 = only active exercises, |
|
2452
|
|
|
* 2 = all exercises |
|
2453
|
|
|
* 3 = active <> -1 |
|
2454
|
|
|
* @return array array with exercise data |
|
2455
|
|
|
*/ |
|
2456
|
|
|
public static function get_all_exercises( |
|
2457
|
|
|
$course_info = null, |
|
2458
|
|
|
$session_id = 0, |
|
2459
|
|
|
$check_publication_dates = false, |
|
2460
|
|
|
$search = '', |
|
2461
|
|
|
$search_all_sessions = false, |
|
2462
|
|
|
$active = 2 |
|
2463
|
|
|
) { |
|
2464
|
|
|
$course_id = api_get_course_int_id(); |
|
2465
|
|
|
|
|
2466
|
|
|
if (!empty($course_info) && !empty($course_info['real_id'])) { |
|
2467
|
|
|
$course_id = $course_info['real_id']; |
|
2468
|
|
|
} |
|
2469
|
|
|
|
|
2470
|
|
|
if ($session_id == -1) { |
|
2471
|
|
|
$session_id = 0; |
|
2472
|
|
|
} |
|
2473
|
|
|
|
|
2474
|
|
|
$now = api_get_utc_datetime(); |
|
2475
|
|
|
$time_conditions = ''; |
|
2476
|
|
|
|
|
2477
|
|
|
if ($check_publication_dates) { |
|
2478
|
|
|
//start and end are set |
|
2479
|
|
|
$time_conditions = " AND ((start_time <> '' AND start_time < '$now' AND end_time <> '' AND end_time > '$now' ) OR "; |
|
2480
|
|
|
// only start is set |
|
2481
|
|
|
$time_conditions .= " (start_time <> '' AND start_time < '$now' AND end_time is NULL) OR "; |
|
2482
|
|
|
// only end is set |
|
2483
|
|
|
$time_conditions .= " (start_time IS NULL AND end_time <> '' AND end_time > '$now') OR "; |
|
2484
|
|
|
// nothing is set |
|
2485
|
|
|
$time_conditions .= " (start_time IS NULL AND end_time IS NULL)) "; |
|
2486
|
|
|
} |
|
2487
|
|
|
|
|
2488
|
|
|
$needle_where = !empty($search) ? " AND title LIKE '?' " : ''; |
|
2489
|
|
|
$needle = !empty($search) ? "%".$search."%" : ''; |
|
2490
|
|
|
|
|
2491
|
|
|
// Show courses by active status |
|
2492
|
|
|
$active_sql = ''; |
|
2493
|
|
|
if ($active == 3) { |
|
2494
|
|
|
$active_sql = ' active <> -1 AND'; |
|
2495
|
|
|
} else { |
|
2496
|
|
|
if ($active != 2) { |
|
2497
|
|
|
$active_sql = sprintf(' active = %d AND', $active); |
|
2498
|
|
|
} |
|
2499
|
|
|
} |
|
2500
|
|
|
|
|
2501
|
|
|
if ($search_all_sessions == true) { |
|
2502
|
|
|
$conditions = array( |
|
2503
|
|
|
'where' => array( |
|
2504
|
|
|
$active_sql.' c_id = ? '.$needle_where.$time_conditions => array( |
|
2505
|
|
|
$course_id, |
|
2506
|
|
|
$needle |
|
2507
|
|
|
) |
|
2508
|
|
|
), |
|
2509
|
|
|
'order' => 'title' |
|
2510
|
|
|
); |
|
2511
|
|
|
} else { |
|
2512
|
|
|
if ($session_id == 0) { |
|
2513
|
|
|
$conditions = array( |
|
2514
|
|
|
'where' => array( |
|
2515
|
|
|
$active_sql.' session_id = ? AND c_id = ? '.$needle_where.$time_conditions => array( |
|
2516
|
|
|
$session_id, |
|
2517
|
|
|
$course_id, |
|
2518
|
|
|
$needle |
|
2519
|
|
|
) |
|
2520
|
|
|
), |
|
2521
|
|
|
'order' => 'title' |
|
2522
|
|
|
); |
|
2523
|
|
|
} else { |
|
2524
|
|
|
$conditions = array( |
|
2525
|
|
|
'where' => array( |
|
2526
|
|
|
$active_sql.' (session_id = 0 OR session_id = ? ) AND c_id = ? '.$needle_where.$time_conditions => array( |
|
2527
|
|
|
$session_id, |
|
2528
|
|
|
$course_id, |
|
2529
|
|
|
$needle |
|
2530
|
|
|
) |
|
2531
|
|
|
), |
|
2532
|
|
|
'order' => 'title' |
|
2533
|
|
|
); |
|
2534
|
|
|
} |
|
2535
|
|
|
} |
|
2536
|
|
|
|
|
2537
|
|
|
$table = Database::get_course_table(TABLE_QUIZ_TEST); |
|
2538
|
|
|
|
|
2539
|
|
|
return Database::select('*', $table, $conditions); |
|
2540
|
|
|
} |
|
2541
|
|
|
|
|
2542
|
|
|
/** |
|
2543
|
|
|
* Get exercise information by id |
|
2544
|
|
|
* @param int $exerciseId Exercise Id |
|
2545
|
|
|
* @param int $courseId The course ID (necessary as c_quiz.id is not unique) |
|
2546
|
|
|
* @return array Exercise info |
|
2547
|
|
|
*/ |
|
2548
|
|
|
public static function get_exercise_by_id($exerciseId = 0, $courseId = 0) |
|
2549
|
|
|
{ |
|
2550
|
|
|
$table = Database::get_course_table(TABLE_QUIZ_TEST); |
|
2551
|
|
|
if (empty($courseId)) { |
|
2552
|
|
|
$courseId = api_get_course_int_id(); |
|
2553
|
|
|
} else { |
|
2554
|
|
|
$courseId = intval($courseId); |
|
2555
|
|
|
} |
|
2556
|
|
|
$conditions = array( |
|
2557
|
|
|
'where' => array( |
|
2558
|
|
|
'id = ?' => array($exerciseId), |
|
2559
|
|
|
' AND c_id = ? ' => $courseId |
|
2560
|
|
|
) |
|
2561
|
|
|
); |
|
2562
|
|
|
|
|
2563
|
|
|
return Database::select('*', $table, $conditions); |
|
2564
|
|
|
} |
|
2565
|
|
|
|
|
2566
|
|
|
/** |
|
2567
|
|
|
* Getting all exercises (active only or all) |
|
2568
|
|
|
* from a course from a session |
|
2569
|
|
|
* (if a session_id is provided we will show all the exercises in the |
|
2570
|
|
|
* course + all exercises in the session) |
|
2571
|
|
|
* @param array course data |
|
2572
|
|
|
* @param int session id |
|
2573
|
|
|
* @param int course c_id |
|
2574
|
|
|
* @param boolean $only_active_exercises |
|
2575
|
|
|
* @return array array with exercise data |
|
2576
|
|
|
* modified by Hubert Borderiou |
|
2577
|
|
|
*/ |
|
2578
|
|
|
public static function get_all_exercises_for_course_id( |
|
2579
|
|
|
$course_info = null, |
|
2580
|
|
|
$session_id = 0, |
|
2581
|
|
|
$course_id = 0, |
|
2582
|
|
|
$only_active_exercises = true |
|
2583
|
|
|
) { |
|
2584
|
|
|
$TBL_EXERCISES = Database::get_course_table(TABLE_QUIZ_TEST); |
|
2585
|
|
|
|
|
2586
|
|
|
if ($only_active_exercises) { |
|
2587
|
|
|
// Only active exercises. |
|
2588
|
|
|
$sql_active_exercises = "active = 1 AND "; |
|
2589
|
|
|
} else { |
|
2590
|
|
|
// Not only active means visible and invisible NOT deleted (-2) |
|
2591
|
|
|
$sql_active_exercises = "active IN (1, 0) AND "; |
|
2592
|
|
|
} |
|
2593
|
|
|
|
|
2594
|
|
|
if ($session_id == -1) { |
|
2595
|
|
|
$session_id = 0; |
|
2596
|
|
|
} |
|
2597
|
|
|
|
|
2598
|
|
|
$params = array( |
|
2599
|
|
|
$session_id, |
|
2600
|
|
|
$course_id |
|
2601
|
|
|
); |
|
2602
|
|
|
|
|
2603
|
|
|
if ($session_id == 0) { |
|
2604
|
|
|
$conditions = array( |
|
2605
|
|
|
'where' => array("$sql_active_exercises session_id = ? AND c_id = ?" => $params), |
|
2606
|
|
|
'order' => 'title' |
|
2607
|
|
|
); |
|
2608
|
|
|
} else { |
|
2609
|
|
|
// All exercises |
|
2610
|
|
|
$conditions = array( |
|
2611
|
|
|
'where' => array("$sql_active_exercises (session_id = 0 OR session_id = ? ) AND c_id=?" => $params), |
|
2612
|
|
|
'order' => 'title' |
|
2613
|
|
|
); |
|
2614
|
|
|
} |
|
2615
|
|
|
|
|
2616
|
|
|
return Database::select('*', $TBL_EXERCISES, $conditions); |
|
2617
|
|
|
} |
|
2618
|
|
|
|
|
2619
|
|
|
/** |
|
2620
|
|
|
* Gets the position of the score based in a given score (result/weight) |
|
2621
|
|
|
* and the exe_id based in the user list |
|
2622
|
|
|
* (NO Exercises in LPs ) |
|
2623
|
|
|
* @param float $my_score user score to be compared *attention* |
|
2624
|
|
|
* $my_score = score/weight and not just the score |
|
2625
|
|
|
* @param int $my_exe_id exe id of the exercise |
|
2626
|
|
|
* (this is necessary because if 2 students have the same score the one |
|
2627
|
|
|
* with the minor exe_id will have a best position, just to be fair and FIFO) |
|
2628
|
|
|
* @param int $exercise_id |
|
2629
|
|
|
* @param string $course_code |
|
2630
|
|
|
* @param int $session_id |
|
2631
|
|
|
* @param array $user_list |
|
2632
|
|
|
* @param bool $return_string |
|
2633
|
|
|
* |
|
2634
|
|
|
* @return int the position of the user between his friends in a course |
|
2635
|
|
|
* (or course within a session) |
|
2636
|
|
|
*/ |
|
2637
|
|
|
public static function get_exercise_result_ranking( |
|
2638
|
|
|
$my_score, |
|
2639
|
|
|
$my_exe_id, |
|
2640
|
|
|
$exercise_id, |
|
2641
|
|
|
$course_code, |
|
2642
|
|
|
$session_id = 0, |
|
2643
|
|
|
$user_list = array(), |
|
2644
|
|
|
$return_string = true |
|
2645
|
|
|
) { |
|
2646
|
|
|
//No score given we return |
|
2647
|
|
|
if (is_null($my_score)) { |
|
2648
|
|
|
return '-'; |
|
2649
|
|
|
} |
|
2650
|
|
|
if (empty($user_list)) { |
|
2651
|
|
|
return '-'; |
|
2652
|
|
|
} |
|
2653
|
|
|
|
|
2654
|
|
|
$best_attempts = array(); |
|
2655
|
|
|
foreach ($user_list as $user_data) { |
|
2656
|
|
|
$user_id = $user_data['user_id']; |
|
2657
|
|
|
$best_attempts[$user_id] = self::get_best_attempt_by_user( |
|
2658
|
|
|
$user_id, |
|
2659
|
|
|
$exercise_id, |
|
2660
|
|
|
$course_code, |
|
2661
|
|
|
$session_id |
|
2662
|
|
|
); |
|
2663
|
|
|
} |
|
2664
|
|
|
|
|
2665
|
|
|
if (empty($best_attempts)) { |
|
2666
|
|
|
return 1; |
|
2667
|
|
|
} else { |
|
2668
|
|
|
$position = 1; |
|
2669
|
|
|
$my_ranking = array(); |
|
2670
|
|
View Code Duplication |
foreach ($best_attempts as $user_id => $result) { |
|
2671
|
|
|
if (!empty($result['exe_weighting']) && intval( |
|
2672
|
|
|
$result['exe_weighting'] |
|
2673
|
|
|
) != 0 |
|
2674
|
|
|
) { |
|
2675
|
|
|
$my_ranking[$user_id] = $result['exe_result'] / $result['exe_weighting']; |
|
2676
|
|
|
} else { |
|
2677
|
|
|
$my_ranking[$user_id] = 0; |
|
2678
|
|
|
} |
|
2679
|
|
|
} |
|
2680
|
|
|
//if (!empty($my_ranking)) { |
|
2681
|
|
|
asort($my_ranking); |
|
2682
|
|
|
$position = count($my_ranking); |
|
2683
|
|
|
if (!empty($my_ranking)) { |
|
2684
|
|
|
foreach ($my_ranking as $user_id => $ranking) { |
|
2685
|
|
|
if ($my_score >= $ranking) { |
|
2686
|
|
|
if ($my_score == $ranking && isset($best_attempts[$user_id]['exe_id'])) { |
|
2687
|
|
|
$exe_id = $best_attempts[$user_id]['exe_id']; |
|
2688
|
|
|
if ($my_exe_id < $exe_id) { |
|
2689
|
|
|
$position--; |
|
2690
|
|
|
} |
|
2691
|
|
|
} else { |
|
2692
|
|
|
$position--; |
|
2693
|
|
|
} |
|
2694
|
|
|
} |
|
2695
|
|
|
} |
|
2696
|
|
|
} |
|
2697
|
|
|
//} |
|
2698
|
|
|
$return_value = array( |
|
2699
|
|
|
'position' => $position, |
|
2700
|
|
|
'count' => count($my_ranking) |
|
2701
|
|
|
); |
|
2702
|
|
|
|
|
2703
|
|
|
if ($return_string) { |
|
2704
|
|
|
if (!empty($position) && !empty($my_ranking)) { |
|
2705
|
|
|
$return_value = $position.'/'.count($my_ranking); |
|
2706
|
|
|
} else { |
|
2707
|
|
|
$return_value = '-'; |
|
2708
|
|
|
} |
|
2709
|
|
|
} |
|
2710
|
|
|
return $return_value; |
|
2711
|
|
|
} |
|
2712
|
|
|
} |
|
2713
|
|
|
|
|
2714
|
|
|
/** |
|
2715
|
|
|
* Gets the position of the score based in a given score (result/weight) and the exe_id based in all attempts |
|
2716
|
|
|
* (NO Exercises in LPs ) old functionality by attempt |
|
2717
|
|
|
* @param float user score to be compared attention => score/weight |
|
2718
|
|
|
* @param int exe id of the exercise |
|
2719
|
|
|
* (this is necessary because if 2 students have the same score the one |
|
2720
|
|
|
* with the minor exe_id will have a best position, just to be fair and FIFO) |
|
2721
|
|
|
* @param int exercise id |
|
2722
|
|
|
* @param string course code |
|
2723
|
|
|
* @param int session id |
|
2724
|
|
|
* @param bool $return_string |
|
2725
|
|
|
* @return int the position of the user between his friends in a course (or course within a session) |
|
2726
|
|
|
*/ |
|
2727
|
|
|
public static function get_exercise_result_ranking_by_attempt( |
|
2728
|
|
|
$my_score, |
|
2729
|
|
|
$my_exe_id, |
|
2730
|
|
|
$exercise_id, |
|
2731
|
|
|
$courseId, |
|
2732
|
|
|
$session_id = 0, |
|
2733
|
|
|
$return_string = true |
|
2734
|
|
|
) { |
|
2735
|
|
|
if (empty($session_id)) { |
|
2736
|
|
|
$session_id = 0; |
|
2737
|
|
|
} |
|
2738
|
|
|
if (is_null($my_score)) { |
|
2739
|
|
|
return '-'; |
|
2740
|
|
|
} |
|
2741
|
|
|
$user_results = Event::get_all_exercise_results( |
|
2742
|
|
|
$exercise_id, |
|
2743
|
|
|
$courseId, |
|
2744
|
|
|
$session_id, |
|
2745
|
|
|
false |
|
2746
|
|
|
); |
|
2747
|
|
|
$position_data = array(); |
|
2748
|
|
|
if (empty($user_results)) { |
|
2749
|
|
|
return 1; |
|
2750
|
|
|
} else { |
|
2751
|
|
|
$position = 1; |
|
2752
|
|
|
$my_ranking = array(); |
|
2753
|
|
View Code Duplication |
foreach ($user_results as $result) { |
|
2754
|
|
|
//print_r($result); |
|
2755
|
|
|
if (!empty($result['exe_weighting']) && intval( |
|
2756
|
|
|
$result['exe_weighting'] |
|
2757
|
|
|
) != 0 |
|
2758
|
|
|
) { |
|
2759
|
|
|
$my_ranking[$result['exe_id']] = $result['exe_result'] / $result['exe_weighting']; |
|
2760
|
|
|
} else { |
|
2761
|
|
|
$my_ranking[$result['exe_id']] = 0; |
|
2762
|
|
|
} |
|
2763
|
|
|
} |
|
2764
|
|
|
asort($my_ranking); |
|
2765
|
|
|
$position = count($my_ranking); |
|
2766
|
|
|
if (!empty($my_ranking)) { |
|
2767
|
|
|
foreach ($my_ranking as $exe_id => $ranking) { |
|
2768
|
|
|
if ($my_score >= $ranking) { |
|
2769
|
|
|
if ($my_score == $ranking) { |
|
2770
|
|
|
if ($my_exe_id < $exe_id) { |
|
2771
|
|
|
$position--; |
|
2772
|
|
|
} |
|
2773
|
|
|
} else { |
|
2774
|
|
|
$position--; |
|
2775
|
|
|
} |
|
2776
|
|
|
} |
|
2777
|
|
|
} |
|
2778
|
|
|
} |
|
2779
|
|
|
$return_value = array( |
|
2780
|
|
|
'position' => $position, |
|
2781
|
|
|
'count' => count($my_ranking) |
|
2782
|
|
|
); |
|
2783
|
|
|
|
|
2784
|
|
|
if ($return_string) { |
|
2785
|
|
|
if (!empty($position) && !empty($my_ranking)) { |
|
2786
|
|
|
return $position.'/'.count($my_ranking); |
|
2787
|
|
|
} |
|
2788
|
|
|
} |
|
2789
|
|
|
return $return_value; |
|
2790
|
|
|
} |
|
2791
|
|
|
} |
|
2792
|
|
|
|
|
2793
|
|
|
/** |
|
2794
|
|
|
* Get the best attempt in a exercise (NO Exercises in LPs ) |
|
2795
|
|
|
* @param int $exercise_id |
|
2796
|
|
|
* @param int $courseId |
|
2797
|
|
|
* @param int $session_id |
|
2798
|
|
|
* |
|
2799
|
|
|
* @return array |
|
2800
|
|
|
*/ |
|
2801
|
|
View Code Duplication |
public static function get_best_attempt_in_course($exercise_id, $courseId, $session_id) |
|
2802
|
|
|
{ |
|
2803
|
|
|
$user_results = Event::get_all_exercise_results( |
|
2804
|
|
|
$exercise_id, |
|
2805
|
|
|
$courseId, |
|
2806
|
|
|
$session_id, |
|
2807
|
|
|
false |
|
2808
|
|
|
); |
|
2809
|
|
|
|
|
2810
|
|
|
$best_score_data = array(); |
|
2811
|
|
|
$best_score = 0; |
|
2812
|
|
|
if (!empty($user_results)) { |
|
2813
|
|
|
foreach ($user_results as $result) { |
|
2814
|
|
|
if (!empty($result['exe_weighting']) && |
|
2815
|
|
|
intval($result['exe_weighting']) != 0 |
|
2816
|
|
|
) { |
|
2817
|
|
|
$score = $result['exe_result'] / $result['exe_weighting']; |
|
2818
|
|
|
if ($score >= $best_score) { |
|
2819
|
|
|
$best_score = $score; |
|
2820
|
|
|
$best_score_data = $result; |
|
2821
|
|
|
} |
|
2822
|
|
|
} |
|
2823
|
|
|
} |
|
2824
|
|
|
} |
|
2825
|
|
|
|
|
2826
|
|
|
return $best_score_data; |
|
2827
|
|
|
} |
|
2828
|
|
|
|
|
2829
|
|
|
/** |
|
2830
|
|
|
* Get the best score in a exercise (NO Exercises in LPs ) |
|
2831
|
|
|
* @param int $user_id |
|
2832
|
|
|
* @param int $exercise_id |
|
2833
|
|
|
* @param int $courseId |
|
2834
|
|
|
* @param int $session_id |
|
2835
|
|
|
* |
|
2836
|
|
|
* @return array |
|
2837
|
|
|
*/ |
|
2838
|
|
View Code Duplication |
public static function get_best_attempt_by_user( |
|
2839
|
|
|
$user_id, |
|
2840
|
|
|
$exercise_id, |
|
2841
|
|
|
$courseId, |
|
2842
|
|
|
$session_id |
|
2843
|
|
|
) |
|
2844
|
|
|
{ |
|
2845
|
|
|
$user_results = Event::get_all_exercise_results( |
|
2846
|
|
|
$exercise_id, |
|
2847
|
|
|
$courseId, |
|
2848
|
|
|
$session_id, |
|
2849
|
|
|
false, |
|
2850
|
|
|
$user_id |
|
2851
|
|
|
); |
|
2852
|
|
|
$best_score_data = array(); |
|
2853
|
|
|
$best_score = 0; |
|
2854
|
|
|
if (!empty($user_results)) { |
|
2855
|
|
|
foreach ($user_results as $result) { |
|
2856
|
|
|
if (!empty($result['exe_weighting']) && intval($result['exe_weighting']) != 0) { |
|
2857
|
|
|
$score = $result['exe_result'] / $result['exe_weighting']; |
|
2858
|
|
|
if ($score >= $best_score) { |
|
2859
|
|
|
$best_score = $score; |
|
2860
|
|
|
$best_score_data = $result; |
|
2861
|
|
|
} |
|
2862
|
|
|
} |
|
2863
|
|
|
} |
|
2864
|
|
|
} |
|
2865
|
|
|
|
|
2866
|
|
|
return $best_score_data; |
|
2867
|
|
|
} |
|
2868
|
|
|
|
|
2869
|
|
|
/** |
|
2870
|
|
|
* Get average score (NO Exercises in LPs ) |
|
2871
|
|
|
* @param int exercise id |
|
2872
|
|
|
* @param int $courseId |
|
2873
|
|
|
* @param int session id |
|
2874
|
|
|
* @return float Average score |
|
2875
|
|
|
*/ |
|
2876
|
|
View Code Duplication |
public static function get_average_score($exercise_id, $courseId, $session_id) |
|
2877
|
|
|
{ |
|
2878
|
|
|
$user_results = Event::get_all_exercise_results( |
|
2879
|
|
|
$exercise_id, |
|
2880
|
|
|
$courseId, |
|
2881
|
|
|
$session_id |
|
2882
|
|
|
); |
|
2883
|
|
|
$avg_score = 0; |
|
2884
|
|
|
if (!empty($user_results)) { |
|
2885
|
|
|
foreach ($user_results as $result) { |
|
2886
|
|
|
if (!empty($result['exe_weighting']) && intval( |
|
2887
|
|
|
$result['exe_weighting'] |
|
2888
|
|
|
) != 0 |
|
2889
|
|
|
) { |
|
2890
|
|
|
$score = $result['exe_result'] / $result['exe_weighting']; |
|
2891
|
|
|
$avg_score += $score; |
|
2892
|
|
|
} |
|
2893
|
|
|
} |
|
2894
|
|
|
$avg_score = float_format($avg_score / count($user_results), 1); |
|
2895
|
|
|
} |
|
2896
|
|
|
|
|
2897
|
|
|
return $avg_score; |
|
2898
|
|
|
} |
|
2899
|
|
|
|
|
2900
|
|
|
/** |
|
2901
|
|
|
* Get average score by score (NO Exercises in LPs ) |
|
2902
|
|
|
* @param int exercise id |
|
2903
|
|
|
* @param int $courseId |
|
2904
|
|
|
* @param int session id |
|
2905
|
|
|
* @return float Average score |
|
2906
|
|
|
*/ |
|
2907
|
|
View Code Duplication |
public static function get_average_score_by_course($courseId, $session_id) |
|
2908
|
|
|
{ |
|
2909
|
|
|
$user_results = Event::get_all_exercise_results_by_course( |
|
2910
|
|
|
$courseId, |
|
2911
|
|
|
$session_id, |
|
2912
|
|
|
false |
|
2913
|
|
|
); |
|
2914
|
|
|
//echo $course_code.' - '.$session_id.'<br />'; |
|
2915
|
|
|
$avg_score = 0; |
|
2916
|
|
|
if (!empty($user_results)) { |
|
2917
|
|
|
foreach ($user_results as $result) { |
|
2918
|
|
|
if (!empty($result['exe_weighting']) && intval( |
|
2919
|
|
|
$result['exe_weighting'] |
|
2920
|
|
|
) != 0 |
|
2921
|
|
|
) { |
|
2922
|
|
|
$score = $result['exe_result'] / $result['exe_weighting']; |
|
2923
|
|
|
$avg_score += $score; |
|
2924
|
|
|
} |
|
2925
|
|
|
} |
|
2926
|
|
|
//We asume that all exe_weighting |
|
2927
|
|
|
$avg_score = ($avg_score / count($user_results)); |
|
2928
|
|
|
} |
|
2929
|
|
|
|
|
2930
|
|
|
return $avg_score; |
|
2931
|
|
|
} |
|
2932
|
|
|
|
|
2933
|
|
|
/** |
|
2934
|
|
|
* @param int $user_id |
|
2935
|
|
|
* @param int $courseId |
|
2936
|
|
|
* @param int $session_id |
|
2937
|
|
|
* |
|
2938
|
|
|
* @return float|int |
|
2939
|
|
|
*/ |
|
2940
|
|
View Code Duplication |
public static function get_average_score_by_course_by_user( |
|
2941
|
|
|
$user_id, |
|
2942
|
|
|
$courseId, |
|
2943
|
|
|
$session_id |
|
2944
|
|
|
) |
|
2945
|
|
|
{ |
|
2946
|
|
|
$user_results = Event::get_all_exercise_results_by_user( |
|
2947
|
|
|
$user_id, |
|
2948
|
|
|
$courseId, |
|
2949
|
|
|
$session_id |
|
2950
|
|
|
); |
|
2951
|
|
|
$avg_score = 0; |
|
2952
|
|
|
if (!empty($user_results)) { |
|
2953
|
|
|
foreach ($user_results as $result) { |
|
2954
|
|
|
if (!empty($result['exe_weighting']) && intval( |
|
2955
|
|
|
$result['exe_weighting'] |
|
2956
|
|
|
) != 0 |
|
2957
|
|
|
) { |
|
2958
|
|
|
$score = $result['exe_result'] / $result['exe_weighting']; |
|
2959
|
|
|
$avg_score += $score; |
|
2960
|
|
|
} |
|
2961
|
|
|
} |
|
2962
|
|
|
// We asumme that all exe_weighting |
|
2963
|
|
|
$avg_score = ($avg_score / count($user_results)); |
|
2964
|
|
|
} |
|
2965
|
|
|
|
|
2966
|
|
|
return $avg_score; |
|
2967
|
|
|
} |
|
2968
|
|
|
|
|
2969
|
|
|
/** |
|
2970
|
|
|
* Get average score by score (NO Exercises in LPs ) |
|
2971
|
|
|
* @param int exercise id |
|
2972
|
|
|
* @param int $courseId |
|
2973
|
|
|
* @param int session id |
|
2974
|
|
|
* @return float Best average score |
|
2975
|
|
|
*/ |
|
2976
|
|
View Code Duplication |
public static function get_best_average_score_by_exercise( |
|
2977
|
|
|
$exercise_id, |
|
2978
|
|
|
$courseId, |
|
2979
|
|
|
$session_id, |
|
2980
|
|
|
$user_count |
|
2981
|
|
|
) |
|
2982
|
|
|
{ |
|
2983
|
|
|
$user_results = Event::get_best_exercise_results_by_user( |
|
2984
|
|
|
$exercise_id, |
|
2985
|
|
|
$courseId, |
|
2986
|
|
|
$session_id |
|
2987
|
|
|
); |
|
2988
|
|
|
$avg_score = 0; |
|
2989
|
|
|
if (!empty($user_results)) { |
|
2990
|
|
|
foreach ($user_results as $result) { |
|
2991
|
|
|
if (!empty($result['exe_weighting']) && intval($result['exe_weighting']) != 0) { |
|
2992
|
|
|
$score = $result['exe_result'] / $result['exe_weighting']; |
|
2993
|
|
|
$avg_score += $score; |
|
2994
|
|
|
} |
|
2995
|
|
|
} |
|
2996
|
|
|
//We asumme that all exe_weighting |
|
2997
|
|
|
//$avg_score = show_score( $avg_score / count($user_results) , $result['exe_weighting']); |
|
2998
|
|
|
//$avg_score = ($avg_score / count($user_results)); |
|
2999
|
|
|
if (!empty($user_count)) { |
|
3000
|
|
|
$avg_score = float_format($avg_score / $user_count, 1) * 100; |
|
3001
|
|
|
} else { |
|
3002
|
|
|
$avg_score = 0; |
|
3003
|
|
|
} |
|
3004
|
|
|
} |
|
3005
|
|
|
|
|
3006
|
|
|
return $avg_score; |
|
3007
|
|
|
} |
|
3008
|
|
|
|
|
3009
|
|
|
/** |
|
3010
|
|
|
* @param string $course_code |
|
3011
|
|
|
* @param int $session_id |
|
3012
|
|
|
* |
|
3013
|
|
|
* @return array |
|
3014
|
|
|
*/ |
|
3015
|
|
|
public static function get_exercises_to_be_taken($course_code, $session_id) |
|
3016
|
|
|
{ |
|
3017
|
|
|
$course_info = api_get_course_info($course_code); |
|
3018
|
|
|
$exercises = self::get_all_exercises($course_info, $session_id); |
|
3019
|
|
|
$result = array(); |
|
3020
|
|
|
$now = time() + 15 * 24 * 60 * 60; |
|
3021
|
|
|
foreach ($exercises as $exercise_item) { |
|
3022
|
|
|
if (isset($exercise_item['end_time']) && |
|
3023
|
|
|
!empty($exercise_item['end_time']) && |
|
3024
|
|
|
api_strtotime($exercise_item['end_time'], 'UTC') < $now |
|
3025
|
|
|
) { |
|
3026
|
|
|
$result[] = $exercise_item; |
|
3027
|
|
|
} |
|
3028
|
|
|
} |
|
3029
|
|
|
return $result; |
|
3030
|
|
|
} |
|
3031
|
|
|
|
|
3032
|
|
|
/** |
|
3033
|
|
|
* Get student results (only in completed exercises) stats by question |
|
3034
|
|
|
* @param int $question_id |
|
3035
|
|
|
* @param int $exercise_id |
|
3036
|
|
|
* @param string $course_code |
|
3037
|
|
|
* @param int $session_id |
|
3038
|
|
|
* |
|
3039
|
|
|
**/ |
|
3040
|
|
|
public static function get_student_stats_by_question( |
|
3041
|
|
|
$question_id, |
|
3042
|
|
|
$exercise_id, |
|
3043
|
|
|
$course_code, |
|
3044
|
|
|
$session_id |
|
3045
|
|
|
) { |
|
3046
|
|
|
$track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
|
3047
|
|
|
$track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
|
3048
|
|
|
|
|
3049
|
|
|
$question_id = intval($question_id); |
|
3050
|
|
|
$exercise_id = intval($exercise_id); |
|
3051
|
|
|
$course_code = Database::escape_string($course_code); |
|
3052
|
|
|
$session_id = intval($session_id); |
|
3053
|
|
|
$courseId = api_get_course_int_id($course_code); |
|
3054
|
|
|
|
|
3055
|
|
|
$sql = "SELECT MAX(marks) as max, MIN(marks) as min, AVG(marks) as average |
|
3056
|
|
|
FROM $track_exercises e |
|
3057
|
|
|
INNER JOIN $track_attempt a |
|
3058
|
|
|
ON ( |
|
3059
|
|
|
a.exe_id = e.exe_id AND |
|
3060
|
|
|
e.c_id = a.c_id AND |
|
3061
|
|
|
e.session_id = a.session_id |
|
3062
|
|
|
) |
|
3063
|
|
|
WHERE |
|
3064
|
|
|
exe_exo_id = $exercise_id AND |
|
3065
|
|
|
a.c_id = $courseId AND |
|
3066
|
|
|
e.session_id = $session_id AND |
|
3067
|
|
|
question_id = $question_id AND |
|
3068
|
|
|
status = '' |
|
3069
|
|
|
LIMIT 1"; |
|
3070
|
|
|
$result = Database::query($sql); |
|
3071
|
|
|
$return = array(); |
|
3072
|
|
|
if ($result) { |
|
3073
|
|
|
$return = Database::fetch_array($result, 'ASSOC'); |
|
3074
|
|
|
} |
|
3075
|
|
|
|
|
3076
|
|
|
return $return; |
|
3077
|
|
|
} |
|
3078
|
|
|
|
|
3079
|
|
|
/** |
|
3080
|
|
|
* Get the correct answer count for a fill blanks question |
|
3081
|
|
|
* |
|
3082
|
|
|
* @param int $question_id |
|
3083
|
|
|
* @param int $exercise_id |
|
3084
|
|
|
* @return int |
|
3085
|
|
|
*/ |
|
3086
|
|
|
public static function getNumberStudentsFillBlanksAnwserCount( |
|
3087
|
|
|
$question_id, |
|
3088
|
|
|
$exercise_id |
|
3089
|
|
|
) |
|
3090
|
|
|
{ |
|
3091
|
|
|
$listStudentsId = []; |
|
3092
|
|
|
$listAllStudentInfo = CourseManager::get_student_list_from_course_code( |
|
3093
|
|
|
api_get_course_id(), |
|
3094
|
|
|
true |
|
3095
|
|
|
); |
|
3096
|
|
|
foreach ($listAllStudentInfo as $i => $listStudentInfo) { |
|
3097
|
|
|
$listStudentsId[] = $listStudentInfo['user_id']; |
|
3098
|
|
|
} |
|
3099
|
|
|
|
|
3100
|
|
|
$listFillTheBlankResult = FillBlanks::getFillTheBlankTabResult( |
|
3101
|
|
|
$exercise_id, |
|
3102
|
|
|
$question_id, |
|
3103
|
|
|
$listStudentsId, |
|
3104
|
|
|
'1970-01-01', |
|
3105
|
|
|
'3000-01-01' |
|
3106
|
|
|
); |
|
3107
|
|
|
|
|
3108
|
|
|
$arrayCount = []; |
|
3109
|
|
|
|
|
3110
|
|
|
foreach ($listFillTheBlankResult as $resultCount) { |
|
3111
|
|
|
foreach ($resultCount as $index => $count) { |
|
3112
|
|
|
//this is only for declare the array index per answer |
|
3113
|
|
|
$arrayCount[$index] = 0; |
|
3114
|
|
|
} |
|
3115
|
|
|
} |
|
3116
|
|
|
|
|
3117
|
|
|
foreach ($listFillTheBlankResult as $resultCount) { |
|
3118
|
|
|
foreach ($resultCount as $index => $count) { |
|
3119
|
|
|
$count = ($count === 0) ? 1 : 0; |
|
3120
|
|
|
$arrayCount[$index] += $count; |
|
3121
|
|
|
} |
|
3122
|
|
|
} |
|
3123
|
|
|
|
|
3124
|
|
|
return $arrayCount; |
|
3125
|
|
|
} |
|
3126
|
|
|
|
|
3127
|
|
|
/** |
|
3128
|
|
|
* @param int $question_id |
|
3129
|
|
|
* @param int $exercise_id |
|
3130
|
|
|
* @param string $course_code |
|
3131
|
|
|
* @param int $session_id |
|
3132
|
|
|
* @param string $questionType |
|
3133
|
|
|
* @return int |
|
3134
|
|
|
*/ |
|
3135
|
|
|
public static function get_number_students_question_with_answer_count( |
|
3136
|
|
|
$question_id, |
|
3137
|
|
|
$exercise_id, |
|
3138
|
|
|
$course_code, |
|
3139
|
|
|
$session_id, |
|
3140
|
|
|
$questionType = '' |
|
3141
|
|
|
) { |
|
3142
|
|
|
$track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
|
3143
|
|
|
$track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
|
3144
|
|
|
$courseUser = Database::get_main_table(TABLE_MAIN_COURSE_USER); |
|
3145
|
|
|
$courseTable = Database::get_main_table(TABLE_MAIN_COURSE); |
|
3146
|
|
|
$courseUserSession = Database::get_main_table( |
|
3147
|
|
|
TABLE_MAIN_SESSION_COURSE_USER |
|
3148
|
|
|
); |
|
3149
|
|
|
|
|
3150
|
|
|
$question_id = intval($question_id); |
|
3151
|
|
|
$exercise_id = intval($exercise_id); |
|
3152
|
|
|
$courseId = api_get_course_int_id($course_code); |
|
3153
|
|
|
$session_id = intval($session_id); |
|
3154
|
|
|
|
|
3155
|
|
|
if ($questionType == FILL_IN_BLANKS) { |
|
3156
|
|
|
$listStudentsId = array(); |
|
3157
|
|
|
$listAllStudentInfo = CourseManager::get_student_list_from_course_code( |
|
3158
|
|
|
api_get_course_id(), |
|
3159
|
|
|
true |
|
3160
|
|
|
); |
|
3161
|
|
|
foreach ($listAllStudentInfo as $i => $listStudentInfo) { |
|
3162
|
|
|
$listStudentsId[] = $listStudentInfo['user_id']; |
|
3163
|
|
|
} |
|
3164
|
|
|
|
|
3165
|
|
|
$listFillTheBlankResult = FillBlanks::getFillTheBlankTabResult( |
|
3166
|
|
|
$exercise_id, |
|
3167
|
|
|
$question_id, |
|
3168
|
|
|
$listStudentsId, |
|
3169
|
|
|
'1970-01-01', |
|
3170
|
|
|
'3000-01-01' |
|
3171
|
|
|
); |
|
3172
|
|
|
|
|
3173
|
|
|
return FillBlanks::getNbResultFillBlankAll($listFillTheBlankResult); |
|
3174
|
|
|
} |
|
3175
|
|
|
|
|
3176
|
|
View Code Duplication |
if (empty($session_id)) { |
|
3177
|
|
|
$courseCondition = " |
|
3178
|
|
|
INNER JOIN $courseUser cu |
|
3179
|
|
|
ON cu.c_id = c.id AND cu.user_id = exe_user_id"; |
|
3180
|
|
|
$courseConditionWhere = " AND relation_type <> 2 AND cu.status = ".STUDENT; |
|
3181
|
|
|
} else { |
|
3182
|
|
|
$courseCondition = " |
|
3183
|
|
|
INNER JOIN $courseUserSession cu |
|
3184
|
|
|
ON cu.c_id = c.id AND cu.user_id = exe_user_id"; |
|
3185
|
|
|
$courseConditionWhere = " AND cu.status = 0 "; |
|
3186
|
|
|
} |
|
3187
|
|
|
|
|
3188
|
|
|
$sql = "SELECT DISTINCT exe_user_id |
|
3189
|
|
|
FROM $track_exercises e |
|
3190
|
|
|
INNER JOIN $track_attempt a |
|
3191
|
|
|
ON ( |
|
3192
|
|
|
a.exe_id = e.exe_id AND |
|
3193
|
|
|
e.c_id = a.c_id AND |
|
3194
|
|
|
e.session_id = a.session_id |
|
3195
|
|
|
) |
|
3196
|
|
|
INNER JOIN $courseTable c |
|
3197
|
|
|
ON (c.id = a.c_id) |
|
3198
|
|
|
$courseCondition |
|
3199
|
|
|
WHERE |
|
3200
|
|
|
exe_exo_id = $exercise_id AND |
|
3201
|
|
|
a.c_id = $courseId AND |
|
3202
|
|
|
e.session_id = $session_id AND |
|
3203
|
|
|
question_id = $question_id AND |
|
3204
|
|
|
answer <> '0' AND |
|
3205
|
|
|
e.status = '' |
|
3206
|
|
|
$courseConditionWhere |
|
3207
|
|
|
"; |
|
3208
|
|
|
$result = Database::query($sql); |
|
3209
|
|
|
$return = 0; |
|
3210
|
|
|
if ($result) { |
|
3211
|
|
|
$return = Database::num_rows($result); |
|
3212
|
|
|
} |
|
3213
|
|
|
return $return; |
|
3214
|
|
|
} |
|
3215
|
|
|
|
|
3216
|
|
|
/** |
|
3217
|
|
|
* @param int $answer_id |
|
3218
|
|
|
* @param int $question_id |
|
3219
|
|
|
* @param int $exercise_id |
|
3220
|
|
|
* @param string $course_code |
|
3221
|
|
|
* @param int $session_id |
|
3222
|
|
|
* |
|
3223
|
|
|
* @return int |
|
3224
|
|
|
*/ |
|
3225
|
|
|
public static function get_number_students_answer_hotspot_count( |
|
3226
|
|
|
$answer_id, |
|
3227
|
|
|
$question_id, |
|
3228
|
|
|
$exercise_id, |
|
3229
|
|
|
$course_code, |
|
3230
|
|
|
$session_id |
|
3231
|
|
|
) |
|
3232
|
|
|
{ |
|
3233
|
|
|
$track_exercises = Database::get_main_table( |
|
3234
|
|
|
TABLE_STATISTIC_TRACK_E_EXERCISES |
|
3235
|
|
|
); |
|
3236
|
|
|
$track_hotspot = Database::get_main_table( |
|
3237
|
|
|
TABLE_STATISTIC_TRACK_E_HOTSPOT |
|
3238
|
|
|
); |
|
3239
|
|
|
$courseUser = Database::get_main_table(TABLE_MAIN_COURSE_USER); |
|
3240
|
|
|
$courseTable = Database::get_main_table(TABLE_MAIN_COURSE); |
|
3241
|
|
|
|
|
3242
|
|
|
$courseUserSession = Database::get_main_table( |
|
3243
|
|
|
TABLE_MAIN_SESSION_COURSE_USER |
|
3244
|
|
|
); |
|
3245
|
|
|
|
|
3246
|
|
|
$question_id = intval($question_id); |
|
3247
|
|
|
$answer_id = intval($answer_id); |
|
3248
|
|
|
$exercise_id = intval($exercise_id); |
|
3249
|
|
|
$course_code = Database::escape_string($course_code); |
|
3250
|
|
|
$session_id = intval($session_id); |
|
3251
|
|
|
|
|
3252
|
|
View Code Duplication |
if (empty($session_id)) { |
|
3253
|
|
|
$courseCondition = " |
|
3254
|
|
|
INNER JOIN $courseUser cu |
|
3255
|
|
|
ON cu.c_id = c.id AND cu.user_id = exe_user_id"; |
|
3256
|
|
|
$courseConditionWhere = " AND relation_type <> 2 AND cu.status = ".STUDENT; |
|
3257
|
|
|
} else { |
|
3258
|
|
|
$courseCondition = " |
|
3259
|
|
|
INNER JOIN $courseUserSession cu |
|
3260
|
|
|
ON cu.c_id = c.id AND cu.user_id = exe_user_id"; |
|
3261
|
|
|
$courseConditionWhere = " AND cu.status = 0 "; |
|
3262
|
|
|
} |
|
3263
|
|
|
|
|
3264
|
|
|
$sql = "SELECT DISTINCT exe_user_id |
|
3265
|
|
|
FROM $track_exercises e |
|
3266
|
|
|
INNER JOIN $track_hotspot a |
|
3267
|
|
|
ON (a.hotspot_exe_id = e.exe_id) |
|
3268
|
|
|
INNER JOIN $courseTable c |
|
3269
|
|
|
ON (hotspot_course_code = c.code) |
|
3270
|
|
|
$courseCondition |
|
3271
|
|
|
WHERE |
|
3272
|
|
|
exe_exo_id = $exercise_id AND |
|
3273
|
|
|
a.hotspot_course_code = '$course_code' AND |
|
3274
|
|
|
e.session_id = $session_id AND |
|
3275
|
|
|
hotspot_answer_id = $answer_id AND |
|
3276
|
|
|
hotspot_question_id = $question_id AND |
|
3277
|
|
|
hotspot_correct = 1 AND |
|
3278
|
|
|
e.status = '' |
|
3279
|
|
|
$courseConditionWhere |
|
3280
|
|
|
"; |
|
3281
|
|
|
|
|
3282
|
|
|
$result = Database::query($sql); |
|
3283
|
|
|
$return = 0; |
|
3284
|
|
|
if ($result) { |
|
3285
|
|
|
$return = Database::num_rows($result); |
|
3286
|
|
|
} |
|
3287
|
|
|
return $return; |
|
3288
|
|
|
} |
|
3289
|
|
|
|
|
3290
|
|
|
/** |
|
3291
|
|
|
* @param int $answer_id |
|
3292
|
|
|
* @param int $question_id |
|
3293
|
|
|
* @param int $exercise_id |
|
3294
|
|
|
* @param string $course_code |
|
3295
|
|
|
* @param int $session_id |
|
3296
|
|
|
* @param string $question_type |
|
3297
|
|
|
* @param string $correct_answer |
|
3298
|
|
|
* @param string $current_answer |
|
3299
|
|
|
* @return int |
|
3300
|
|
|
*/ |
|
3301
|
|
|
public static function get_number_students_answer_count( |
|
3302
|
|
|
$answer_id, |
|
3303
|
|
|
$question_id, |
|
3304
|
|
|
$exercise_id, |
|
3305
|
|
|
$course_code, |
|
3306
|
|
|
$session_id, |
|
3307
|
|
|
$question_type = null, |
|
3308
|
|
|
$correct_answer = null, |
|
3309
|
|
|
$current_answer = null |
|
3310
|
|
|
) { |
|
3311
|
|
|
$track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
|
3312
|
|
|
$track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
|
3313
|
|
|
$courseTable = Database::get_main_table(TABLE_MAIN_COURSE); |
|
3314
|
|
|
$courseUser = Database::get_main_table(TABLE_MAIN_COURSE_USER); |
|
3315
|
|
|
$courseUserSession = Database::get_main_table( |
|
3316
|
|
|
TABLE_MAIN_SESSION_COURSE_USER |
|
3317
|
|
|
); |
|
3318
|
|
|
|
|
3319
|
|
|
$question_id = intval($question_id); |
|
3320
|
|
|
$answer_id = intval($answer_id); |
|
3321
|
|
|
$exercise_id = intval($exercise_id); |
|
3322
|
|
|
$courseId = api_get_course_int_id($course_code); |
|
3323
|
|
|
$course_code = Database::escape_string($course_code); |
|
3324
|
|
|
$session_id = intval($session_id); |
|
3325
|
|
|
|
|
3326
|
|
|
switch ($question_type) { |
|
3327
|
|
|
case FILL_IN_BLANKS: |
|
3328
|
|
|
$answer_condition = ""; |
|
3329
|
|
|
$select_condition = " e.exe_id, answer "; |
|
3330
|
|
|
break; |
|
3331
|
|
|
case MATCHING: |
|
3332
|
|
|
//no break |
|
3333
|
|
|
case MATCHING_DRAGGABLE: |
|
3334
|
|
|
//no break |
|
3335
|
|
|
default: |
|
3336
|
|
|
$answer_condition = " answer = $answer_id AND "; |
|
3337
|
|
|
$select_condition = " DISTINCT exe_user_id "; |
|
3338
|
|
|
} |
|
3339
|
|
|
|
|
3340
|
|
View Code Duplication |
if (empty($session_id)) { |
|
3341
|
|
|
$courseCondition = " |
|
3342
|
|
|
INNER JOIN $courseUser cu |
|
3343
|
|
|
ON cu.c_id = c.id AND cu.user_id = exe_user_id"; |
|
3344
|
|
|
$courseConditionWhere = " AND relation_type <> 2 AND cu.status = ".STUDENT; |
|
3345
|
|
|
} else { |
|
3346
|
|
|
$courseCondition = " |
|
3347
|
|
|
INNER JOIN $courseUserSession cu |
|
3348
|
|
|
ON cu.c_id = a.c_id AND cu.user_id = exe_user_id"; |
|
3349
|
|
|
$courseConditionWhere = " AND cu.status = 0 "; |
|
3350
|
|
|
} |
|
3351
|
|
|
|
|
3352
|
|
|
$sql = "SELECT $select_condition |
|
3353
|
|
|
FROM $track_exercises e |
|
3354
|
|
|
INNER JOIN $track_attempt a |
|
3355
|
|
|
ON ( |
|
3356
|
|
|
a.exe_id = e.exe_id AND |
|
3357
|
|
|
e.c_id = a.c_id AND |
|
3358
|
|
|
e.session_id = a.session_id |
|
3359
|
|
|
) |
|
3360
|
|
|
INNER JOIN $courseTable c |
|
3361
|
|
|
ON c.id = a.c_id |
|
3362
|
|
|
$courseCondition |
|
3363
|
|
|
WHERE |
|
3364
|
|
|
exe_exo_id = $exercise_id AND |
|
3365
|
|
|
a.c_id = $courseId AND |
|
3366
|
|
|
e.session_id = $session_id AND |
|
3367
|
|
|
$answer_condition |
|
3368
|
|
|
question_id = $question_id AND |
|
3369
|
|
|
e.status = '' |
|
3370
|
|
|
$courseConditionWhere |
|
3371
|
|
|
"; |
|
3372
|
|
|
$result = Database::query($sql); |
|
3373
|
|
|
$return = 0; |
|
3374
|
|
|
if ($result) { |
|
3375
|
|
|
$good_answers = 0; |
|
3376
|
|
|
switch ($question_type) { |
|
3377
|
|
|
case FILL_IN_BLANKS: |
|
3378
|
|
|
while ($row = Database::fetch_array($result, 'ASSOC')) { |
|
3379
|
|
|
$fill_blank = self::check_fill_in_blanks( |
|
3380
|
|
|
$correct_answer, |
|
3381
|
|
|
$row['answer'], |
|
3382
|
|
|
$current_answer |
|
3383
|
|
|
); |
|
3384
|
|
|
if (isset($fill_blank[$current_answer]) && $fill_blank[$current_answer] == 1) { |
|
3385
|
|
|
$good_answers++; |
|
3386
|
|
|
} |
|
3387
|
|
|
} |
|
3388
|
|
|
return $good_answers; |
|
3389
|
|
|
break; |
|
3390
|
|
|
case MATCHING: |
|
3391
|
|
|
//no break |
|
3392
|
|
|
case MATCHING_DRAGGABLE: |
|
3393
|
|
|
//no break |
|
3394
|
|
|
default: |
|
3395
|
|
|
$return = Database::num_rows($result); |
|
3396
|
|
|
} |
|
3397
|
|
|
} |
|
3398
|
|
|
|
|
3399
|
|
|
return $return; |
|
3400
|
|
|
} |
|
3401
|
|
|
|
|
3402
|
|
|
/** |
|
3403
|
|
|
* @param array $answer |
|
3404
|
|
|
* @param string $user_answer |
|
3405
|
|
|
* @return array |
|
3406
|
|
|
*/ |
|
3407
|
|
|
public static function check_fill_in_blanks($answer, $user_answer, $current_answer) |
|
3408
|
|
|
{ |
|
3409
|
|
|
// the question is encoded like this |
|
3410
|
|
|
// [A] B [C] D [E] F::10,10,10@1 |
|
3411
|
|
|
// number 1 before the "@" means that is a switchable fill in blank question |
|
3412
|
|
|
// [A] B [C] D [E] F::10,10,10@ or [A] B [C] D [E] F::10,10,10 |
|
3413
|
|
|
// means that is a normal fill blank question |
|
3414
|
|
|
// first we explode the "::" |
|
3415
|
|
|
$pre_array = explode('::', $answer); |
|
3416
|
|
|
// is switchable fill blank or not |
|
3417
|
|
|
$last = count($pre_array) - 1; |
|
3418
|
|
|
$is_set_switchable = explode('@', $pre_array[$last]); |
|
3419
|
|
|
$switchable_answer_set = false; |
|
3420
|
|
|
if (isset ($is_set_switchable[1]) && $is_set_switchable[1] == 1) { |
|
3421
|
|
|
$switchable_answer_set = true; |
|
3422
|
|
|
} |
|
3423
|
|
|
$answer = ''; |
|
3424
|
|
|
for ($k = 0; $k < $last; $k++) { |
|
3425
|
|
|
$answer .= $pre_array[$k]; |
|
3426
|
|
|
} |
|
3427
|
|
|
// splits weightings that are joined with a comma |
|
3428
|
|
|
$answerWeighting = explode(',', $is_set_switchable[0]); |
|
3429
|
|
|
|
|
3430
|
|
|
// we save the answer because it will be modified |
|
3431
|
|
|
//$temp = $answer; |
|
3432
|
|
|
$temp = $answer; |
|
3433
|
|
|
|
|
3434
|
|
|
$answer = ''; |
|
3435
|
|
|
$j = 0; |
|
3436
|
|
|
//initialise answer tags |
|
3437
|
|
|
$user_tags = $correct_tags = $real_text = array(); |
|
3438
|
|
|
// the loop will stop at the end of the text |
|
3439
|
|
|
while (1) { |
|
3440
|
|
|
// quits the loop if there are no more blanks (detect '[') |
|
3441
|
|
|
if (($pos = api_strpos($temp, '[')) === false) { |
|
|
|
|
|
|
3442
|
|
|
// adds the end of the text |
|
3443
|
|
|
$answer = $temp; |
|
3444
|
|
|
$real_text[] = $answer; |
|
3445
|
|
|
break; //no more "blanks", quit the loop |
|
3446
|
|
|
} |
|
3447
|
|
|
// adds the piece of text that is before the blank |
|
3448
|
|
|
//and ends with '[' into a general storage array |
|
3449
|
|
|
$real_text[] = api_substr($temp, 0, $pos + 1); |
|
|
|
|
|
|
3450
|
|
|
$answer .= api_substr($temp, 0, $pos + 1); |
|
|
|
|
|
|
3451
|
|
|
//take the string remaining (after the last "[" we found) |
|
3452
|
|
|
$temp = api_substr($temp, $pos + 1); |
|
|
|
|
|
|
3453
|
|
|
// quit the loop if there are no more blanks, and update $pos to the position of next ']' |
|
3454
|
|
|
if (($pos = api_strpos($temp, ']')) === false) { |
|
|
|
|
|
|
3455
|
|
|
// adds the end of the text |
|
3456
|
|
|
$answer .= $temp; |
|
3457
|
|
|
break; |
|
3458
|
|
|
} |
|
3459
|
|
|
|
|
3460
|
|
|
$str = $user_answer; |
|
3461
|
|
|
|
|
3462
|
|
|
preg_match_all('#\[([^[]*)\]#', $str, $arr); |
|
3463
|
|
|
$str = str_replace('\r\n', '', $str); |
|
3464
|
|
|
$choices = $arr[1]; |
|
3465
|
|
|
$choice = []; |
|
3466
|
|
|
$check = false; |
|
3467
|
|
|
$i = 0; |
|
3468
|
|
|
foreach ($choices as $item) { |
|
3469
|
|
|
if ($current_answer === $item) { |
|
3470
|
|
|
$check = true; |
|
3471
|
|
|
} |
|
3472
|
|
|
if ($check) { |
|
3473
|
|
|
$choice[] = $item; |
|
3474
|
|
|
$i++; |
|
3475
|
|
|
} |
|
3476
|
|
|
if ($i == 3) { |
|
3477
|
|
|
break; |
|
3478
|
|
|
} |
|
3479
|
|
|
} |
|
3480
|
|
|
$tmp = api_strrpos($choice[$j], ' / '); |
|
3481
|
|
|
|
|
3482
|
|
|
if ($tmp !== false) { |
|
3483
|
|
|
$choice[$j] = api_substr($choice[$j], 0, $tmp); |
|
3484
|
|
|
} |
|
3485
|
|
|
|
|
3486
|
|
|
$choice[$j] = trim($choice[$j]); |
|
3487
|
|
|
|
|
3488
|
|
|
//Needed to let characters ' and " to work as part of an answer |
|
3489
|
|
|
$choice[$j] = stripslashes($choice[$j]); |
|
3490
|
|
|
|
|
3491
|
|
|
$user_tags[] = api_strtolower($choice[$j]); |
|
3492
|
|
|
//put the contents of the [] answer tag into correct_tags[] |
|
3493
|
|
|
$correct_tags[] = api_strtolower(api_substr($temp, 0, $pos)); |
|
|
|
|
|
|
3494
|
|
|
$j++; |
|
3495
|
|
|
$temp = api_substr($temp, $pos + 1); |
|
|
|
|
|
|
3496
|
|
|
} |
|
3497
|
|
|
|
|
3498
|
|
|
$answer = ''; |
|
3499
|
|
|
$real_correct_tags = $correct_tags; |
|
3500
|
|
|
$chosen_list = array(); |
|
3501
|
|
|
$good_answer = array(); |
|
3502
|
|
|
|
|
3503
|
|
|
for ($i = 0; $i < count($real_correct_tags); $i++) { |
|
3504
|
|
|
if (!$switchable_answer_set) { |
|
3505
|
|
|
//needed to parse ' and " characters |
|
3506
|
|
|
$user_tags[$i] = stripslashes($user_tags[$i]); |
|
3507
|
|
|
if ($correct_tags[$i] == $user_tags[$i]) { |
|
3508
|
|
|
$good_answer[$correct_tags[$i]] = 1; |
|
3509
|
|
|
} elseif (!empty ($user_tags[$i])) { |
|
3510
|
|
|
$good_answer[$correct_tags[$i]] = 0; |
|
3511
|
|
|
} else { |
|
3512
|
|
|
$good_answer[$correct_tags[$i]] = 0; |
|
3513
|
|
|
} |
|
3514
|
|
|
} else { |
|
3515
|
|
|
// switchable fill in the blanks |
|
3516
|
|
|
if (in_array($user_tags[$i], $correct_tags)) { |
|
3517
|
|
|
$correct_tags = array_diff($correct_tags, $chosen_list); |
|
3518
|
|
|
$good_answer[$correct_tags[$i]] = 1; |
|
3519
|
|
|
} elseif (!empty ($user_tags[$i])) { |
|
3520
|
|
|
$good_answer[$correct_tags[$i]] = 0; |
|
3521
|
|
|
} else { |
|
3522
|
|
|
$good_answer[$correct_tags[$i]] = 0; |
|
3523
|
|
|
} |
|
3524
|
|
|
} |
|
3525
|
|
|
// adds the correct word, followed by ] to close the blank |
|
3526
|
|
|
$answer .= ' / <font color="green"><b>'.$real_correct_tags[$i].'</b></font>]'; |
|
3527
|
|
|
if (isset ($real_text[$i + 1])) { |
|
3528
|
|
|
$answer .= $real_text[$i + 1]; |
|
3529
|
|
|
} |
|
3530
|
|
|
} |
|
3531
|
|
|
|
|
3532
|
|
|
return $good_answer; |
|
3533
|
|
|
} |
|
3534
|
|
|
|
|
3535
|
|
|
/** |
|
3536
|
|
|
* @param int $exercise_id |
|
3537
|
|
|
* @param string $course_code |
|
3538
|
|
|
* @param int $session_id |
|
3539
|
|
|
* @return int |
|
3540
|
|
|
*/ |
|
3541
|
|
View Code Duplication |
public static function get_number_students_finish_exercise( |
|
3542
|
|
|
$exercise_id, |
|
3543
|
|
|
$course_code, |
|
3544
|
|
|
$session_id |
|
3545
|
|
|
) { |
|
3546
|
|
|
$track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
|
3547
|
|
|
$track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
|
3548
|
|
|
|
|
3549
|
|
|
$exercise_id = intval($exercise_id); |
|
3550
|
|
|
$course_code = Database::escape_string($course_code); |
|
3551
|
|
|
$session_id = intval($session_id); |
|
3552
|
|
|
|
|
3553
|
|
|
$sql = "SELECT DISTINCT exe_user_id |
|
3554
|
|
|
FROM $track_exercises e |
|
3555
|
|
|
INNER JOIN $track_attempt a |
|
3556
|
|
|
ON (a.exe_id = e.exe_id) |
|
3557
|
|
|
WHERE |
|
3558
|
|
|
exe_exo_id = $exercise_id AND |
|
3559
|
|
|
course_code = '$course_code' AND |
|
3560
|
|
|
e.session_id = $session_id AND |
|
3561
|
|
|
status = ''"; |
|
3562
|
|
|
$result = Database::query($sql); |
|
3563
|
|
|
$return = 0; |
|
3564
|
|
|
if ($result) { |
|
3565
|
|
|
$return = Database::num_rows($result); |
|
3566
|
|
|
|
|
3567
|
|
|
} |
|
3568
|
|
|
return $return; |
|
3569
|
|
|
} |
|
3570
|
|
|
|
|
3571
|
|
|
/** |
|
3572
|
|
|
* @param string $in_name is the name and the id of the <select> |
|
3573
|
|
|
* @param string $in_default default value for option |
|
3574
|
|
|
* @param string $in_onchange |
|
3575
|
|
|
* @return string the html code of the <select> |
|
3576
|
|
|
*/ |
|
3577
|
|
|
public static function displayGroupMenu($in_name, $in_default, $in_onchange = "") |
|
3578
|
|
|
{ |
|
3579
|
|
|
// check the default value of option |
|
3580
|
|
|
$tabSelected = array($in_default => " selected='selected' "); |
|
3581
|
|
|
$res = ""; |
|
3582
|
|
|
$res .= "<select name='$in_name' id='$in_name' onchange='".$in_onchange."' >"; |
|
3583
|
|
|
$res .= "<option value='-1'".$tabSelected["-1"].">-- ".get_lang( |
|
3584
|
|
|
'AllGroups' |
|
3585
|
|
|
)." --</option>"; |
|
3586
|
|
|
$res .= "<option value='0'".$tabSelected["0"].">- ".get_lang( |
|
3587
|
|
|
'NotInAGroup' |
|
3588
|
|
|
)." -</option>"; |
|
3589
|
|
|
$tabGroups = GroupManager::get_group_list(); |
|
3590
|
|
|
$currentCatId = 0; |
|
3591
|
|
|
for ($i = 0; $i < count($tabGroups); $i++) { |
|
3592
|
|
|
$tabCategory = GroupManager::get_category_from_group( |
|
3593
|
|
|
$tabGroups[$i]['iid'] |
|
3594
|
|
|
); |
|
3595
|
|
|
if ($tabCategory["id"] != $currentCatId) { |
|
3596
|
|
|
$res .= "<option value='-1' disabled='disabled'>".$tabCategory["title"]."</option>"; |
|
3597
|
|
|
$currentCatId = $tabCategory["id"]; |
|
3598
|
|
|
} |
|
3599
|
|
|
$res .= "<option ".$tabSelected[$tabGroups[$i]["id"]]."style='margin-left:40px' value='".$tabGroups[$i]["id"]."'>".$tabGroups[$i]["name"]."</option>"; |
|
3600
|
|
|
} |
|
3601
|
|
|
$res .= "</select>"; |
|
3602
|
|
|
return $res; |
|
3603
|
|
|
} |
|
3604
|
|
|
|
|
3605
|
|
|
/** |
|
3606
|
|
|
* @param int $exe_id |
|
3607
|
|
|
*/ |
|
3608
|
|
|
public static function create_chat_exercise_session($exe_id) |
|
3609
|
|
|
{ |
|
3610
|
|
|
if (!isset($_SESSION['current_exercises'])) { |
|
3611
|
|
|
$_SESSION['current_exercises'] = array(); |
|
3612
|
|
|
} |
|
3613
|
|
|
$_SESSION['current_exercises'][$exe_id] = true; |
|
3614
|
|
|
} |
|
3615
|
|
|
|
|
3616
|
|
|
/** |
|
3617
|
|
|
* @param int $exe_id |
|
3618
|
|
|
*/ |
|
3619
|
|
|
public static function delete_chat_exercise_session($exe_id) |
|
3620
|
|
|
{ |
|
3621
|
|
|
if (isset($_SESSION['current_exercises'])) { |
|
3622
|
|
|
$_SESSION['current_exercises'][$exe_id] = false; |
|
3623
|
|
|
} |
|
3624
|
|
|
} |
|
3625
|
|
|
|
|
3626
|
|
|
/** |
|
3627
|
|
|
* Display the exercise results |
|
3628
|
|
|
* @param Exercise $objExercise |
|
3629
|
|
|
* @param int $exe_id |
|
3630
|
|
|
* @param bool $save_user_result save users results (true) or just show the results (false) |
|
3631
|
|
|
* @param string $remainingMessage |
|
3632
|
|
|
*/ |
|
3633
|
|
|
public static function display_question_list_by_attempt( |
|
3634
|
|
|
$objExercise, |
|
3635
|
|
|
$exe_id, |
|
3636
|
|
|
$save_user_result = false, |
|
3637
|
|
|
$remainingMessage = '' |
|
3638
|
|
|
) { |
|
3639
|
|
|
$origin = api_get_origin(); |
|
3640
|
|
|
|
|
3641
|
|
|
// Getting attempt info |
|
3642
|
|
|
$exercise_stat_info = $objExercise->get_stat_track_exercise_info_by_exe_id( |
|
3643
|
|
|
$exe_id |
|
3644
|
|
|
); |
|
3645
|
|
|
|
|
3646
|
|
|
// Getting question list |
|
3647
|
|
|
$question_list = array(); |
|
3648
|
|
|
if (!empty($exercise_stat_info['data_tracking'])) { |
|
3649
|
|
|
$question_list = explode(',', $exercise_stat_info['data_tracking']); |
|
3650
|
|
|
} else { |
|
3651
|
|
|
// Try getting the question list only if save result is off |
|
3652
|
|
|
if ($save_user_result == false) { |
|
3653
|
|
|
$question_list = $objExercise->get_validated_question_list(); |
|
3654
|
|
|
} |
|
3655
|
|
|
if ($objExercise->selectFeedbackType() == EXERCISE_FEEDBACK_TYPE_DIRECT) { |
|
3656
|
|
|
$question_list = $objExercise->get_validated_question_list(); |
|
3657
|
|
|
} |
|
3658
|
|
|
} |
|
3659
|
|
|
|
|
3660
|
|
|
$counter = 1; |
|
3661
|
|
|
$total_score = $total_weight = 0; |
|
3662
|
|
|
$exercise_content = null; |
|
3663
|
|
|
|
|
3664
|
|
|
// Hide results |
|
3665
|
|
|
$show_results = false; |
|
3666
|
|
|
$show_only_score = false; |
|
3667
|
|
|
|
|
3668
|
|
|
if ($objExercise->results_disabled == RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS) { |
|
3669
|
|
|
$show_results = true; |
|
3670
|
|
|
} |
|
3671
|
|
|
|
|
3672
|
|
|
if (in_array( |
|
3673
|
|
|
$objExercise->results_disabled, |
|
3674
|
|
|
array( |
|
3675
|
|
|
RESULT_DISABLE_SHOW_SCORE_ONLY, |
|
3676
|
|
|
RESULT_DISABLE_SHOW_FINAL_SCORE_ONLY_WITH_CATEGORIES |
|
3677
|
|
|
) |
|
3678
|
|
|
) |
|
3679
|
|
|
) { |
|
3680
|
|
|
$show_only_score = true; |
|
3681
|
|
|
} |
|
3682
|
|
|
|
|
3683
|
|
|
// Not display expected answer, but score, and feedback |
|
3684
|
|
|
$show_all_but_expected_answer = false; |
|
3685
|
|
|
if ($objExercise->results_disabled == RESULT_DISABLE_SHOW_SCORE_ONLY && |
|
3686
|
|
|
$objExercise->feedback_type == EXERCISE_FEEDBACK_TYPE_END |
|
3687
|
|
|
) { |
|
3688
|
|
|
$show_all_but_expected_answer = true; |
|
3689
|
|
|
$show_results = true; |
|
3690
|
|
|
$show_only_score = false; |
|
3691
|
|
|
} |
|
3692
|
|
|
|
|
3693
|
|
|
$showTotalScoreAndUserChoicesInLastAttempt = true; |
|
3694
|
|
|
|
|
3695
|
|
|
if ($objExercise->results_disabled == RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT) { |
|
3696
|
|
|
$show_only_score = true; |
|
3697
|
|
|
$show_results = true; |
|
3698
|
|
|
if ($objExercise->attempts > 0) { |
|
3699
|
|
|
$attempts = Event::getExerciseResultsByUser( |
|
3700
|
|
|
api_get_user_id(), |
|
3701
|
|
|
$objExercise->id, |
|
3702
|
|
|
api_get_course_int_id(), |
|
3703
|
|
|
api_get_session_id(), |
|
3704
|
|
|
$exercise_stat_info['orig_lp_id'], |
|
3705
|
|
|
$exercise_stat_info['orig_lp_item_id'], |
|
3706
|
|
|
'desc' |
|
3707
|
|
|
); |
|
3708
|
|
|
|
|
3709
|
|
|
if ($attempts) { |
|
3710
|
|
|
$numberAttempts = count($attempts); |
|
3711
|
|
|
} else { |
|
3712
|
|
|
$numberAttempts = 0; |
|
3713
|
|
|
} |
|
3714
|
|
|
|
|
3715
|
|
|
if ($save_user_result) { |
|
3716
|
|
|
$numberAttempts++; |
|
3717
|
|
|
} |
|
3718
|
|
|
if ($numberAttempts >= $objExercise->attempts) { |
|
3719
|
|
|
$show_results = true; |
|
3720
|
|
|
$show_only_score = false; |
|
3721
|
|
|
$showTotalScoreAndUserChoicesInLastAttempt = true; |
|
3722
|
|
|
} else { |
|
3723
|
|
|
$showTotalScoreAndUserChoicesInLastAttempt = false; |
|
3724
|
|
|
} |
|
3725
|
|
|
} |
|
3726
|
|
|
} |
|
3727
|
|
|
|
|
3728
|
|
|
if ($show_results || $show_only_score) { |
|
3729
|
|
|
if (isset($exercise_stat_info['exe_user_id'])) { |
|
3730
|
|
|
$user_info = api_get_user_info($exercise_stat_info['exe_user_id']); |
|
3731
|
|
|
if ($user_info) { |
|
3732
|
|
|
|
|
3733
|
|
|
// Shows exercise header |
|
3734
|
|
|
echo $objExercise->show_exercise_result_header( |
|
3735
|
|
|
$user_info, |
|
3736
|
|
|
api_convert_and_format_date( |
|
3737
|
|
|
$exercise_stat_info['start_date'], |
|
3738
|
|
|
DATE_TIME_FORMAT_LONG |
|
3739
|
|
|
), |
|
3740
|
|
|
$exercise_stat_info['duration'], |
|
3741
|
|
|
$exercise_stat_info['user_ip'] |
|
3742
|
|
|
); |
|
3743
|
|
|
} |
|
3744
|
|
|
} |
|
3745
|
|
|
} |
|
3746
|
|
|
|
|
3747
|
|
|
// Display text when test is finished #4074 and for LP #4227 |
|
3748
|
|
|
$end_of_message = $objExercise->selectTextWhenFinished(); |
|
3749
|
|
|
if (!empty($end_of_message)) { |
|
3750
|
|
|
echo Display::return_message($end_of_message, 'normal', false); |
|
3751
|
|
|
echo "<div class='clear'> </div>"; |
|
3752
|
|
|
} |
|
3753
|
|
|
|
|
3754
|
|
|
$question_list_answers = array(); |
|
3755
|
|
|
$media_list = array(); |
|
3756
|
|
|
$category_list = array(); |
|
3757
|
|
|
$loadChoiceFromSession = false; |
|
3758
|
|
|
$fromDatabase = true; |
|
3759
|
|
|
$exerciseResult = null; |
|
3760
|
|
|
$exerciseResultCoordinates = null; |
|
3761
|
|
|
$delineationResults = null; |
|
3762
|
|
|
if ($objExercise->selectFeedbackType() == EXERCISE_FEEDBACK_TYPE_DIRECT) { |
|
3763
|
|
|
$loadChoiceFromSession = true; |
|
3764
|
|
|
$fromDatabase = false; |
|
3765
|
|
|
$exerciseResult = Session::read('exerciseResult'); |
|
3766
|
|
|
$exerciseResultCoordinates = Session::read('exerciseResultCoordinates'); |
|
3767
|
|
|
$delineationResults = Session::read('hotspot_delineation_result'); |
|
3768
|
|
|
$delineationResults = isset($delineationResults[$objExercise->id]) ? $delineationResults[$objExercise->id] : null; |
|
3769
|
|
|
} |
|
3770
|
|
|
|
|
3771
|
|
|
$countPendingQuestions = 0; |
|
3772
|
|
|
// Loop over all question to show results for each of them, one by one |
|
3773
|
|
|
if (!empty($question_list)) { |
|
3774
|
|
|
foreach ($question_list as $questionId) { |
|
3775
|
|
|
// creates a temporary Question object |
|
3776
|
|
|
$objQuestionTmp = Question::read($questionId); |
|
3777
|
|
|
|
|
3778
|
|
|
// This variable came from exercise_submit_modal.php |
|
3779
|
|
|
ob_start(); |
|
3780
|
|
|
$choice = null; |
|
3781
|
|
|
$delineationChoice = null; |
|
3782
|
|
|
if ($loadChoiceFromSession) { |
|
3783
|
|
|
$choice = isset($exerciseResult[$questionId]) ? $exerciseResult[$questionId] : null; |
|
3784
|
|
|
$delineationChoice = isset($delineationResults[$questionId]) ? $delineationResults[$questionId] : null; |
|
3785
|
|
|
} |
|
3786
|
|
|
|
|
3787
|
|
|
// We're inside *one* question. Go through each possible answer for this question |
|
3788
|
|
|
$result = $objExercise->manage_answer( |
|
3789
|
|
|
$exe_id, |
|
3790
|
|
|
$questionId, |
|
3791
|
|
|
$choice, |
|
3792
|
|
|
'exercise_result', |
|
3793
|
|
|
$exerciseResultCoordinates, |
|
3794
|
|
|
$save_user_result, |
|
3795
|
|
|
$fromDatabase, |
|
3796
|
|
|
$show_results, |
|
3797
|
|
|
$objExercise->selectPropagateNeg(), |
|
3798
|
|
|
$delineationChoice, |
|
3799
|
|
|
$showTotalScoreAndUserChoicesInLastAttempt |
|
3800
|
|
|
); |
|
3801
|
|
|
|
|
3802
|
|
|
if (empty($result)) { |
|
3803
|
|
|
continue; |
|
3804
|
|
|
} |
|
3805
|
|
|
|
|
3806
|
|
|
$total_score += $result['score']; |
|
3807
|
|
|
$total_weight += $result['weight']; |
|
3808
|
|
|
|
|
3809
|
|
|
$question_list_answers[] = array( |
|
3810
|
|
|
'question' => $result['open_question'], |
|
3811
|
|
|
'answer' => $result['open_answer'], |
|
3812
|
|
|
'answer_type' => $result['answer_type'] |
|
3813
|
|
|
); |
|
3814
|
|
|
|
|
3815
|
|
|
$my_total_score = $result['score']; |
|
3816
|
|
|
$my_total_weight = $result['weight']; |
|
3817
|
|
|
|
|
3818
|
|
|
// Category report |
|
3819
|
|
|
$category_was_added_for_this_test = false; |
|
3820
|
|
|
|
|
3821
|
|
View Code Duplication |
if (isset($objQuestionTmp->category) && !empty($objQuestionTmp->category)) { |
|
3822
|
|
|
if (!isset($category_list[$objQuestionTmp->category]['score'])) { |
|
3823
|
|
|
$category_list[$objQuestionTmp->category]['score'] = 0; |
|
3824
|
|
|
} |
|
3825
|
|
|
if (!isset($category_list[$objQuestionTmp->category]['total'])) { |
|
3826
|
|
|
$category_list[$objQuestionTmp->category]['total'] = 0; |
|
3827
|
|
|
} |
|
3828
|
|
|
$category_list[$objQuestionTmp->category]['score'] += $my_total_score; |
|
3829
|
|
|
$category_list[$objQuestionTmp->category]['total'] += $my_total_weight; |
|
3830
|
|
|
$category_was_added_for_this_test = true; |
|
3831
|
|
|
} |
|
3832
|
|
|
|
|
3833
|
|
View Code Duplication |
if (isset($objQuestionTmp->category_list) && !empty($objQuestionTmp->category_list)) { |
|
3834
|
|
|
foreach ($objQuestionTmp->category_list as $category_id) { |
|
3835
|
|
|
$category_list[$category_id]['score'] += $my_total_score; |
|
3836
|
|
|
$category_list[$category_id]['total'] += $my_total_weight; |
|
3837
|
|
|
$category_was_added_for_this_test = true; |
|
3838
|
|
|
} |
|
3839
|
|
|
} |
|
3840
|
|
|
|
|
3841
|
|
|
// No category for this question! |
|
3842
|
|
|
if ($category_was_added_for_this_test == false) { |
|
3843
|
|
|
if (!isset($category_list['none']['score'])) { |
|
3844
|
|
|
$category_list['none']['score'] = 0; |
|
3845
|
|
|
} |
|
3846
|
|
|
if (!isset($category_list['none']['total'])) { |
|
3847
|
|
|
$category_list['none']['total'] = 0; |
|
3848
|
|
|
} |
|
3849
|
|
|
|
|
3850
|
|
|
$category_list['none']['score'] += $my_total_score; |
|
3851
|
|
|
$category_list['none']['total'] += $my_total_weight; |
|
3852
|
|
|
} |
|
3853
|
|
|
|
|
3854
|
|
|
if ($objExercise->selectPropagateNeg() == 0 && $my_total_score < 0 |
|
3855
|
|
|
) { |
|
3856
|
|
|
$my_total_score = 0; |
|
3857
|
|
|
} |
|
3858
|
|
|
|
|
3859
|
|
|
$comnt = null; |
|
3860
|
|
View Code Duplication |
if ($show_results) { |
|
3861
|
|
|
$comnt = Event::get_comments($exe_id, $questionId); |
|
3862
|
|
|
if (!empty($comnt)) { |
|
3863
|
|
|
echo '<b>'.get_lang('Feedback').'</b>'; |
|
3864
|
|
|
echo ExerciseLib::getFeedbackText($comnt); |
|
|
|
|
|
|
3865
|
|
|
} |
|
3866
|
|
|
} |
|
3867
|
|
|
|
|
3868
|
|
|
if ($show_results) { |
|
3869
|
|
|
$score = array( |
|
3870
|
|
|
'result' => self::show_score( |
|
3871
|
|
|
$my_total_score, |
|
3872
|
|
|
$my_total_weight, |
|
3873
|
|
|
false, |
|
3874
|
|
|
true |
|
3875
|
|
|
), |
|
3876
|
|
|
'pass' => $my_total_score >= $my_total_weight ? true : false, |
|
3877
|
|
|
'score' => $my_total_score, |
|
3878
|
|
|
'weight' => $my_total_weight, |
|
3879
|
|
|
'comments' => $comnt, |
|
3880
|
|
|
); |
|
3881
|
|
|
} else { |
|
3882
|
|
|
$score = array(); |
|
3883
|
|
|
} |
|
3884
|
|
|
|
|
3885
|
|
View Code Duplication |
if (in_array($objQuestionTmp->type, [FREE_ANSWER, ORAL_EXPRESSION])) { |
|
3886
|
|
|
$check = $objQuestionTmp->isQuestionWaitingReview($score); |
|
3887
|
|
|
if ($check === false) { |
|
3888
|
|
|
$countPendingQuestions++; |
|
3889
|
|
|
} |
|
3890
|
|
|
} |
|
3891
|
|
|
|
|
3892
|
|
|
$contents = ob_get_clean(); |
|
3893
|
|
|
$question_content = ''; |
|
3894
|
|
|
if ($show_results) { |
|
3895
|
|
|
$question_content = '<div class="question_row_answer">'; |
|
3896
|
|
|
// Shows question title an description |
|
3897
|
|
|
$question_content .= $objQuestionTmp->return_header( |
|
3898
|
|
|
null, |
|
3899
|
|
|
$counter, |
|
3900
|
|
|
$score |
|
3901
|
|
|
); |
|
3902
|
|
|
} |
|
3903
|
|
|
$counter++; |
|
3904
|
|
|
$question_content .= $contents; |
|
3905
|
|
|
if ($show_results) { |
|
3906
|
|
|
$question_content .= '</div>'; |
|
3907
|
|
|
} |
|
3908
|
|
|
|
|
3909
|
|
|
$exercise_content .= $question_content; |
|
3910
|
|
|
} // end foreach() block that loops over all questions |
|
3911
|
|
|
} |
|
3912
|
|
|
|
|
3913
|
|
|
$total_score_text = null; |
|
3914
|
|
|
if ($show_results || $show_only_score) { |
|
3915
|
|
|
$total_score_text .= '<div class="question_row_score">'; |
|
3916
|
|
|
$total_score_text .= self::getTotalScoreRibbon( |
|
3917
|
|
|
$objExercise, |
|
3918
|
|
|
$total_score, |
|
3919
|
|
|
$total_weight, |
|
3920
|
|
|
true, |
|
3921
|
|
|
$countPendingQuestions |
|
3922
|
|
|
); |
|
3923
|
|
|
$total_score_text .= '</div>'; |
|
3924
|
|
|
} |
|
3925
|
|
|
|
|
3926
|
|
View Code Duplication |
if (!empty($category_list) && ($show_results || $show_only_score)) { |
|
3927
|
|
|
// Adding total |
|
3928
|
|
|
$category_list['total'] = array( |
|
3929
|
|
|
'score' => $total_score, |
|
3930
|
|
|
'total' => $total_weight |
|
3931
|
|
|
); |
|
3932
|
|
|
echo TestCategory::get_stats_table_by_attempt( |
|
3933
|
|
|
$objExercise->id, |
|
3934
|
|
|
$category_list |
|
3935
|
|
|
); |
|
3936
|
|
|
} |
|
3937
|
|
|
|
|
3938
|
|
|
if ($show_all_but_expected_answer) { |
|
3939
|
|
|
$exercise_content .= "<div class='normal-message'>".get_lang( |
|
3940
|
|
|
"ExerciseWithFeedbackWithoutCorrectionComment" |
|
3941
|
|
|
)."</div>"; |
|
3942
|
|
|
} |
|
3943
|
|
|
// Remove audio auto play from questions on results page - refs BT#7939 |
|
3944
|
|
|
$exercise_content = preg_replace( |
|
3945
|
|
|
['/autoplay[\=\".+\"]+/', '/autostart[\=\".+\"]+/'], |
|
3946
|
|
|
'', |
|
3947
|
|
|
$exercise_content |
|
3948
|
|
|
); |
|
3949
|
|
|
|
|
3950
|
|
|
echo $total_score_text; |
|
3951
|
|
|
echo $exercise_content; |
|
3952
|
|
|
|
|
3953
|
|
|
if (!$show_only_score) { |
|
3954
|
|
|
echo $total_score_text; |
|
3955
|
|
|
} |
|
3956
|
|
|
|
|
3957
|
|
|
if (!empty($remainingMessage)) { |
|
3958
|
|
|
echo Display::return_message($remainingMessage, 'normal', false); |
|
3959
|
|
|
} |
|
3960
|
|
|
|
|
3961
|
|
|
if ($save_user_result) { |
|
3962
|
|
|
// Tracking of results |
|
3963
|
|
|
if ($exercise_stat_info) { |
|
3964
|
|
|
$learnpath_id = $exercise_stat_info['orig_lp_id']; |
|
3965
|
|
|
$learnpath_item_id = $exercise_stat_info['orig_lp_item_id']; |
|
3966
|
|
|
$learnpath_item_view_id = $exercise_stat_info['orig_lp_item_view_id']; |
|
3967
|
|
|
|
|
3968
|
|
|
if (api_is_allowed_to_session_edit()) { |
|
3969
|
|
|
Event::update_event_exercise( |
|
3970
|
|
|
$exercise_stat_info['exe_id'], |
|
3971
|
|
|
$objExercise->selectId(), |
|
3972
|
|
|
$total_score, |
|
3973
|
|
|
$total_weight, |
|
3974
|
|
|
api_get_session_id(), |
|
3975
|
|
|
$learnpath_id, |
|
3976
|
|
|
$learnpath_item_id, |
|
3977
|
|
|
$learnpath_item_view_id, |
|
3978
|
|
|
$exercise_stat_info['exe_duration'], |
|
3979
|
|
|
$question_list, |
|
3980
|
|
|
'', |
|
3981
|
|
|
array() |
|
3982
|
|
|
); |
|
3983
|
|
|
} |
|
3984
|
|
|
} |
|
3985
|
|
|
|
|
3986
|
|
|
// Send notification at the end |
|
3987
|
|
|
if (!api_is_allowed_to_edit(null, true) && |
|
3988
|
|
|
!api_is_excluded_user_type() |
|
3989
|
|
|
) { |
|
3990
|
|
|
$objExercise->send_mail_notification_for_exam( |
|
3991
|
|
|
'end', |
|
3992
|
|
|
$question_list_answers, |
|
3993
|
|
|
$origin, |
|
3994
|
|
|
$exe_id, |
|
3995
|
|
|
$total_score, |
|
3996
|
|
|
$total_weight |
|
3997
|
|
|
); |
|
3998
|
|
|
} |
|
3999
|
|
|
} |
|
4000
|
|
|
} |
|
4001
|
|
|
|
|
4002
|
|
|
/** |
|
4003
|
|
|
* @param string $class |
|
4004
|
|
|
* @param string $scoreLabel |
|
4005
|
|
|
* @param string $result |
|
4006
|
|
|
* |
|
4007
|
|
|
* @return string |
|
4008
|
|
|
*/ |
|
4009
|
|
|
public static function getQuestionRibbon($class, $scoreLabel, $result) |
|
4010
|
|
|
{ |
|
4011
|
|
|
return '<div class="ribbon"> |
|
4012
|
|
|
<div class="rib rib-'.$class.'"> |
|
4013
|
|
|
<h3>'.$scoreLabel.'</h3> |
|
4014
|
|
|
</div> |
|
4015
|
|
|
<h4>'.get_lang('Score').': '.$result.'</h4> |
|
4016
|
|
|
</div>' |
|
4017
|
|
|
; |
|
4018
|
|
|
} |
|
4019
|
|
|
|
|
4020
|
|
|
/** |
|
4021
|
|
|
* @param Exercise $objExercise |
|
4022
|
|
|
* @param float $score |
|
4023
|
|
|
* @param float $weight |
|
4024
|
|
|
* @param bool $checkPassPercentage |
|
4025
|
|
|
* @param int $countPendingQuestions |
|
4026
|
|
|
* @return string |
|
4027
|
|
|
*/ |
|
4028
|
|
|
public static function getTotalScoreRibbon( |
|
4029
|
|
|
$objExercise, |
|
4030
|
|
|
$score, |
|
4031
|
|
|
$weight, |
|
4032
|
|
|
$checkPassPercentage = false, |
|
4033
|
|
|
$countPendingQuestions = 0 |
|
4034
|
|
|
) { |
|
4035
|
|
|
$passPercentage = $objExercise->selectPassPercentage(); |
|
4036
|
|
|
$ribbon = '<div class="title-score">'; |
|
4037
|
|
|
if ($checkPassPercentage) { |
|
4038
|
|
|
$isSuccess = self::isSuccessExerciseResult( |
|
4039
|
|
|
$score, |
|
4040
|
|
|
$weight, |
|
4041
|
|
|
$passPercentage |
|
4042
|
|
|
); |
|
4043
|
|
|
// Color the final test score if pass_percentage activated |
|
4044
|
|
|
$class = ''; |
|
4045
|
|
|
if (self::isPassPercentageEnabled($passPercentage)) { |
|
4046
|
|
|
if ($isSuccess) { |
|
4047
|
|
|
$class = ' ribbon-total-success'; |
|
4048
|
|
|
} else { |
|
4049
|
|
|
$class = ' ribbon-total-error'; |
|
4050
|
|
|
} |
|
4051
|
|
|
} |
|
4052
|
|
|
$ribbon .= '<div class="total '.$class.'">'; |
|
4053
|
|
|
} else { |
|
4054
|
|
|
$ribbon .= '<div class="total">'; |
|
4055
|
|
|
} |
|
4056
|
|
|
$ribbon .= '<h3>'.get_lang('YourTotalScore').": "; |
|
4057
|
|
|
$ribbon .= self::show_score($score, $weight, false, true); |
|
4058
|
|
|
$ribbon .= '</h3>'; |
|
4059
|
|
|
$ribbon .= '</div>'; |
|
4060
|
|
|
if ($checkPassPercentage) { |
|
4061
|
|
|
$ribbon .= self::showSuccessMessage( |
|
4062
|
|
|
$score, |
|
4063
|
|
|
$weight, |
|
4064
|
|
|
$passPercentage |
|
4065
|
|
|
); |
|
4066
|
|
|
} |
|
4067
|
|
|
$ribbon .= '</div>'; |
|
4068
|
|
|
|
|
4069
|
|
|
if (!empty($countPendingQuestions)) { |
|
4070
|
|
|
$ribbon .= '<br />'; |
|
4071
|
|
|
$ribbon .= Display::return_message( |
|
4072
|
|
|
sprintf( |
|
4073
|
|
|
get_lang('TempScoreXQuestionsNotCorrectedYet'), |
|
4074
|
|
|
$countPendingQuestions |
|
4075
|
|
|
), |
|
4076
|
|
|
'warning' |
|
4077
|
|
|
); |
|
4078
|
|
|
} |
|
4079
|
|
|
|
|
4080
|
|
|
return $ribbon; |
|
4081
|
|
|
} |
|
4082
|
|
|
|
|
4083
|
|
|
/** |
|
4084
|
|
|
* @param int $countLetter |
|
4085
|
|
|
* @return mixed |
|
4086
|
|
|
*/ |
|
4087
|
|
|
public static function detectInputAppropriateClass($countLetter) |
|
4088
|
|
|
{ |
|
4089
|
|
|
$limits = array( |
|
4090
|
|
|
0 => 'input-mini', |
|
4091
|
|
|
10 => 'input-mini', |
|
4092
|
|
|
15 => 'input-medium', |
|
4093
|
|
|
20 => 'input-xlarge', |
|
4094
|
|
|
40 => 'input-xlarge', |
|
4095
|
|
|
60 => 'input-xxlarge', |
|
4096
|
|
|
100 => 'input-xxlarge', |
|
4097
|
|
|
200 => 'input-xxlarge', |
|
4098
|
|
|
); |
|
4099
|
|
|
|
|
4100
|
|
|
foreach ($limits as $size => $item) { |
|
4101
|
|
|
if ($countLetter <= $size) { |
|
4102
|
|
|
return $item; |
|
4103
|
|
|
} |
|
4104
|
|
|
} |
|
4105
|
|
|
return $limits[0]; |
|
4106
|
|
|
} |
|
4107
|
|
|
|
|
4108
|
|
|
/** |
|
4109
|
|
|
* @param int $senderId |
|
4110
|
|
|
* @param array $course_info |
|
4111
|
|
|
* @param string $test |
|
4112
|
|
|
* @param string $url |
|
4113
|
|
|
* |
|
4114
|
|
|
* @return string |
|
4115
|
|
|
*/ |
|
4116
|
|
|
public static function getEmailNotification($senderId, $course_info, $test, $url) |
|
4117
|
|
|
{ |
|
4118
|
|
|
$teacher_info = api_get_user_info($senderId); |
|
4119
|
|
|
$from_name = api_get_person_name( |
|
4120
|
|
|
$teacher_info['firstname'], |
|
4121
|
|
|
$teacher_info['lastname'], |
|
4122
|
|
|
null, |
|
4123
|
|
|
PERSON_NAME_EMAIL_ADDRESS |
|
4124
|
|
|
); |
|
4125
|
|
|
|
|
4126
|
|
|
$message = '<p>'.get_lang('DearStudentEmailIntroduction').'</p><p>'.get_lang('AttemptVCC'); |
|
4127
|
|
|
$message .= '<h3>'.get_lang('CourseName').'</h3><p>'.Security::remove_XSS($course_info['name']).''; |
|
4128
|
|
|
$message .= '<h3>'.get_lang('Exercise').'</h3><p>'.Security::remove_XSS($test); |
|
4129
|
|
|
$message .= '<p>'.get_lang('ClickLinkToViewComment').' <br /><a href="#url#">#url#</a><br />'; |
|
4130
|
|
|
$message .= '<p>'.get_lang('Regards').'</p>'; |
|
4131
|
|
|
$message .= $from_name; |
|
4132
|
|
|
$message = str_replace("#test#", Security::remove_XSS($test), $message); |
|
4133
|
|
|
$message = str_replace("#url#", $url, $message); |
|
4134
|
|
|
|
|
4135
|
|
|
return $message; |
|
4136
|
|
|
} |
|
4137
|
|
|
|
|
4138
|
|
|
/** |
|
4139
|
|
|
* @return string |
|
4140
|
|
|
*/ |
|
4141
|
|
|
public static function getNotCorrectedYetText() |
|
4142
|
|
|
{ |
|
4143
|
|
|
return Display::return_message(get_lang('notCorrectedYet'), 'warning'); |
|
4144
|
|
|
} |
|
4145
|
|
|
|
|
4146
|
|
|
/** |
|
4147
|
|
|
* @param string $message |
|
4148
|
|
|
* @return string |
|
4149
|
|
|
*/ |
|
4150
|
|
|
public static function getFeedbackText($message) |
|
4151
|
|
|
{ |
|
4152
|
|
|
// Old style |
|
4153
|
|
|
//return '<div id="question_feedback">'.$message.'</div>'; |
|
4154
|
|
|
return Display::return_message($message, 'warning', false); |
|
4155
|
|
|
} |
|
4156
|
|
|
} |
|
4157
|
|
|
|
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.
If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.