Added function for matching/checking question grades on quiz import.
[moodle.git] / question / format.php
CommitLineData
aca318e1 1<?php // $Id$
2
3////////////////////////////////////////////////////////////////////
4/// format.php - Default format class for file imports/exports. //
5/// //
6/// Doesn't do everything on it's own -- it needs to be extended. //
7////////////////////////////////////////////////////////////////////
8
9// Included by import.php and export.php
10
f5565b69 11class qformat_default {
aca318e1 12
13 var $displayerrors = true;
14 var $category = NULL;
15 var $course = NULL;
16 var $questionids = array();
17
18// functions to indicate import/export functionality
19// override to return true if implemented
20
21 function provide_import() {
22 return false;
23 }
24
25 function provide_export() {
26 return false;
27 }
28
29/// Importing functions
30
31 function importpreprocess($category, $course=NULL ) {
32 /// Does any pre-processing that may be desired
33
34 $this->category = $category; // Important
35 $this->course = $course;
36
37 return true;
38 }
39
40 function importprocess($filename) {
41 /// Processes a given file. There's probably little need to change this
42
43 if (! $lines = $this->readdata($filename)) {
1e3d6fd8 44 notify( get_string('cannotread','quiz') );
aca318e1 45 return false;
46 }
47
48 if (! $questions = $this->readquestions($lines)) { // Extract all the questions
1e3d6fd8 49 notify( get_string('noquestionsinfile','quiz') );
aca318e1 50 return false;
51 }
52
1e3d6fd8 53 notify( get_string('importingquestions','quiz',count($questions)) );
aca318e1 54
55 $count = 0;
56
57 foreach ($questions as $question) { // Process and store each question
58 $count++;
59
60 echo "<hr /><p><b>$count</b>. ".stripslashes($question->questiontext)."</p>";
61
62 $question->category = $this->category->id;
63 $question->stamp = make_unique_id_code(); // Set the unique code (not to be changed)
64 $question->version = 1; // Original version of this question
65
062f1125 66 if (!$question->id = insert_record("question", $question)) {
1e3d6fd8 67 error( get_string('cannotinsert','quiz') );
aca318e1 68 }
69
70 $this->questionids[] = $question->id;
71
72 // Now to save all the answers and type-specific options
73
74 global $QTYPES;
75 $result = $QTYPES[$question->qtype]
76 ->save_question_options($question);
77
78 if (!empty($result->error)) {
79 notify($result->error);
80 return false;
81 }
82
83 if (!empty($result->notice)) {
84 notify($result->notice);
85 return true;
86 }
87 }
88 return true;
89 }
90
91
92 function readdata($filename) {
93 /// Returns complete file with an array, one item per line
94
95 if (is_readable($filename)) {
96 $filearray = file($filename);
97
98 /// Check for Macintosh OS line returns (ie file on one line), and fix
99 if (ereg("\r", $filearray[0]) AND !ereg("\n", $filearray[0])) {
100 return explode("\r", $filearray[0]);
101 } else {
102 return $filearray;
103 }
104 }
105 return false;
106 }
107
108 function readquestions($lines) {
109 /// Parses an array of lines into an array of questions,
110 /// where each item is a question object as defined by
111 /// readquestion(). Questions are defined as anything
112 /// between blank lines.
113
114 $questions = array();
115 $currentquestion = array();
116
117 foreach ($lines as $line) {
118 $line = trim($line);
119 if (empty($line)) {
120 if (!empty($currentquestion)) {
121 if ($question = $this->readquestion($currentquestion)) {
122 $questions[] = $question;
123 }
124 $currentquestion = array();
125 }
126 } else {
127 $currentquestion[] = $line;
128 }
129 }
130
131 if (!empty($currentquestion)) { // There may be a final question
132 if ($question = $this->readquestion($currentquestion)) {
133 $questions[] = $question;
134 }
135 }
136
137 return $questions;
138 }
139
140
141 function defaultquestion() {
142 // returns an "empty" question
143 // Somewhere to specify question parameters that are not handled
144 // by import but are required db fields.
145 // This should not be overridden.
146 $question = new stdClass();
147 $question->shuffleanswers = 0;
148 $question->defaultgrade = 1;
149 $question->image = "";
150 $question->usecase = 0;
151 $question->multiplier = array();
152
153 return $question;
154 }
155
156 function readquestion($lines) {
157 /// Given an array of lines known to define a question in
158 /// this format, this function converts it into a question
159 /// object suitable for processing and insertion into Moodle.
160
1e3d6fd8 161 $formatnotimplemented = get_string( 'formatnotimplemented','quiz' );
162 echo "<p>$formatnotimplemented</p>";
aca318e1 163
164 return NULL;
165 }
166
167
168 function importpostprocess() {
169 /// Does any post-processing that may be desired
170 /// Argument is a simple array of question ids that
171 /// have just been added.
172
173 return true;
174 }
175
176// Export functions
177
178
179 function export_file_extension() {
180 /// return the files extension appropriate for this type
181 /// override if you don't want .txt
182
183 return ".txt";
184 }
185
186 function exportpreprocess($category, $course) {
187 /// Does any pre-processing that may be desired
188
189 $this->category = $category; // Important
190 $this->course = $course; // As is this!
191
192 return true;
193 }
194
195 function presave_process( $content ) {
196 /// enables any processing to be done on the content
197 /// just prior to the file being saved
198 /// default is to do nothing
199
200 return $content;
201 }
202
203 function exportprocess($filename) {
204 /// Exports a given category. There's probably little need to change this
205
206 global $CFG;
207
208 // create a directory for the exports (if not already existing)
209 $dirname = get_string("exportfilename","quiz");
210 $courseid = $this->course->id;
211 $path = $CFG->dataroot.'/'.$courseid.'/'.$dirname;
212 if (!is_dir($path)) {
213 if (!mkdir($path, $CFG->directorypermissions)) {
1e3d6fd8 214 error( get_string('cannotcreatepath','quiz',$path) );
aca318e1 215 }
216 }
217
218 // get the questions (from database) in this category
219 // only get q's with no parents (no cloze subquestions specifically)
220 $questions = get_questions_category( $this->category, true );
221
1e3d6fd8 222 notify( get_string('exportingquestions','quiz') );
aca318e1 223 if (!count($questions)) {
1e3d6fd8 224 notify( get_string('noquestions','quiz') );
225 return false;
aca318e1 226 }
227 $count = 0;
228
229 // results are first written into string (and then to a file)
230 // so create/initialize the string here
231 $expout = "";
232
233 // iterate through questions
234 foreach($questions as $question) {
235 $count++;
236 $qtype = $question->qtype;
237 // ignore random questiond
238 if ($qtype!=RANDOM) {
239 echo "<hr /><p><b>$count</b>. ".stripslashes($question->questiontext)."</p>";
240 $expout .= $this->writequestion( $question ) . "\n";
241 }
242 }
243
244 // final pre-process on exported data
245 $expout = $this->presave_process( $expout );
246
247 // write file
248 $filepath = $path."/".$filename . $this->export_file_extension();
249 if (!$fh=fopen($filepath,"w")) {
1e3d6fd8 250 error( get_string('cannotopen','quiz',$filepath) );
aca318e1 251 }
252 if (!fwrite($fh, $expout)) {
1e3d6fd8 253 error( get_string('cannotwrite','quiz',$filepath) );
aca318e1 254 }
255 fclose($fh);
256
257 return true;
258 }
259
260 function exportpostprocess() {
261 /// Does any post-processing that may be desired
262
263 return true;
264 }
265
266 function writequestion($question) {
267 /// Turns a question object into textual output in the given format
268 /// must be overidden
269
1e3d6fd8 270 // if not overidden, then this is an error.
271 $formatnotimplemented = get_string( 'formatnotimplemented','quiz' );
272 echo "<p>$formatnotimplemented</p>";
aca318e1 273
274 return NULL;
275 }
276
277}
278
279?>