Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.

Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 and 403] [Versions 402 and 403]

   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/>.
  16  
  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   */
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  require_once($CFG->libdir . '/formslib.php');
  30  
  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 {
  43  
  44      /**
  45       * The stage this form belongs to
  46       * @var base_ui_stage
  47       */
  48      protected $uistage = null;
  49  
  50      /**
  51       * True if we have a course div open, false otherwise
  52       * @var bool
  53       */
  54      protected $coursediv = false;
  55  
  56      /**
  57       * True if we have a section div open, false otherwise
  58       * @var bool
  59       */
  60      protected $sectiondiv = false;
  61  
  62      /**
  63       * True if we have an activity div open, false otherwise
  64       * @var bool
  65       */
  66      protected $activitydiv = false;
  67  
  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      }
  92  
  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  
 138          $cancelparams = [
 139              'data-modal' => 'confirmation',
 140              'data-modal-content-str' => json_encode([
 141                  'confirmcancelquestion',
 142                  'backup',
 143              ]),
 144              'data-modal-yes-button-str' => json_encode([
 145                  'yes',
 146                  'moodle',
 147              ]),
 148          ];
 149          if ($this->uistage->get_ui() instanceof import_ui) {
 150              $cancelparams['data-modal-title-str'] = json_encode([
 151                  'confirmcancelimport',
 152                  'backup',
 153              ]);
 154          } else if ($this->uistage->get_ui() instanceof restore_ui) {
 155              $cancelparams['data-modal-title-str'] = json_encode([
 156                  'confirmcancelrestore',
 157                  'backup',
 158              ]);
 159          } else {
 160              $cancelparams['data-modal-title-str'] = json_encode([
 161                  'confirmcancel',
 162                  'backup',
 163              ]);
 164          }
 165  
 166          $buttonarray[] = $this->_form->createElement('cancel', 'cancel', get_string('cancel'), $cancelparams);
 167          $buttonarray[] = $this->_form->createElement(
 168              'submit',
 169              'submitbutton',
 170              get_string($this->uistage->get_ui()->get_name().'stage'.$this->uistage->get_stage().'action', 'backup'),
 171              array('class' => 'proceedbutton')
 172          );
 173          $this->_form->addGroup($buttonarray, 'buttonar', '', array(' '), false);
 174          $this->_form->closeHeaderBefore('buttonar');
 175  
 176          $this->_definition_finalized = true;
 177      }
 178  
 179      /**
 180       * Closes any open divs
 181       */
 182      public function close_task_divs() {
 183          if ($this->activitydiv) {
 184              $this->_form->addElement('html', html_writer::end_tag('div'));
 185              $this->activitydiv = false;
 186          }
 187          if ($this->sectiondiv) {
 188              $this->_form->addElement('html', html_writer::end_tag('div'));
 189              $this->sectiondiv = false;
 190          }
 191          if ($this->coursediv) {
 192              $this->_form->addElement('html', html_writer::end_tag('div'));
 193              $this->coursediv = false;
 194          }
 195      }
 196  
 197      /**
 198       * Adds the backup_setting as a element to the form
 199       * @param backup_setting $setting
 200       * @param base_task $task
 201       * @return bool
 202       */
 203      public function add_setting(backup_setting $setting, base_task $task = null) {
 204          return $this->add_settings(array(array($setting, $task)));
 205      }
 206  
 207      /**
 208       * Adds multiple backup_settings as elements to the form
 209       * @param array $settingstasks Consists of array($setting, $task) elements
 210       * @return bool
 211       */
 212      public function add_settings(array $settingstasks) {
 213          global $OUTPUT;
 214  
 215          // Determine highest setting level, which is displayed in this stage. This is relevant for considering only
 216          // locks of dependency settings for parent settings, which are not displayed in this stage.
 217          $highestlevel = backup_setting::ACTIVITY_LEVEL;
 218          foreach ($settingstasks as $st) {
 219              list($setting, $task) = $st;
 220              if ($setting->get_level() < $highestlevel) {
 221                  $highestlevel = $setting->get_level();
 222              }
 223          }
 224  
 225          $defaults = array();
 226          foreach ($settingstasks as $st) {
 227              list($setting, $task) = $st;
 228              // If the setting cant be changed or isn't visible then add it as a fixed setting.
 229              if (!$setting->get_ui()->is_changeable($highestlevel) ||
 230                  $setting->get_visibility() != backup_setting::VISIBLE) {
 231                  $this->add_fixed_setting($setting, $task);
 232                  continue;
 233              }
 234  
 235              // First add the formatting for this setting.
 236              $this->add_html_formatting($setting);
 237  
 238              // Then call the add method with the get_element_properties array.
 239              call_user_func_array(array($this->_form, 'addElement'),
 240                  array_values($setting->get_ui()->get_element_properties($task, $OUTPUT)));
 241              $this->_form->setType($setting->get_ui_name(), $setting->get_param_validation());
 242              $defaults[$setting->get_ui_name()] = $setting->get_value();
 243              if ($setting->has_help()) {
 244                  list($identifier, $component) = $setting->get_help();
 245                  $this->_form->addHelpButton($setting->get_ui_name(), $identifier, $component);
 246              }
 247              $this->_form->addElement('html', html_writer::end_tag('div'));
 248          }
 249          $this->_form->setDefaults($defaults);
 250          return true;
 251      }
 252  
 253      /**
 254       * Adds a heading to the form
 255       * @param string $name
 256       * @param string $text
 257       */
 258      public function add_heading($name , $text) {
 259          $this->_form->addElement('header', $name, $text);
 260      }
 261  
 262      /**
 263       * Adds HTML formatting for the given backup setting, needed to group/segment
 264       * correctly.
 265       * @param backup_setting $setting
 266       */
 267      protected function add_html_formatting(backup_setting $setting) {
 268          $mform = $this->_form;
 269          $isincludesetting = (strpos($setting->get_name(), '_include') !== false);
 270          if ($isincludesetting && $setting->get_level() != backup_setting::ROOT_LEVEL) {
 271              switch ($setting->get_level()) {
 272                  case backup_setting::COURSE_LEVEL:
 273                      if ($this->activitydiv) {
 274                          $this->_form->addElement('html', html_writer::end_tag('div'));
 275                          $this->activitydiv = false;
 276                      }
 277                      if ($this->sectiondiv) {
 278                          $this->_form->addElement('html', html_writer::end_tag('div'));
 279                          $this->sectiondiv = false;
 280                      }
 281                      if ($this->coursediv) {
 282                          $this->_form->addElement('html', html_writer::end_tag('div'));
 283                      }
 284                      $mform->addElement('html', html_writer::start_tag('div', array('class' => 'grouped_settings course_level')));
 285                      $mform->addElement('html', html_writer::start_tag('div', array('class' => 'include_setting course_level')));
 286                      $this->coursediv = true;
 287                      break;
 288                  case backup_setting::SECTION_LEVEL:
 289                      if ($this->activitydiv) {
 290                          $this->_form->addElement('html', html_writer::end_tag('div'));
 291                          $this->activitydiv = false;
 292                      }
 293                      if ($this->sectiondiv) {
 294                          $this->_form->addElement('html', html_writer::end_tag('div'));
 295                      }
 296                      $mform->addElement('html', html_writer::start_tag('div', array('class' => 'grouped_settings section_level')));
 297                      $mform->addElement('html', html_writer::start_tag('div', array('class' => 'include_setting section_level')));
 298                      $this->sectiondiv = true;
 299                      break;
 300                  case backup_setting::ACTIVITY_LEVEL:
 301                      if ($this->activitydiv) {
 302                          $this->_form->addElement('html', html_writer::end_tag('div'));
 303                      }
 304                      $mform->addElement('html', html_writer::start_tag('div', array('class' => 'grouped_settings activity_level')));
 305                      $mform->addElement('html', html_writer::start_tag('div', array('class' => 'include_setting activity_level')));
 306                      $this->activitydiv = true;
 307                      break;
 308                  default:
 309                      $mform->addElement('html', html_writer::start_tag('div', array('class' => 'normal_setting')));
 310                      break;
 311              }
 312          } else if ($setting->get_level() == backup_setting::ROOT_LEVEL) {
 313              $mform->addElement('html', html_writer::start_tag('div', array('class' => 'root_setting')));
 314          } else {
 315              $mform->addElement('html', html_writer::start_tag('div', array('class' => 'normal_setting')));
 316          }
 317      }
 318  
 319      /**
 320       * Adds a fixed or static setting to the form
 321       * @param backup_setting $setting
 322       * @param base_task $task
 323       */
 324      public function add_fixed_setting(backup_setting $setting, base_task $task) {
 325          global $OUTPUT;
 326          $settingui = $setting->get_ui();
 327          if ($setting->get_visibility() == backup_setting::VISIBLE) {
 328              $this->add_html_formatting($setting);
 329              switch ($setting->get_status()) {
 330                  case backup_setting::LOCKED_BY_PERMISSION:
 331                      $icon = ' '.$OUTPUT->pix_icon('i/permissionlock', get_string('lockedbypermission', 'backup'), 'moodle',
 332                              array('class' => 'smallicon lockedicon permissionlock'));
 333                      break;
 334                  case backup_setting::LOCKED_BY_CONFIG:
 335                      $icon = ' '.$OUTPUT->pix_icon('i/configlock', get_string('lockedbyconfig', 'backup'), 'moodle',
 336                              array('class' => 'smallicon lockedicon configlock'));
 337                      break;
 338                  case backup_setting::LOCKED_BY_HIERARCHY:
 339                      $icon = ' '.$OUTPUT->pix_icon('i/hierarchylock', get_string('lockedbyhierarchy', 'backup'), 'moodle',
 340                              array('class' => 'smallicon lockedicon configlock'));
 341                      break;
 342                  default:
 343                      $icon = '';
 344                      break;
 345              }
 346              $context = context_course::instance($task->get_courseid());
 347              $label = format_string($settingui->get_label($task), true, array('context' => $context));
 348              $labelicon = $settingui->get_icon();
 349              if (!empty($labelicon)) {
 350                  $label .= $OUTPUT->render($labelicon);
 351              }
 352              $this->_form->addElement('static', 'static_'.$settingui->get_name(), $label, $settingui->get_static_value().$icon);
 353              $this->_form->addElement('html', html_writer::end_tag('div'));
 354          }
 355          $this->_form->addElement('hidden', $settingui->get_name(), $settingui->get_value());
 356          $this->_form->setType($settingui->get_name(), $settingui->get_param_validation());
 357      }
 358  
 359      /**
 360       * Adds dependencies to the form recursively
 361       *
 362       * @param backup_setting $setting
 363       */
 364      public function add_dependencies(backup_setting $setting) {
 365          $mform = $this->_form;
 366          // Apply all dependencies for backup.
 367          foreach ($setting->get_my_dependency_properties() as $key => $dependency) {
 368              call_user_func_array(array($this->_form, 'disabledIf'), array_values($dependency));
 369          }
 370      }
 371  
 372      /**
 373       * Returns true if the form was cancelled, false otherwise
 374       * @return bool
 375       */
 376      public function is_cancelled() {
 377          return (optional_param('cancel', false, PARAM_BOOL) || parent::is_cancelled());
 378      }
 379  
 380      /**
 381       * Removes an element from the form if it exists
 382       * @param string $elementname
 383       * @return bool
 384       */
 385      public function remove_element($elementname) {
 386          if ($this->_form->elementExists($elementname)) {
 387              return $this->_form->removeElement($elementname);
 388          } else {
 389              return false;
 390          }
 391      }
 392  
 393      /**
 394       * Gets an element from the form if it exists
 395       *
 396       * @param string $elementname
 397       * @return HTML_QuickForm_input|MoodleQuickForm_group
 398       */
 399      public function get_element($elementname) {
 400          if ($this->_form->elementExists($elementname)) {
 401              return $this->_form->getElement($elementname);
 402          } else {
 403              return false;
 404          }
 405      }
 406  
 407      /**
 408       * Displays the form
 409       */
 410      public function display() {
 411          global $PAGE, $COURSE;
 412  
 413          $this->require_definition_after_data();
 414  
 415          // Get list of module types on course.
 416          $modinfo = get_fast_modinfo($COURSE);
 417          $modnames = array_map('strval', $modinfo->get_used_module_names(true));
 418          core_collator::asort($modnames);
 419          $PAGE->requires->yui_module('moodle-backup-backupselectall', 'M.core_backup.backupselectall',
 420                  array($modnames));
 421          $PAGE->requires->strings_for_js(array('select', 'all', 'none'), 'moodle');
 422          $PAGE->requires->strings_for_js(array('showtypes', 'hidetypes'), 'backup');
 423  
 424          parent::display();
 425      }
 426  
 427      /**
 428       * Ensures the the definition after data is loaded
 429       */
 430      public function require_definition_after_data() {
 431          if (!$this->_definition_finalized) {
 432              $this->definition_after_data();
 433          }
 434      }
 435  }