Output was missing utf8 meta tag.
[moodle-linuxchix.git] / question / backuplib.php
blob00b2fc2542cf49b8c635cfce9fe72b4271b39b02
1 <?php //$Id$
2 //This php script contains all the stuff to backup questions
4 //This is the "graphical" structure of the question database:
5 //To see, put your terminal to 160cc
7 // The following holds student-independent information about the questions
8 //
9 // question_categories
10 // (CL,pk->id)
11 // |
12 // |
13 // |.......................................
14 // | .
15 // | .
16 // | -------question_datasets------ .
17 // | | (CL,pk->id,fk->question, | .
18 // | | fk->dataset_definition) | .
19 // | | | .
20 // | | | .
21 // | | | .
22 // | | question_dataset_definitions
23 // | | (CL,pk->id,fk->category)
24 // question |
25 // (CL,pk->id,fk->category,files) |
26 // | question_dataset_items
27 // | (CL,pk->id,fk->definition)
28 // | question_rqp_type
29 // | (SL,pk->id)
30 // | |
31 // -------------------------------------------------------------------------------------------------------------- |
32 // | | | | | | | question_rqp
33 // | | | | | | |--(CL,pk->id,fk->question)
34 // | | | | question_calculated | |
35 // question_truefalse | question_multichoice | (CL,pl->id,fk->question) | |
36 // (CL,pk->id,fk->question) | (CL,pk->id,fk->question) | . | | question_randomsamatch
37 // . | . | . | |--(CL,pk->id,fk->question)
38 // . question_shortanswer . question_numerical . question_multianswer. |
39 // . (CL,pk->id,fk->question) . (CL,pk->id,fk->question) . (CL,pk->id,fk->question) |
40 // . . . . . . | question_match
41 // . . . . . . |--(CL,pk->id,fk->question)
42 // . . . . . . | .
43 // . . . . . . | .
44 // . . . . . . | .
45 // . . . . . . | question_match_sub
46 // ........................................................................................ |--(CL,pk->id,fk->question)
47 // . |
48 // . |
49 // . | question_numerical_units
50 // question_answers |--(CL,pk->id,fk->question)
51 // (CL,pk->id,fk->question)----------------------------------------------------------
54 // The following holds the information about student interaction with the questions
56 // question_sessions
57 // (UL,pk->id,fk->attempt,question)
58 // .
59 // .
60 // question_states
61 // (UL,pk->id,fk->attempt,question)
62 // |
63 // question_rqp_states
64 // (UL,pk->id,fk->stateid)
66 // Meaning: pk->primary key field of the table
67 // fk->foreign key to link with parent
68 // nt->nested field (recursive data)
69 // SL->site level info
70 // CL->course level info
71 // UL->user level info
72 // files->table may have files
74 //-----------------------------------------------------------
76 require_once("$CFG->libdir/questionlib.php");
78 function backup_question_categories($bf,$preferences) {
80 global $CFG;
82 $status = true;
84 //First, we get the used categories from backup_ids
85 $categories = question_category_ids_by_backup ($preferences->backup_unique_code);
87 //If we've categories
88 if ($categories) {
89 //Write start tag
90 $status = fwrite($bf,start_tag("QUESTION_CATEGORIES",2,true));
91 //Iterate over each category
92 foreach ($categories as $cat) {
93 //Start category
94 $status = fwrite ($bf,start_tag("QUESTION_CATEGORY",3,true));
95 //Get category data from question_categories
96 $category = get_record ("question_categories","id",$cat->old_id);
97 //Print category contents
98 fwrite($bf,full_tag("ID",4,false,$category->id));
99 fwrite($bf,full_tag("NAME",4,false,$category->name));
100 fwrite($bf,full_tag("INFO",4,false,$category->info));
101 fwrite($bf,full_tag("PUBLISH",4,false,$category->publish));
102 fwrite($bf,full_tag("STAMP",4,false,$category->stamp));
103 fwrite($bf,full_tag("PARENT",4,false,$category->parent));
104 fwrite($bf,full_tag("SORTORDER",4,false,$category->sortorder));
105 //Now, backup their questions
106 $status = backup_question($bf,$preferences,$category->id);
107 //End category
108 $status = fwrite ($bf,end_tag("QUESTION_CATEGORY",3,true));
110 //Write end tag
111 $status = fwrite ($bf,end_tag("QUESTION_CATEGORIES",2,true));
114 return $status;
117 //This function backups all the questions in selected category and their
118 //asociated data
119 function backup_question($bf,$preferences,$category, $level = 4) {
121 global $CFG, $QTYPES;
123 $status = true;
125 // We'll fetch the questions sorted by parent so that questions with no parents
126 // (these are the ones which could be parents themselves) are backed up first. This
127 // is important for the recoding of the parent field during the restore process
128 $questions = get_records("question","category",$category,"parent ASC, id");
129 //If there are questions
130 if ($questions) {
131 //Write start tag
132 $status = fwrite ($bf,start_tag("QUESTIONS",$level,true));
133 $counter = 0;
134 //Iterate over each question
135 foreach ($questions as $question) {
136 //Start question
137 $status = fwrite ($bf,start_tag("QUESTION",$level + 1,true));
138 //Print question contents
139 fwrite ($bf,full_tag("ID",$level + 2,false,$question->id));
140 fwrite ($bf,full_tag("PARENT",$level + 2,false,$question->parent));
141 fwrite ($bf,full_tag("NAME",$level + 2,false,$question->name));
142 fwrite ($bf,full_tag("QUESTIONTEXT",$level + 2,false,$question->questiontext));
143 fwrite ($bf,full_tag("QUESTIONTEXTFORMAT",$level + 2,false,$question->questiontextformat));
144 fwrite ($bf,full_tag("IMAGE",$level + 2,false,$question->image));
145 fwrite ($bf,full_tag("GENERALFEEDBACK",$level + 2,false,$question->generalfeedback));
146 fwrite ($bf,full_tag("DEFAULTGRADE",$level + 2,false,$question->defaultgrade));
147 fwrite ($bf,full_tag("PENALTY",$level + 2,false,$question->penalty));
148 fwrite ($bf,full_tag("QTYPE",$level + 2,false,$question->qtype));
149 fwrite ($bf,full_tag("LENGTH",$level + 2,false,$question->length));
150 fwrite ($bf,full_tag("STAMP",$level + 2,false,$question->stamp));
151 fwrite ($bf,full_tag("VERSION",$level + 2,false,$question->version));
152 fwrite ($bf,full_tag("HIDDEN",$level + 2,false,$question->hidden));
153 // Backup question type specific data
154 $status = $QTYPES[$question->qtype]->backup($bf,$preferences,$question->id, $level + 2);
155 //End question
156 $status = fwrite ($bf,end_tag("QUESTION",$level + 1,true));
157 //Do some output
158 $counter++;
159 if ($counter % 10 == 0) {
160 echo ".";
161 if ($counter % 200 == 0) {
162 echo "<br />";
164 backup_flush(300);
167 //Write end tag
168 $status = fwrite ($bf,end_tag("QUESTIONS",$level,true));
170 return $status;
173 //This function backups the answers data in some question types
174 //(truefalse, shortanswer,multichoice,numerical,calculated)
175 function question_backup_answers($bf,$preferences,$question, $level = 6) {
177 global $CFG;
179 $status = true;
181 $answers = get_records("question_answers","question",$question,"id");
182 //If there are answers
183 if ($answers) {
184 $status = fwrite ($bf,start_tag("ANSWERS",$level,true));
185 //Iterate over each answer
186 foreach ($answers as $answer) {
187 $status = fwrite ($bf,start_tag("ANSWER",$level + 1,true));
188 //Print answer contents
189 fwrite ($bf,full_tag("ID",$level + 2,false,$answer->id));
190 fwrite ($bf,full_tag("ANSWER_TEXT",$level + 2,false,$answer->answer));
191 fwrite ($bf,full_tag("FRACTION",$level + 2,false,$answer->fraction));
192 fwrite ($bf,full_tag("FEEDBACK",$level + 2,false,$answer->feedback));
193 $status = fwrite ($bf,end_tag("ANSWER",$level + 1,true));
195 $status = fwrite ($bf,end_tag("ANSWERS",$level,true));
197 return $status;
200 //This function backups question_numerical_units from different question types
201 function question_backup_numerical_units($bf,$preferences,$question,$level=7) {
203 global $CFG;
205 $status = true;
207 $numerical_units = get_records("question_numerical_units","question",$question,"id");
208 //If there are numericals_units
209 if ($numerical_units) {
210 $status = fwrite ($bf,start_tag("NUMERICAL_UNITS",$level,true));
211 //Iterate over each numerical_unit
212 foreach ($numerical_units as $numerical_unit) {
213 $status = fwrite ($bf,start_tag("NUMERICAL_UNIT",$level+1,true));
214 //Print numerical_unit contents
215 fwrite ($bf,full_tag("MULTIPLIER",$level+2,false,$numerical_unit->multiplier));
216 fwrite ($bf,full_tag("UNIT",$level+2,false,$numerical_unit->unit));
217 //Now backup numerical_units
218 $status = fwrite ($bf,end_tag("NUMERICAL_UNIT",$level+1,true));
220 $status = fwrite ($bf,end_tag("NUMERICAL_UNITS",$level,true));
223 return $status;
227 //This function backups dataset_definitions (via question_datasets) from different question types
228 function question_backup_datasets($bf,$preferences,$question,$level=7) {
230 global $CFG;
232 $status = true;
234 //First, we get the used datasets for this question
235 $question_datasets = get_records("question_datasets","question",$question,"id");
236 //If there are question_datasets
237 if ($question_datasets) {
238 $status = $status &&fwrite ($bf,start_tag("DATASET_DEFINITIONS",$level,true));
239 //Iterate over each question_dataset
240 foreach ($question_datasets as $question_dataset) {
241 $def = NULL;
242 //Get dataset_definition
243 if ($def = get_record("question_dataset_definitions","id",$question_dataset->datasetdefinition)) {;
244 $status = $status &&fwrite ($bf,start_tag("DATASET_DEFINITION",$level+1,true));
245 //Print question_dataset contents
246 fwrite ($bf,full_tag("CATEGORY",$level+2,false,$def->category));
247 fwrite ($bf,full_tag("NAME",$level+2,false,$def->name));
248 fwrite ($bf,full_tag("TYPE",$level+2,false,$def->type));
249 fwrite ($bf,full_tag("OPTIONS",$level+2,false,$def->options));
250 fwrite ($bf,full_tag("ITEMCOUNT",$level+2,false,$def->itemcount));
251 //Now backup dataset_entries
252 $status = question_backup_dataset_items($bf,$preferences,$def->id,$level+2);
253 //End dataset definition
254 $status = $status &&fwrite ($bf,end_tag("DATASET_DEFINITION",$level+1,true));
257 $status = $status &&fwrite ($bf,end_tag("DATASET_DEFINITIONS",$level,true));
260 return $status;
264 //This function backups datases_items from dataset_definitions
265 function question_backup_dataset_items($bf,$preferences,$datasetdefinition,$level=9) {
267 global $CFG;
269 $status = true;
271 //First, we get the datasets_items for this dataset_definition
272 $dataset_items = get_records("question_dataset_items","definition",$datasetdefinition,"id");
273 //If there are dataset_items
274 if ($dataset_items) {
275 $status = $status &&fwrite ($bf,start_tag("DATASET_ITEMS",$level,true));
276 //Iterate over each dataset_item
277 foreach ($dataset_items as $dataset_item) {
278 $status = $status &&fwrite ($bf,start_tag("DATASET_ITEM",$level+1,true));
279 //Print question_dataset contents
280 fwrite ($bf,full_tag("NUMBER",$level+2,false,$dataset_item->itemnumber));
281 fwrite ($bf,full_tag("VALUE",$level+2,false,$dataset_item->value));
282 //End dataset definition
283 $status = $status &&fwrite ($bf,end_tag("DATASET_ITEM",$level+1,true));
285 $status = $status &&fwrite ($bf,end_tag("DATASET_ITEMS",$level,true));
288 return $status;
293 //Backup question_states contents (executed from backup_quiz_attempts)
294 function backup_question_states ($bf,$preferences,$attempt, $level = 6) {
296 global $CFG;
298 $status = true;
300 $question_states = get_records("question_states","attempt",$attempt,"id");
301 //If there are states
302 if ($question_states) {
303 //Write start tag
304 $status = fwrite ($bf,start_tag("STATES",$level,true));
305 //Iterate over each state
306 foreach ($question_states as $state) {
307 //Start state
308 $status = fwrite ($bf,start_tag("STATE",$level + 1,true));
309 //Print state contents
310 fwrite ($bf,full_tag("ID",$level + 2,false,$state->id));
311 fwrite ($bf,full_tag("QUESTION",$level + 2,false,$state->question));
312 fwrite ($bf,full_tag("ORIGINALQUESTION",$level + 2,false,$state->originalquestion));
313 fwrite ($bf,full_tag("SEQ_NUMBER",$level + 2,false,$state->seq_number));
314 fwrite ($bf,full_tag("ANSWER",$level + 2,false,$state->answer));
315 fwrite ($bf,full_tag("TIMESTAMP",$level + 2,false,$state->timestamp));
316 fwrite ($bf,full_tag("EVENT",$level + 2,false,$state->event));
317 fwrite ($bf,full_tag("GRADE",$level + 2,false,$state->grade));
318 fwrite ($bf,full_tag("RAW_GRADE",$level + 2,false,$state->raw_grade));
319 fwrite ($bf,full_tag("PENALTY",$level + 2,false,$state->penalty));
320 // now back up question type specific state information
321 $status = backup_question_rqp_state ($bf,$preferences,$state->id, $level + 2);
322 //End state
323 $status = fwrite ($bf,end_tag("STATE",$level + 1,true));
325 //Write end tag
326 $status = fwrite ($bf,end_tag("STATES",$level,true));
330 //Backup question_sessions contents (executed from backup_quiz_attempts)
331 function backup_question_sessions ($bf,$preferences,$attempt, $level = 6) {
332 global $CFG;
334 $status = true;
336 $question_sessions = get_records("question_sessions","attemptid",$attempt,"id");
337 //If there are sessions
338 if ($question_sessions) {
339 //Write start tag (the funny name 'newest states' has historical reasons)
340 $status = fwrite ($bf,start_tag("NEWEST_STATES",$level,true));
341 //Iterate over each newest_state
342 foreach ($question_sessions as $newest_state) {
343 //Start newest_state
344 $status = fwrite ($bf,start_tag("NEWEST_STATE",$level + 1,true));
345 //Print newest_state contents
346 fwrite ($bf,full_tag("ID",$level + 2,false,$newest_state->id));
347 fwrite ($bf,full_tag("QUESTIONID",$level + 2,false,$newest_state->questionid));
348 fwrite ($bf,full_tag("NEWEST",$level + 2,false,$newest_state->newest));
349 fwrite ($bf,full_tag("NEWGRADED",$level + 2,false,$newest_state->newgraded));
350 fwrite ($bf,full_tag("SUMPENALTY",$level + 2,false,$newest_state->sumpenalty));
351 //End newest_state
352 $status = fwrite ($bf,end_tag("NEWEST_STATE",$level + 1,true));
354 //Write end tag
355 $status = fwrite ($bf,end_tag("NEWEST_STATES",$level,true));
357 return $status;
360 //Backup question_rqp_state contents (executed from backup_question_states)
361 function backup_question_rqp_state ($bf,$preferences,$state, $level = 8) {
363 global $CFG;
365 $status = true;
367 $rqp_state = get_record("question_rqp_states","stateid",$state);
368 //If there is a state
369 if ($rqp_state) {
370 //Write start tag
371 $status = fwrite ($bf,start_tag("RQP_STATE",$level,true));
372 //Print state contents
373 fwrite ($bf,full_tag("RESPONSES",$level + 1,false,$rqp_state->responses));
374 fwrite ($bf,full_tag("PERSISTENT_DATA",$level + 1,false,$rqp_state->persistent_data));
375 fwrite ($bf,full_tag("TEMPLATE_VARS",$level + 1,false,$rqp_state->template_vars));
376 //Write end tag
377 $status = fwrite ($bf,end_tag("RQP_STATE",$level,true));
379 return $status;
382 //Returns an array of categories id
383 function question_category_ids_by_backup ($backup_unique_code) {
385 global $CFG;
387 return get_records_sql ("SELECT a.old_id, a.backup_code
388 FROM {$CFG->prefix}backup_ids a
389 WHERE a.backup_code = '$backup_unique_code' AND
390 a.table_name = 'question_categories'");
393 function question_ids_by_backup ($backup_unique_code) {
395 global $CFG;
397 return get_records_sql ("SELECT q.id, q.category
398 FROM {$CFG->prefix}backup_ids a,
399 {$CFG->prefix}question q
400 WHERE a.backup_code = '$backup_unique_code' AND
401 q.category = a.old_id AND
402 a.table_name = 'question_categories'");
405 //Delete category ids from backup_ids table
406 function delete_category_ids ($backup_unique_code) {
407 global $CFG;
408 $status = true;
409 $status = execute_sql("DELETE FROM {$CFG->prefix}backup_ids
410 WHERE backup_code = '$backup_unique_code'",false);
411 return $status;