MDL-46481 backup: implemented quick backup process (one click)
[moodle.git] / backup / util / ui / base_moodleform.class.php
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
18 /**
19  * This file contains the generic moodleform bridge for the backup user interface
20  * as well as the individual forms that relate to the different stages the user
21  * interface can exist within.
22  *
23  * @package   moodlecore
24  * @copyright 2010 Sam Hemelryk
25  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26  */
28 defined('MOODLE_INTERNAL') || die();
30 require_once($CFG->libdir . '/formslib.php');
32 /**
33  * Backup moodleform bridge
34  *
35  * Ahhh the mighty moodleform bridge! Strong enough to take the weight of 682 full
36  * grown african swallows all of whom have been carring coconuts for several days.
37  * EWWWWW!!!!!!!!!!!!!!!!!!!!!!!!
38  *
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 {
43     /**
44      * The stage this form belongs to
45      * @var base_ui_stage
46      */
47     protected $uistage = null;
48     /**
49      * True if we have a course div open, false otherwise
50      * @var bool
51      */
52     protected $coursediv = false;
53     /**
54      * True if we have a section div open, false otherwise
55      * @var bool
56      */
57     protected $sectiondiv = false;
58     /**
59      * True if we have an activity div open, false otherwise
60      * @var bool
61      */
62     protected $activitydiv = false;
63     /**
64      * Creates the form
65      *
66      * @param backup_ui_stage $uistage
67      * @param moodle_url|string $action
68      * @param mixed $customdata
69      * @param string $method get|post
70      * @param string $target
71      * @param array $attributes
72      * @param bool $editable
73      */
74     function __construct(base_ui_stage $uistage, $action=null, $customdata=null, $method='post', $target='', $attributes=null, $editable=true) {
75         $this->uistage = $uistage;
76         // Add a class to the attributes to prevent the default collapsible behaviour.
77         if (!$attributes) {
78             $attributes = array();
79         }
80         $attributes['class'] = 'unresponsive';
81         if (!isset($attributes['enctype'])) {
82             $attributes['enctype'] = 'application/x-www-form-urlencoded'; // Enforce compatibility with our max_input_vars hack.
83         }
84         parent::__construct($action, $customdata, $method, $target, $attributes, $editable);
85     }
86     /**
87      * The standard form definition... obviously not much here
88      */
89     function definition() {
90         $ui = $this->uistage->get_ui();
91         $mform = $this->_form;
92         $mform->setDisableShortforms();
93         $stage = $mform->addElement('hidden', 'stage', $this->uistage->get_stage());
94         $mform->setType('stage', PARAM_INT);
95         $stage = $mform->addElement('hidden', $ui->get_name(), $ui->get_uniqueid());
96         $mform->setType($ui->get_name(), PARAM_ALPHANUM);
97         $params = $this->uistage->get_params();
98         if (is_array($params) && count($params) > 0) {
99             foreach ($params as $name=>$value) {
100                 // TODO: Horrible hack, but current backup ui structure does not allow
101                 // to make this easy (only changing params to objects that would be
102                 // possible. MDL-38735.
103                 $intparams = array(
104                         'contextid', 'importid', 'target');
105                 $stage = $mform->addElement('hidden', $name, $value);
106                 if (in_array($name, $intparams)) {
107                     $mform->setType($name, PARAM_INT);
108                 } else {
109                     // Adding setType() to avoid missing setType() warnings.
110                     // MDL-39126: support $mform->setType() for additional backup parameters.
111                     $mform->setType($name, PARAM_RAW);
112                 }
113             }
114         }
115     }
116     /**
117      * Definition applied after the data is organised.. why's it here? because I want
118      * to add elements on the fly.
119      * @global moodle_page $PAGE
120      */
121     function definition_after_data() {
122         $buttonarray=array();
123         $buttonarray[] = $this->_form->createElement('submit', 'submitbutton', get_string($this->uistage->get_ui()->get_name().'stage'.$this->uistage->get_stage().'action', 'backup'), array('class'=>'proceedbutton'));
124         if (!$this->uistage->is_first_stage()) {
125             $buttonarray[] = $this->_form->createElement('submit', 'previous', get_string('previousstage','backup'));
126         }
127         $buttonarray[] = $this->_form->createElement('cancel', 'cancel', get_string('cancel'), array('class'=>'confirmcancel'));
128         $this->_form->addGroup($buttonarray, 'buttonar', '', array(' '), false);
129         $this->_form->closeHeaderBefore('buttonar');
131         $this->_definition_finalized = true;
132     }
134     /**
135      * Closes any open divs
136      */
137     function close_task_divs() {
138         if ($this->activitydiv) {
139             $this->_form->addElement('html', html_writer::end_tag('div'));
140             $this->activitydiv = false;
141         }
142         if ($this->sectiondiv) {
143             $this->_form->addElement('html', html_writer::end_tag('div'));
144             $this->sectiondiv = false;
145         }
146         if ($this->coursediv) {
147             $this->_form->addElement('html', html_writer::end_tag('div'));
148             $this->coursediv = false;
149         }
150     }
151     /**
152      * Adds the backup_setting as a element to the form
153      * @param backup_setting $setting
154      * @return bool
155      */
156     function add_setting(backup_setting $setting, base_task $task=null) {
157         return $this->add_settings(array(array($setting, $task)));
158     }
159     /**
160      * Adds multiple backup_settings as elements to the form
161      * @param array $settingstasks Consists of array($setting, $task) elements
162      * @return bool
163      */
164     public function add_settings(array $settingstasks) {
165         global $OUTPUT;
167         $defaults = array();
168         foreach ($settingstasks as $st) {
169             list($setting, $task) = $st;
170             // If the setting cant be changed or isn't visible then add it as a fixed setting.
171             if (!$setting->get_ui()->is_changeable() || $setting->get_visibility() != backup_setting::VISIBLE) {
172                 $this->add_fixed_setting($setting, $task);
173                 continue;
174             }
176             // First add the formatting for this setting
177             $this->add_html_formatting($setting);
179             // Then call the add method with the get_element_properties array
180             call_user_func_array(array($this->_form, 'addElement'), $setting->get_ui()->get_element_properties($task, $OUTPUT));
181             $this->_form->setType($setting->get_ui_name(), $setting->get_param_validation());
182             $defaults[$setting->get_ui_name()] = $setting->get_value();
183             if ($setting->has_help()) {
184                 list($identifier, $component) = $setting->get_help();
185                 $this->_form->addHelpButton($setting->get_ui_name(), $identifier, $component);
186             }
187             $this->_form->addElement('html', html_writer::end_tag('div'));
188         }
189         $this->_form->setDefaults($defaults);
190         return true;
191     }
192     /**
193      * Adds a heading to the form
194      * @param string $name
195      * @param string $text
196      */
197     function add_heading($name , $text) {
198         $this->_form->addElement('header', $name, $text);
199     }
200     /**
201      * Adds HTML formatting for the given backup setting, needed to group/segment
202      * correctly.
203      * @param backup_setting $setting
204      */
205     protected function add_html_formatting(backup_setting $setting) {
206         $mform = $this->_form;
207         $isincludesetting = (strpos($setting->get_name(), '_include')!==false);
208         if ($isincludesetting && $setting->get_level() != backup_setting::ROOT_LEVEL)  {
209             switch ($setting->get_level()) {
210                 case backup_setting::COURSE_LEVEL:
211                     if ($this->activitydiv) {
212                         $this->_form->addElement('html', html_writer::end_tag('div'));
213                         $this->activitydiv = false;
214                     }
215                     if ($this->sectiondiv) {
216                         $this->_form->addElement('html', html_writer::end_tag('div'));
217                         $this->sectiondiv = false;
218                     }
219                     if ($this->coursediv) {
220                         $this->_form->addElement('html', html_writer::end_tag('div'));
221                     }
222                     $mform->addElement('html', html_writer::start_tag('div', array('class'=>'grouped_settings course_level')));
223                     $mform->addElement('html', html_writer::start_tag('div', array('class'=>'include_setting course_level')));
224                     $this->coursediv = true;
225                     break;
226                 case backup_setting::SECTION_LEVEL:
227                     if ($this->activitydiv) {
228                         $this->_form->addElement('html', html_writer::end_tag('div'));
229                         $this->activitydiv = false;
230                     }
231                     if ($this->sectiondiv) {
232                         $this->_form->addElement('html', html_writer::end_tag('div'));
233                     }
234                     $mform->addElement('html', html_writer::start_tag('div', array('class'=>'grouped_settings section_level')));
235                     $mform->addElement('html', html_writer::start_tag('div', array('class'=>'include_setting section_level')));
236                     $this->sectiondiv = true;
237                     break;
238                 case backup_setting::ACTIVITY_LEVEL:
239                     if ($this->activitydiv) {
240                         $this->_form->addElement('html', html_writer::end_tag('div'));
241                     }
242                     $mform->addElement('html', html_writer::start_tag('div', array('class'=>'grouped_settings activity_level')));
243                     $mform->addElement('html', html_writer::start_tag('div', array('class'=>'include_setting activity_level')));
244                     $this->activitydiv = true;
245                     break;
246                 default:
247                     $mform->addElement('html', html_writer::start_tag('div', array('class'=>'normal_setting')));
248                     break;
249             }
250         } else if ($setting->get_level() == backup_setting::ROOT_LEVEL) {
251             $mform->addElement('html', html_writer::start_tag('div', array('class'=>'root_setting')));
252         } else {
253             $mform->addElement('html', html_writer::start_tag('div', array('class'=>'normal_setting')));
254         }
255     }
256     /**
257      * Adds a fixed or static setting to the form
258      * @param backup_setting $setting
259      */
260     function add_fixed_setting(backup_setting $setting, base_task $task) {
261         global $OUTPUT;
262         $settingui = $setting->get_ui();
263         if ($setting->get_visibility() == backup_setting::VISIBLE) {
264             $this->add_html_formatting($setting);
265             switch ($setting->get_status()) {
266                 case backup_setting::LOCKED_BY_PERMISSION:
267                     $icon = ' '.$OUTPUT->pix_icon('i/permissionlock', get_string('lockedbypermission', 'backup'), 'moodle', array('class'=>'smallicon lockedicon permissionlock'));
268                     break;
269                 case backup_setting::LOCKED_BY_CONFIG:
270                     $icon = ' '.$OUTPUT->pix_icon('i/configlock', get_string('lockedbyconfig', 'backup'), 'moodle', array('class'=>'smallicon lockedicon configlock'));
271                     break;
272                 case backup_setting::LOCKED_BY_HIERARCHY:
273                     $icon = ' '.$OUTPUT->pix_icon('i/hierarchylock', get_string('lockedbyhierarchy', 'backup'), 'moodle', array('class'=>'smallicon lockedicon configlock'));
274                     break;
275                 default:
276                     $icon = '';
277                     break;
278             }
279             $label = $settingui->get_label($task);
280             $labelicon = $settingui->get_icon();
281             if (!empty($labelicon)) {
282                 $label .= '&nbsp;'.$OUTPUT->render($labelicon);
283             }
284             $this->_form->addElement('static', 'static_'.$settingui->get_name(), $label, $settingui->get_static_value().$icon);
285             $this->_form->addElement('html', html_writer::end_tag('div'));
286         }
287         $this->_form->addElement('hidden', $settingui->get_name(), $settingui->get_value());
288         $this->_form->setType($settingui->get_name(), $settingui->get_param_validation());
289     }
290     /**
291      * Adds dependencies to the form recursively
292      *
293      * @param backup_setting $setting
294      */
295     function add_dependencies(backup_setting $setting) {
296         $mform = $this->_form;
297         // Apply all dependencies for backup
298         foreach ($setting->get_my_dependency_properties() as $key=>$dependency) {
299             call_user_func_array(array($this->_form, 'disabledIf'), $dependency);
300         }
301     }
302     /**
303      * Returns true if the form was cancelled, false otherwise
304      * @return bool
305      */
306     public function is_cancelled() {
307         return (optional_param('cancel', false, PARAM_BOOL) || parent::is_cancelled());
308     }
310     /**
311      * Removes an element from the form if it exists
312      * @param string $elementname
313      * @return bool
314      */
315     public function remove_element($elementname) {
316         if ($this->_form->elementExists($elementname)) {
317             return $this->_form->removeElement($elementname);
318         } else {
319             return false;
320         }
321     }
323     /**
324      * Gets an element from the form if it exists
325      *
326      * @param string $elementname
327      * @return HTML_QuickForm_input|MoodleQuickForm_group
328      */
329     public function get_element($elementname) {
330         if ($this->_form->elementExists($elementname)) {
331             return $this->_form->getElement($elementname);
332         } else {
333             return false;
334         }
335     }
337     /**
338      * Displays the form
339      */
340     public function display() {
341         global $PAGE, $COURSE;
343         $this->require_definition_after_data();
345         $config = new stdClass;
346         $config->title = get_string('confirmcancel', 'backup');
347         $config->question = get_string('confirmcancelquestion', 'backup');
348         $config->yesLabel = get_string('confirmcancelyes', 'backup');
349         $config->noLabel = get_string('confirmcancelno', 'backup');
350         $config->closeButtonTitle = get_string('close', 'editor');
351         $PAGE->requires->yui_module('moodle-backup-confirmcancel', 'M.core_backup.confirmcancel.watch_cancel_buttons', array($config));
353         // Get list of module types on course.
354         $modinfo = get_fast_modinfo($COURSE);
355         $modnames = $modinfo->get_used_module_names(true);
356         $PAGE->requires->yui_module('moodle-backup-backupselectall', 'M.core_backup.backupselectall',
357                 array($modnames));
358         $PAGE->requires->strings_for_js(array('select', 'all', 'none'), 'moodle');
359         $PAGE->requires->strings_for_js(array('showtypes', 'hidetypes'), 'backup');
361         parent::display();
362     }
364     /**
365      * Ensures the the definition after data is loaded
366      */
367     public function require_definition_after_data() {
368         if (!$this->_definition_finalized) {
369             $this->definition_after_data();
370         }
371     }
373     /**
374      * Can be used to collapse a heading from outside of this form.
375      *
376      * @param string $heading
377      */
378     public function collapse_heading($heading) {
379         $this->_form->setExpanded($heading, false);
380     }