Merge branch 'MDL-30021' of git://github.com/timhunt/moodle
[moodle.git] / question / type / numerical / db / upgrade.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Numerical question type upgrade code.
19  *
20  * @package    qtype
21  * @subpackage numerical
22  * @copyright  1999 onwards Martin Dougiamas {@link http://moodle.com}
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
27 defined('MOODLE_INTERNAL') || die();
30 /**
31  * Upgrade code for the numerical question type.
32  * @param int $oldversion the version we are upgrading from.
33  */
34 function xmldb_qtype_numerical_upgrade($oldversion) {
35     global $CFG, $DB;
37     $dbman = $DB->get_manager();
39     //===== 1.9.0 upgrade line ======//
40     if ($oldversion < 2009100100 ) { //New version in version.php
42         // Define table question_numerical_options to be created
43         $table = new xmldb_table('question_numerical_options');
45         // Adding fields to table question_numerical_options
46         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED,
47                 XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
48         $table->add_field('question', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED,
49                 XMLDB_NOTNULL, null, '0');
50         $table->add_field('instructions', XMLDB_TYPE_TEXT, 'small', null,
51                 null, null, null);
52         $table->add_field('showunits', XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED,
53                 XMLDB_NOTNULL, null, '0');
54         $table->add_field('unitsleft', XMLDB_TYPE_INTEGER, '4', null,
55                 XMLDB_NOTNULL, null, '0');
56         $table->add_field('unitgradingtype', XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED,
57                 XMLDB_NOTNULL, null, '0');
58         $table->add_field('unitpenalty', XMLDB_TYPE_NUMBER, '12, 7', XMLDB_UNSIGNED,
59                 XMLDB_NOTNULL, null, '0.1');
61         // Adding keys to table question_numerical_options
62         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
63         $table->add_key('question', XMLDB_KEY_FOREIGN, array('question'), 'question', array('id'));
65         // Conditionally launch create table for question_calculated_options
66         if (!$dbman->table_exists($table)) {
67             // $dbman->create_table doesnt return a result, we just have to trust it
68             $dbman->create_table($table);
69         }
71         // Set a better default for questions without units.
72         $DB->execute('
73                 UPDATE {question_numerical_options} qno
74                    SET showunits = 3
75                  WHERE NOT EXISTS (
76                          SELECT 1
77                            FROM {question_numerical_units} qnu
78                           WHERE qnu.question = qno.question)');
80         upgrade_plugin_savepoint(true, 2009100100, 'qtype', 'numerical');
81     }
83     if ($oldversion < 2009100101) {
85         // Define field instructionsformat to be added to question_numerical_options
86         $table = new xmldb_table('question_numerical_options');
87         $field = new xmldb_field('instructionsformat', XMLDB_TYPE_INTEGER, '2', null,
88                 XMLDB_NOTNULL, null, '0', 'instructions');
90         // Conditionally launch add field instructionsformat
91         if (!$dbman->field_exists($table, $field)) {
92             $dbman->add_field($table, $field);
93         }
95         // In the past, question_numerical_options.instructions assumed to contain
96         // content of the same form as question.questiontextformat. If we are
97         // using the HTML editor, then convert FORMAT_MOODLE content to FORMAT_HTML.
98         $rs = $DB->get_recordset_sql('
99                 SELECT qno.*, q.oldquestiontextformat
100                 FROM {question_numerical_options} qno
101                 JOIN {question} q ON qno.question = q.id');
102         foreach ($rs as $record) {
103             if ($CFG->texteditors !== 'textarea' &&
104                     $record->oldquestiontextformat == FORMAT_MOODLE) {
105                 $record->instructions = text_to_html($record->instructions, false, false, true);
106                 $record->instructionsformat = FORMAT_HTML;
107             } else {
108                 $record->instructionsformat = $record->oldquestiontextformat;
109             }
110             $DB->update_record('question_numerical_options', $record);
111         }
112         $rs->close();
114         // numerical savepoint reached
115         upgrade_plugin_savepoint(true, 2009100101, 'qtype', 'numerical');
116     }
118     if ($oldversion < 2011042600) {
119         // Get rid of the instructions field by adding it to the qestion
120         // text. Also, if the unit was set to be displayed beside the input,
121         // deal with that within the question text too.
123         // The hard-coded constants used here are:
124         // 2 = the old qtype_numerical::UNITDISPLAY for ->showunits
125         // 3 = qtype_numerical::UNITNONE
127         $fs = get_file_storage();
129         $rs = $DB->get_recordset_sql('
130                 SELECT q.id AS questionid,
131                        q.questiontext,
132                        q.questiontextformat,
133                        qc.contextid,
134                        qno.id AS qnoid,
135                        qno.instructions,
136                        qno.instructionsformat,
137                        qno.showunits,
138                        qno.unitsleft,
139                        qnu.unit AS defaultunit
141                   FROM {question} q
142                   JOIN {question_categories} qc ON qc.id = q.category
143                   JOIN {question_numerical_options} qno ON qno.question = q.id
144                   JOIN {question_numerical_units} qnu ON qnu.id = (
145                             SELECT min(id)
146                               FROM {question_numerical_units}
147                              WHERE question = q.id AND ABS(multiplier - 1) < 0.0000000001)');
148         foreach ($rs as $numericaloptions) {
149             if ($numericaloptions->showunits != 2 && empty($numericaloptions->instructions)) {
150                 // Nothing to do for this question.
151                 continue;
152             }
154             $ishtml = qtype_numerical_convert_text_format($numericaloptions);
156             $response = '_______________';
157             if ($numericaloptions->showunits == 2) {
158                 if ($numericaloptions->unitsleft) {
159                     $response = $numericaloptions->defaultunit . ' _______________';
160                 } else {
161                     $response = '_______________ ' . $numericaloptions->defaultunit;
162                 }
164                 $DB->set_field('question_numerical_options', 'showunits', 3,
165                         array('id' => $numericaloptions->qnoid));
166             }
168             if ($ishtml) {
169                 $numericaloptions->questiontext .= '<p>' . $response . '</p>';
170             } else {
171                 $numericaloptions->questiontext .= "\n\n" . $response;
172             }
174             if (!empty($numericaloptions->instructions)) {
175                 if ($ishtml) {
176                     $numericaloptions->questiontext .= $numericaloptions->instructions;
177                 } else {
178                     $numericaloptions->questiontext .= "\n\n" . $numericaloptions->instructions;
179                 }
181                 $oldfiles = $fs->get_area_files($numericaloptions->contextid,
182                         'qtype_numerical', 'instruction', $numericaloptions->questionid,
183                         'id', false);
184                 foreach ($oldfiles as $oldfile) {
185                     $filerecord = new stdClass();
186                     $filerecord->component = 'question';
187                     $filerecord->filearea = 'questiontext';
188                     $fs->create_file_from_storedfile($filerecord, $oldfile);
189                 }
191                 if ($oldfiles) {
192                     $fs->delete_area_files($numericaloptions->contextid,
193                         'qtype_numerical', 'instruction', $numericaloptions->questionid);
194                 }
195             }
197             $updaterecord = new stdClass();
198             $updaterecord->id = $numericaloptions->questionid;
199             $updaterecord->questiontext = $numericaloptions->questiontext;
200             $updaterecord->questiontextformat = $numericaloptions->questiontextformat;
201             $DB->update_record('question', $updaterecord);
202         }
203         $rs->close();
205         // numerical savepoint reached
206         upgrade_plugin_savepoint(true, 2011042600, 'qtype', 'numerical');
207     }
209     if ($oldversion < 2011042601) {
210         // Define field instructions to be dropped from question_numerical_options
211         $table = new xmldb_table('question_numerical_options');
212         $field = new xmldb_field('instructions');
214         // Conditionally launch drop field instructions
215         if ($dbman->field_exists($table, $field)) {
216             $dbman->drop_field($table, $field);
217         }
219         // numerical savepoint reached
220         upgrade_plugin_savepoint(true, 2011042601, 'qtype', 'numerical');
221     }
223     if ($oldversion < 2011042602) {
224         // Define field instructionsformat to be dropped from question_numerical_options
225         $table = new xmldb_table('question_numerical_options');
226         $field = new xmldb_field('instructionsformat');
228         // Conditionally launch drop field instructionsformat
229         if ($dbman->field_exists($table, $field)) {
230             $dbman->drop_field($table, $field);
231         }
233         // numerical savepoint reached
234         upgrade_plugin_savepoint(true, 2011042602, 'qtype', 'numerical');
235     }
237     // Moodle v2.1.0 release upgrade line
238     // Put any upgrade step following this
240     return true;
243 /**
244  * Convert the ->questiontext and ->instructions fields to have the same text format.
245  * If they are already the same, do nothing. Otherwise, this method works by
246  * converting both to HTML.
247  * @param $numericaloptions the data to convert.
248  * @return bool true if the resulting fields are in HTML, as opposed to one of
249  * the text-based formats.
250  */
251 function qtype_numerical_convert_text_format($numericaloptions) {
252     if ($numericaloptions->questiontextformat == $numericaloptions->instructionsformat) {
253         // Nothing to do:
254         return $numericaloptions->questiontextformat == FORMAT_HTML;
255     }
257     if ($numericaloptions->questiontextformat != FORMAT_HTML) {
258         $numericaloptions->questiontext = qtype_numerical_convert_to_html(
259                 $numericaloptions->questiontext, $numericaloptions->questiontextformat);
260         $numericaloptions->questiontextformat = FORMAT_HTML;
261     }
263     if ($numericaloptions->instructionsformat != FORMAT_HTML) {
264         $numericaloptions->instructions = qtype_numerical_convert_to_html(
265                 $numericaloptions->instructions, $numericaloptions->instructionsformat);
266         $numericaloptions->instructionsformat = FORMAT_HTML;
267     }
269     return true;
272 // Add some helper functions that should be in upgradelib.php, but having there already
273 // the question attempts updater classes prevents us to do so :-(
275 /**
276  * Convert some content to HTML.
277  * @param string $text the content to convert to HTML
278  * @param int $oldformat One of the FORMAT_... constants.
279  */
280 function qtype_numerical_convert_to_html($text, $oldformat) {
281     switch ($oldformat) {
282         // Similar to format_text.
284         case FORMAT_PLAIN:
285             $text = s($text);
286             $text = str_replace('  ', '&nbsp; ', $text);
287             $text = nl2br($text);
288             return $text;
290         case FORMAT_MARKDOWN:
291             return markdown_to_html($text);
293         case FORMAT_MOODLE:
294             return text_to_html($text, null, $options['para'], $options['newlines']);
296         default:
297             throw new coding_exception(
298                     'Unexpected text format when upgrading numerical questions.');
299     }