Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php
/**
* The main file for short_answer.
*
* Short answer is structurally similar to long answer. However, the module
* mechanism makes it very difficult for these two modules (either one of
* which may be disabled) to effectively share code.
* @file
*/
/**
* Implements hook_help().
*/
function short_answer_help($path, $args) {
if ($path == 'admin/help#short_answer') {
return t('This module provides a short answer question type for Quiz.');
}
}
/**
* Implements hook_permission().
*/
function short_answer_permission() {
return array(
'use regex for short answer' => array(
'title' => t('use regex for short answer'),
'description' => t('Use PHP "regular expressions" the advanced option for automated response evaluation.'),
'restrict access' => TRUE,
),
);
}
/**
* Implements hook_menu().
*/
function short_answer_menu() {
$items['admin/quiz/reports/score-short-answer'] = array(
'title' => 'Score short answer questions',
'description' => 'Score the answers from quizzes that use short answer questions.',
'page callback' => 'short_answer_view_unscored',
'access arguments' => array('score any quiz', 'score own quiz', 'score taken quiz answer'),
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
'access callback' => 'quiz_access_multi_or',
'type' => MENU_NORMAL_ITEM,
'file' => 'short_answer.admin.inc',
);
// Pass vid and rid to this path.
$items['admin/quiz/reports/score-short-answer/%/%'] = array(
'title' => 'Score short answer response',
'description' => 'Score a response to a short answer question.',
'page callback' => 'short_answer_edit_score',
'page arguments' => array(4, 5),
'type' => MENU_NORMAL_ITEM,
'access arguments' => array(4, 5),
'access callback' => 'quiz_question_access_to_score',
'file' => 'short_answer.admin.inc'
);
return $items;
}
/**
* Implements hook_quiz_question_info().
*/
function short_answer_quiz_question_info() {
return array(
'short_answer' => array(
'name' => t('Short answer question'),
'description' => t('Quiz questions that allow a user to enter a line of text.'),
'question provider' => 'ShortAnswerQuestion',
'response provider' => 'ShortAnswerResponse',
'module' => 'quiz_question', // All wrapper functions are in that module.
),
);
}
/**
* Implements hook_config().
*/
function short_answer_config() {
return FALSE; // No config options available for the short answer question type
}
/**
* Implements hook_theme().
*/
function short_answer_theme($existing, $type, $theme, $path) {
$module_path = drupal_get_path('module', 'short_answer');
return array(
'short_answer_view_unscored' => array(
'variables' => array('unscored' => array()),
'path' => $module_path . '/theme',
'file' => 'short_answer.theme.inc',
),
'short_answer_response_form' => array(
'render element' => 'form',
'path' => $module_path . '/theme',
'file' => 'short_answer.theme.inc',
),
'short_answer_user_answer' => array(
'variables' => array('answer' => NULL, 'correct' => NULL),
'path' => $module_path . '/theme',
'file' => 'short_answer.theme.inc',
),
'short_answer_answering_form' => array(
'render element' => 'form',
'path' => $module_path . '/theme',
'template' => 'short-answer-answering-form',
),
);
}
/**
* Set a score for a short answer question.
*
* This stores a score for a short answer question and marks that question as having been evaluated.
* The function updates all of the necessary data sources so that the individual answer results should be
* reflected in the total scoring table.
*
* @param $quiz
* Quiz node.
* @param $nid
* Node ID of question.
* @param $vid
* Version ID of question.
* @param $rid
* Result ID for the quiz results.
* @param $score
* The numeric score to assign the result.
* @param $update_total
* Shall the total score for a quiz be updated?
*
* @return int
* Number of scores adjusted. If a change was made, this should be 1.
*/
function short_answer_score_an_answer($values, $update_total = TRUE) {
extract($values);
// When we set the score we make sure that the max score in the quiz the question belongs to is considered
$question_max_score = db_query('SELECT max_score FROM {quiz_question_properties} WHERE nid = :nid AND vid = :vid', array(':nid' => $nid, ':vid' => $vid))->FetchField();
$quiz_max_score = db_query('SELECT max_score FROM {quiz_node_relationship} WHERE parent_vid = :pvid AND child_vid = :cvid', array(':pvid' => $quiz->vid, ':cvid' => $vid))->fetchField();
$changed = db_update('quiz_short_answer_user_answers')
->fields(array(
'score' => $score * $question_max_score / $quiz_max_score,
'answer_feedback' => empty($answer_feedback) ? '' : $answer_feedback
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
))
->condition('question_nid', $nid)
->condition('question_vid', $vid)
->condition('result_id', $rid)
->execute();
// Now the short answer user data has been updated. We also need to update the data in the quiz tables
if ($changed > 0) {
$max = db_query('SELECT max_score FROM {quiz_question_properties} WHERE vid = :vid', array(':vid' => $vid))->fetchField();
if ($max <= 0) {
$is_correct = 0;
$points_awarded = 0;
}
else {
$is_correct = ($score / $max > 0.5) ? 1 : 0;
$points_awarded = $score;
}
db_update('quiz_node_results_answers')
->fields(array(
'points_awarded' => $points_awarded,
'is_correct' => $is_correct,
))
->condition('question_vid', $vid)
->condition('result_id', $rid)
->execute();
// Third, we update the main quiz results table
if ($update_total) {
quiz_update_total_score($quiz, $rid);
}
}
return $changed;
}
/**
* Validate the result report for short answer
*/
function short_answer_report_validate($values, $form_key) {
// Check to make sure that entered score is not higher than max allowed score.
if (!_quiz_is_int($values['score'], 0, (int) $values['max_score'])) {
form_set_error($form_key . '][score', t('The score needs to be a number between 0 and @max', array('@max' => (int) $values['max_score'])));
}
}
/**
* Submit the result report for short answer
*/
function short_answer_report_submit($values) {
short_answer_score_an_answer($values, FALSE);
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
}
/**
* Get the answer for a question.
*
* This stores a score for a short answer question and marks that question as having been evaluated.
* @param $question_nid
* Node ID of question.
* @param $question_vid
* Version ID of question.
* @param $result_id
* Result ID for the quiz results.
*
* @return Assoc array
* An array if successful, or FALSE if no result could be found. The array contains the following properties:
* <code>
* answer_id; // The answer ID
* answer; // The full text of the answer
* is_evaluated; // 0 if the question has not been evaluated, 1 if it has
* score; // The score the evaluator gave the user; this should be 0 if is_evaluated is 0.
* question_vid
* question_nid
* result_id
* </code>
*/
function short_answer_get_answer($question_nid, $question_vid, $result_id) {
$results = db_query('SELECT sa.answer_id, sa.answer, sa.is_evaluated, sa.score, sa.question_vid, sa.question_nid, sa.result_id, sa.answer_feedback, rel.max_score AS rel_max_score
FROM {quiz_short_answer_user_answers} sa
JOIN {quiz_node_results} qnr ON (sa.result_id = qnr.result_id)
JOIN {quiz_node_relationship} rel ON (qnr.vid = rel.parent_vid AND rel.child_vid = sa.question_vid)
WHERE sa.question_nid = :qnid AND sa.question_vid = :qvid AND sa.result_id = :rid', array(':qnid' => $question_nid, ':qvid' => $question_vid, ':rid' => $result_id))->fetchAssoc();
return $results ? $results : FALSE;
}