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