b37aff296c605c186462404c1b4ef8fe9a32c44c
[moodle.git] / backup / util / ui / base_moodleform.class.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  * This file contains the generic moodleform bridge for the backup user interface
19  * as well as the individual forms that relate to the different stages the user
20  * interface can exist within.
21  *
22  * @package   core_backup
23  * @copyright 2010 Sam Hemelryk
24  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25  */
27 defined('MOODLE_INTERNAL') || die();
29 require_once($CFG->libdir . '/formslib.php');
31 /**
32  * Base moodleform bridge
33  *
34  * Ahhh the mighty moodleform bridge! Strong enough to take the weight of 682 full
35  * grown african swallows all of whom have been carring coconuts for several days.
36  * EWWWWW!!!!!!!!!!!!!!!!!!!!!!!!
37  *
38  * @package   core_backup
39  * @copyright 2010 Sam Hemelryk
40  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
41  */
42 abstract class base_moodleform extends moodleform {
44     /**
45      * The stage this form belongs to
46      * @var base_ui_stage
47      */
48     protected $uistage = null;
50     /**
51      * True if we have a course div open, false otherwise
52      * @var bool
53      */
54     protected $coursediv = false;
56     /**
57      * True if we have a section div open, false otherwise
58      * @var bool
59      */
60     protected $sectiondiv = false;
62     /**
63      * True if we have an activity div open, false otherwise
64      * @var bool
65      */
66     protected $activitydiv = false;
68     /**
69      * Creates the form
70      *
71      * @param base_ui_stage $uistage
72      * @param moodle_url|string $action
73      * @param mixed $customdata
74      * @param string $method get|post
75      * @param string $target
76      * @param array $attributes
77      * @param bool $editable
78      */
79     public function __construct(base_ui_stage $uistage, $action = null, $customdata = null, $method = 'post',
80                                 $target = '', $attributes = null, $editable = true) {
81         $this->uistage = $uistage;
82         // Add a class to the attributes to prevent the default collapsible behaviour.
83         if (!$attributes) {
84             $attributes = array();
85         }
86         $attributes['class'] = 'unresponsive';
87         if (!isset($attributes['enctype'])) {
88             $attributes['enctype'] = 'application/x-www-form-urlencoded'; // Enforce compatibility with our max_input_vars hack.
89         }
90         parent::__construct($action, $customdata, $method, $target, $attributes, $editable);
91     }
93     /**
94      * The standard form definition... obviously not much here
95      */
96     public function definition() {
97         $ui = $this->uistage->get_ui();
98         $mform = $this->_form;
99         $mform->setDisableShortforms();
100         $stage = $mform->addElement('hidden', 'stage', $this->uistage->get_stage());
101         $mform->setType('stage', PARAM_INT);
102         $stage = $mform->addElement('hidden', $ui->get_name(), $ui->get_uniqueid());
103         $mform->setType($ui->get_name(), PARAM_ALPHANUM);
104         $params = $this->uistage->get_params();
105         if (is_array($params) && count($params) > 0) {
106             foreach ($params as $name => $value) {
107                 // TODO: Horrible hack, but current backup ui structure does not allow
108                 // to make this easy (only changing params to objects that would be
109                 // possible. MDL-38735.
110                 $intparams = array(
111                         'contextid', 'importid', 'target');
112                 $stage = $mform->addElement('hidden', $name, $value);
113                 if (in_array($name, $intparams)) {
114                     $mform->setType($name, PARAM_INT);
115                 } else {
116                     // Adding setType() to avoid missing setType() warnings.
117                     // MDL-39126: support $mform->setType() for additional backup parameters.
118                     $mform->setType($name, PARAM_RAW);
119                 }
120             }
121         }
122     }
123     /**
124      * Definition applied after the data is organised.. why's it here? because I want
125      * to add elements on the fly.
126      * @global moodle_page $PAGE
127      */
128     public function definition_after_data() {
129         $buttonarray = array();
130         if (!$this->uistage->is_first_stage()) {
131             $buttonarray[] = $this->_form->createElement('submit', 'previous', get_string('previousstage', 'backup'));
132         } else if ($this->uistage instanceof backup_ui_stage) {
133             // Only display the button on the first stage of backup, they only place where it has an effect.
134             $buttonarray[] = $this->_form->createElement('submit', 'oneclickbackup', get_string('jumptofinalstep', 'backup'),
135                 array('class' => 'oneclickbackup'));
136         }
137         $buttonarray[] = $this->_form->createElement('cancel', 'cancel', get_string('cancel'), array('class' => 'confirmcancel'));
138         $buttonarray[] = $this->_form->createElement(
139             'submit',
140             'submitbutton',
141             get_string($this->uistage->get_ui()->get_name().'stage'.$this->uistage->get_stage().'action', 'backup'),
142             array('class' => 'proceedbutton')
143         );
144         $this->_form->addGroup($buttonarray, 'buttonar', '', array(' '), false);
145         $this->_form->closeHeaderBefore('buttonar');
147         $this->_definition_finalized = true;
148     }
150     /**
151      * Closes any open divs
152      */
153     public function close_task_divs() {
154         if ($this->activitydiv) {
155             $this->_form->addElement('html', html_writer::end_tag('div'));
156             $this->activitydiv = false;
157         }
158         if ($this->sectiondiv) {
159             $this->_form->addElement('html', html_writer::end_tag('div'));
160             $this->sectiondiv = false;
161         }
162         if ($this->coursediv) {
163             $this->_form->addElement('html', html_writer::end_tag('div'));
164             $this->coursediv = false;
165         }
166     }
168     /**
169      * Adds the backup_setting as a element to the form
170      * @param backup_setting $setting
171      * @param base_task $task
172      * @return bool
173      */
174     public function add_setting(backup_setting $setting, base_task $task = null) {
175         return $this->add_settings(array(array($setting, $task)));
176     }
178     /**
179      * Adds multiple backup_settings as elements to the form
180      * @param array $settingstasks Consists of array($setting, $task) elements
181      * @return bool
182      */
183     public function add_settings(array $settingstasks) {
184         global $OUTPUT;
186         // Determine highest setting level, which is displayed in this stage. This is relevant for considering only
187         // locks of dependency settings for parent settings, which are not displayed in this stage.
188         $highestlevel = backup_setting::ACTIVITY_LEVEL;
189         foreach ($settingstasks as $st) {
190             list($setting, $task) = $st;
191             if ($setting->get_level() < $highestlevel) {
192                 $highestlevel = $setting->get_level();
193             }
194         }
196         $defaults = array();
197         foreach ($settingstasks as $st) {
198             list($setting, $task) = $st;
199             // If the setting cant be changed or isn't visible then add it as a fixed setting.
200             if (!$setting->get_ui()->is_changeable($highestlevel) ||
201                 $setting->get_visibility() != backup_setting::VISIBLE) {
202                 $this->add_fixed_setting($setting, $task);
203                 continue;
204             }
206             // First add the formatting for this setting.
207             $this->add_html_formatting($setting);
209             // Then call the add method with the get_element_properties array.
210             call_user_func_array(array($this->_form, 'addElement'), $setting->get_ui()->get_element_properties($task, $OUTPUT));
211             $this->_form->setType($setting->get_ui_name(), $setting->get_param_validation());
212             $defaults[$setting->get_ui_name()] = $setting->get_value();
213             if ($setting->has_help()) {
214                 list($identifier, $component) = $setting->get_help();
215                 $this->_form->addHelpButton($setting->get_ui_name(), $identifier, $component);
216             }
217             $this->_form->addElement('html', html_writer::end_tag('div'));
218         }
219         $this->_form->setDefaults($defaults);
220         return true;
221     }
223     /**
224      * Adds a heading to the form
225      * @param string $name
226      * @param string $text
227      */
228     public function add_heading($name , $text) {
229         $this->_form->addElement('header', $name, $text);
230     }
232     /**
233      * Adds HTML formatting for the given backup setting, needed to group/segment
234      * correctly.
235      * @param backup_setting $setting
236      */
237     protected function add_html_formatting(backup_setting $setting) {
238         $mform = $this->_form;
239         $isincludesetting = (strpos($setting->get_name(), '_include') !== false);
240         if ($isincludesetting && $setting->get_level() != backup_setting::ROOT_LEVEL) {
241             switch ($setting->get_level()) {
242                 case backup_setting::COURSE_LEVEL:
243                     if ($this->activitydiv) {
244                         $this->_form->addElement('html', html_writer::end_tag('div'));
245                         $this->activitydiv = false;
246                     }
247                     if ($this->sectiondiv) {
248                         $this->_form->addElement('html', html_writer::end_tag('div'));
249                         $this->sectiondiv = false;
250                     }
251                     if ($this->coursediv) {
252                         $this->_form->addElement('html', html_writer::end_tag('div'));
253                     }
254                     $mform->addElement('html', html_writer::start_tag('div', array('class' => 'grouped_settings course_level')));
255                     $mform->addElement('html', html_writer::start_tag('div', array('class' => 'include_setting course_level')));
256                     $this->coursediv = true;
257                     break;
258                 case backup_setting::SECTION_LEVEL:
259                     if ($this->activitydiv) {
260                         $this->_form->addElement('html', html_writer::end_tag('div'));
261                         $this->activitydiv = false;
262                     }
263                     if ($this->sectiondiv) {
264                         $this->_form->addElement('html', html_writer::end_tag('div'));
265                     }
266                     $mform->addElement('html', html_writer::start_tag('div', array('class' => 'grouped_settings section_level')));
267                     $mform->addElement('html', html_writer::start_tag('div', array('class' => 'include_setting section_level')));
268                     $this->sectiondiv = true;
269                     break;
270                 case backup_setting::ACTIVITY_LEVEL:
271                     if ($this->activitydiv) {
272                         $this->_form->addElement('html', html_writer::end_tag('div'));
273                     }
274                     $mform->addElement('html', html_writer::start_tag('div', array('class' => 'grouped_settings activity_level')));
275                     $mform->addElement('html', html_writer::start_tag('div', array('class' => 'include_setting activity_level')));
276                     $this->activitydiv = true;
277                     break;
278                 default:
279                     $mform->addElement('html', html_writer::start_tag('div', array('class' => 'normal_setting')));
280                     break;
281             }
282         } else if ($setting->get_level() == backup_setting::ROOT_LEVEL) {
283             $mform->addElement('html', html_writer::start_tag('div', array('class' => 'root_setting')));
284         } else {
285             $mform->addElement('html', html_writer::start_tag('div', array('class' => 'normal_setting')));
286         }
287     }
289     /**
290      * Adds a fixed or static setting to the form
291      * @param backup_setting $setting
292      * @param base_task $task
293      */
294     public function add_fixed_setting(backup_setting $setting, base_task $task) {
295         global $OUTPUT;
296         $settingui = $setting->get_ui();
297         if ($setting->get_visibility() == backup_setting::VISIBLE) {
298             $this->add_html_formatting($setting);
299             switch ($setting->get_status()) {
300                 case backup_setting::LOCKED_BY_PERMISSION:
301                     $icon = ' '.$OUTPUT->pix_icon('i/permissionlock', get_string('lockedbypermission', 'backup'), 'moodle',
302                             array('class' => 'smallicon lockedicon permissionlock'));
303                     break;
304                 case backup_setting::LOCKED_BY_CONFIG:
305                     $icon = ' '.$OUTPUT->pix_icon('i/configlock', get_string('lockedbyconfig', 'backup'), 'moodle',
306                             array('class' => 'smallicon lockedicon configlock'));
307                     break;
308                 case backup_setting::LOCKED_BY_HIERARCHY:
309                     $icon = ' '.$OUTPUT->pix_icon('i/hierarchylock', get_string('lockedbyhierarchy', 'backup'), 'moodle',
310                             array('class' => 'smallicon lockedicon configlock'));
311                     break;
312                 default:
313                     $icon = '';
314                     break;
315             }
316             $context = context_course::instance($task->get_courseid());
317             $label = format_string($settingui->get_label($task), true, array('context' => $context));
318             $labelicon = $settingui->get_icon();
319             if (!empty($labelicon)) {
320                 $label .= '&nbsp;'.$OUTPUT->render($labelicon);
321             }
322             $this->_form->addElement('static', 'static_'.$settingui->get_name(), $label, $settingui->get_static_value().$icon);
323             $this->_form->addElement('html', html_writer::end_tag('div'));
324         }
325         $this->_form->addElement('hidden', $settingui->get_name(), $settingui->get_value());
326         $this->_form->setType($settingui->get_name(), $settingui->get_param_validation());
327     }
329     /**
330      * Adds dependencies to the form recursively
331      *
332      * @param backup_setting $setting
333      */
334     public function add_dependencies(backup_setting $setting) {
335         $mform = $this->_form;
336         // Apply all dependencies for backup.
337         foreach ($setting->get_my_dependency_properties() as $key => $dependency) {
338             call_user_func_array(array($this->_form, 'disabledIf'), $dependency);
339         }
340     }
342     /**
343      * Returns true if the form was cancelled, false otherwise
344      * @return bool
345      */
346     public function is_cancelled() {
347         return (optional_param('cancel', false, PARAM_BOOL) || parent::is_cancelled());
348     }
350     /**
351      * Removes an element from the form if it exists
352      * @param string $elementname
353      * @return bool
354      */
355     public function remove_element($elementname) {
356         if ($this->_form->elementExists($elementname)) {
357             return $this->_form->removeElement($elementname);
358         } else {
359             return false;
360         }
361     }
363     /**
364      * Gets an element from the form if it exists
365      *
366      * @param string $elementname
367      * @return HTML_QuickForm_input|MoodleQuickForm_group
368      */
369     public function get_element($elementname) {
370         if ($this->_form->elementExists($elementname)) {
371             return $this->_form->getElement($elementname);
372         } else {
373             return false;
374         }
375     }
377     /**
378      * Displays the form
379      */
380     public function display() {
381         global $PAGE, $COURSE;
383         $this->require_definition_after_data();
385         $config = new stdClass;
386         if ($this->uistage->get_ui() instanceof import_ui) {
387             $config->title = get_string('confirmcancelimport', 'backup');
388         } else if ($this->uistage->get_ui() instanceof restore_ui) {
389             $config->title = get_string('confirmcancelrestore', 'backup');
390         } else {
391             $config->title = get_string('confirmcancel', 'backup');
392         }
393         $config->question = get_string('confirmcancelquestion', 'backup');
394         $config->yesLabel = $config->title;
395         $config->noLabel = get_string('confirmcancelno', 'backup');
396         $config->closeButtonTitle = get_string('close', 'editor');
397         $PAGE->requires->yui_module(
398             'moodle-backup-confirmcancel',
399             'M.core_backup.confirmcancel.watch_cancel_buttons',
400             array($config)
401         );
403         // Get list of module types on course.
404         $modinfo = get_fast_modinfo($COURSE);
405         $modnames = array_map('strval', $modinfo->get_used_module_names(true));
406         core_collator::asort($modnames);
407         $PAGE->requires->yui_module('moodle-backup-backupselectall', 'M.core_backup.backupselectall',
408                 array($modnames));
409         $PAGE->requires->strings_for_js(array('select', 'all', 'none'), 'moodle');
410         $PAGE->requires->strings_for_js(array('showtypes', 'hidetypes'), 'backup');
412         parent::display();
413     }
415     /**
416      * Ensures the the definition after data is loaded
417      */
418     public function require_definition_after_data() {
419         if (!$this->_definition_finalized) {
420             $this->definition_after_data();
421         }
422     }