Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.
/mod/data/ -> field.php (source)

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

   1  <?php
   2  
   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/>.
  17  
  18  /**
  19   * This file is part of the Database module for Moodle
  20   *
  21   * @copyright 2005 Martin Dougiamas  http://dougiamas.com
  22   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   * @package mod_data
  24   */
  25  
  26  use core\notification;
  27  use mod_data\local\importer\preset_existing_importer;
  28  use mod_data\local\importer\preset_importer;
  29  use mod_data\local\importer\preset_upload_importer;
  30  use mod_data\manager;
  31  
  32  require_once('../../config.php');
  33  require_once ('lib.php');
  34  require_once($CFG->dirroot.'/mod/data/preset_form.php');
  35  
  36  $id             = optional_param('id', 0, PARAM_INT);            // course module id
  37  $d              = optional_param('d', 0, PARAM_INT);             // database id
  38  $fid            = optional_param('fid', 0 , PARAM_INT);          // update field id
  39  $newtype        = optional_param('newtype','',PARAM_ALPHA);      // type of the new field
  40  $mode           = optional_param('mode','',PARAM_ALPHA);
  41  $action         = optional_param('action', '', PARAM_ALPHA);
  42  $fullname       = optional_param('fullname', '', PARAM_PATH);    // Directory the preset is in.
  43  $defaultsort    = optional_param('defaultsort', 0, PARAM_INT);
  44  $defaultsortdir = optional_param('defaultsortdir', 0, PARAM_INT);
  45  $cancel         = optional_param('cancel', 0, PARAM_BOOL);
  46  
  47  if ($cancel) {
  48      $mode = 'list';
  49  }
  50  
  51  $url = new moodle_url('/mod/data/field.php');
  52  if ($fid !== 0) {
  53      $url->param('fid', $fid);
  54  }
  55  if ($newtype !== '') {
  56      $url->param('newtype', $newtype);
  57  }
  58  if ($mode !== '') {
  59      $url->param('mode', $mode);
  60  }
  61  if ($defaultsort !== 0) {
  62      $url->param('defaultsort', $defaultsort);
  63  }
  64  if ($defaultsortdir !== 0) {
  65      $url->param('defaultsortdir', $defaultsortdir);
  66  }
  67  if ($cancel !== 0) {
  68      $url->param('cancel', $cancel);
  69  }
  70  if ($action !== '') {
  71      $url->param('action', $action);
  72  }
  73  
  74  if ($id) {
  75      list($course, $cm) = get_course_and_cm_from_cmid($id, manager::MODULE);
  76      $manager = manager::create_from_coursemodule($cm);
  77      $url->param('id', $cm->id);
  78  } else {   // We must have $d.
  79      $instance = $DB->get_record('data', ['id' => $d], '*', MUST_EXIST);
  80      $manager = manager::create_from_instance($instance);
  81      $cm = $manager->get_coursemodule();
  82      $course = get_course($cm->course);
  83      $url->param('d', $d);
  84  }
  85  
  86  $PAGE->set_url($url);
  87  $data = $manager->get_instance();
  88  $context = $manager->get_context();
  89  
  90  require_login($course, true, $cm);
  91  require_capability('mod/data:managetemplates', $context);
  92  
  93  $actionbar = new \mod_data\output\action_bar($data->id, $PAGE->url);
  94  
  95  $PAGE->add_body_class('mediumwidth');
  96  $PAGE->set_heading($course->fullname);
  97  $PAGE->activityheader->disable();
  98  
  99  // Fill in missing properties needed for updating of instance.
 100  $data->course     = $cm->course;
 101  $data->cmidnumber = $cm->idnumber;
 102  $data->instance   = $cm->instance;
 103  
 104  /************************************
 105   *        Data Processing           *
 106   ***********************************/
 107  $renderer = $manager->get_renderer();
 108  
 109  if ($action == 'finishimport' && confirm_sesskey()) {
 110      $overwritesettings = optional_param('overwritesettings', false, PARAM_BOOL);
 111      $importer = preset_importer::create_from_parameters($manager);
 112      $importer->finish_import_process($overwritesettings, $data);
 113  }
 114  
 115  switch ($mode) {
 116  
 117      case 'add':    ///add a new field
 118          if (confirm_sesskey() and $fieldinput = data_submitted()){
 119  
 120              //$fieldinput->name = data_clean_field_name($fieldinput->name);
 121  
 122          /// Only store this new field if it doesn't already exist.
 123              if (($fieldinput->name == '') or data_fieldname_exists($fieldinput->name, $data->id)) {
 124  
 125                  $displaynoticebad = get_string('invalidfieldname','data');
 126  
 127              } else {
 128  
 129              /// Check for arrays and convert to a comma-delimited string
 130                  data_convert_arrays_to_strings($fieldinput);
 131  
 132              /// Create a field object to collect and store the data safely
 133                  $type = required_param('type', PARAM_FILE);
 134                  $field = data_get_field_new($type, $data);
 135  
 136                  if (!empty($validationerrors = $field->validate($fieldinput))) {
 137                      $displaynoticebad = html_writer::alist($validationerrors);
 138                      $mode = 'new';
 139                      $newtype = $type;
 140                      break;
 141                  }
 142  
 143                  $field->define_field($fieldinput);
 144                  $field->insert_field();
 145  
 146              /// Update some templates
 147                  data_append_new_field_to_templates($data, $fieldinput->name);
 148  
 149                  $displaynoticegood = get_string('fieldadded','data');
 150              }
 151          }
 152          break;
 153  
 154  
 155      case 'update':    ///update a field
 156          if (confirm_sesskey() and $fieldinput = data_submitted()){
 157  
 158              //$fieldinput->name = data_clean_field_name($fieldinput->name);
 159  
 160              if (($fieldinput->name == '') or data_fieldname_exists($fieldinput->name, $data->id, $fieldinput->fid)) {
 161  
 162                  $displaynoticebad = get_string('invalidfieldname','data');
 163  
 164              } else {
 165              /// Check for arrays and convert to a comma-delimited string
 166                  data_convert_arrays_to_strings($fieldinput);
 167  
 168              /// Create a field object to collect and store the data safely
 169                  $field = data_get_field_from_id($fid, $data);
 170                  if (!empty($validationerrors = $field->validate($fieldinput))) {
 171                      $displaynoticebad = html_writer::alist($validationerrors);
 172                      $mode = 'display';
 173                      break;
 174                  }
 175                  $oldfieldname = $field->field->name;
 176  
 177                  $field->field->name = $fieldinput->name;
 178                  $field->field->description = $fieldinput->description;
 179                  $field->field->required = !empty($fieldinput->required) ? 1 : 0;
 180  
 181                  for ($i=1; $i<=10; $i++) {
 182                      if (isset($fieldinput->{'param'.$i})) {
 183                          $field->field->{'param'.$i} = $fieldinput->{'param'.$i};
 184                      } else {
 185                          $field->field->{'param'.$i} = '';
 186                      }
 187                  }
 188  
 189                  $field->update_field();
 190  
 191              /// Update the templates.
 192                  data_replace_field_in_templates($data, $oldfieldname, $field->field->name);
 193  
 194                  $displaynoticegood = get_string('fieldupdated','data');
 195              }
 196          }
 197          break;
 198  
 199  
 200      case 'delete':    // Delete a field
 201          if (confirm_sesskey()){
 202  
 203              if ($confirm = optional_param('confirm', 0, PARAM_INT)) {
 204  
 205  
 206                  // Delete the field completely
 207                  if ($field = data_get_field_from_id($fid, $data)) {
 208                      $field->delete_field();
 209  
 210                      // Update the templates.
 211                      data_replace_field_in_templates($data, $field->field->name, '');
 212  
 213                      // Update the default sort field
 214                      if ($fid == $data->defaultsort) {
 215                          $rec = new stdClass();
 216                          $rec->id = $data->id;
 217                          $rec->defaultsort = 0;
 218                          $rec->defaultsortdir = 0;
 219                          $DB->update_record('data', $rec);
 220                      }
 221  
 222                      $displaynoticegood = get_string('fielddeleted', 'data');
 223                  }
 224  
 225              } else {
 226                  $titleparts = [
 227                      get_string('deletefield', 'data'),
 228                      format_string($data->name),
 229                      format_string($course->fullname),
 230                  ];
 231                  $PAGE->set_title(implode(moodle_page::TITLE_SEPARATOR, $titleparts));
 232                  data_print_header($course,$cm,$data, false);
 233                  echo $OUTPUT->heading(get_string('deletefield', 'data'), 2, 'mb-4');
 234  
 235                  // Print confirmation message.
 236                  $field = data_get_field_from_id($fid, $data);
 237  
 238                  if ($field->type === 'unknown') {
 239                      $fieldtypename = get_string('unknown', 'data');
 240                  } else {
 241                      $fieldtypename = $field->name();
 242                  }
 243                  echo $OUTPUT->confirm('<strong>' . $fieldtypename . ': ' . $field->field->name . '</strong><br /><br />' .
 244                          get_string('confirmdeletefield', 'data'),
 245                          'field.php?d=' . $data->id . '&mode=delete&fid=' . $fid . '&confirm=1',
 246                          'field.php?d=' . $data->id,
 247                          ['type' => single_button::BUTTON_DANGER]);
 248  
 249                  echo $OUTPUT->footer();
 250                  exit;
 251              }
 252          }
 253          break;
 254  
 255  
 256      case 'sort':    // Set the default sort parameters
 257          if (confirm_sesskey()) {
 258              $rec = new stdClass();
 259              $rec->id = $data->id;
 260              $rec->defaultsort = $defaultsort;
 261              $rec->defaultsortdir = $defaultsortdir;
 262  
 263              $DB->update_record('data', $rec);
 264              redirect($CFG->wwwroot.'/mod/data/field.php?d='.$data->id, get_string('changessaved'), 2);
 265              exit;
 266          }
 267          break;
 268  
 269      case 'usepreset':
 270          $importer = preset_importer::create_from_parameters($manager);
 271          if (!$importer->needs_mapping() || $action == 'notmapping') {
 272              $backurl = new moodle_url('/mod/data/field.php', ['id' => $cm->id]);
 273              if ($importer->import(false)) {
 274                  notification::success(get_string('importsuccess', 'mod_data'));
 275              } else {
 276                  notification::error(get_string('cannotapplypreset', 'mod_data'));
 277              }
 278              redirect($backurl);
 279          }
 280          $PAGE->navbar->add(get_string('usestandard', 'data'));
 281          $fieldactionbar = $actionbar->get_fields_mapping_action_bar();
 282          data_print_header($course, $cm, $data, false, $fieldactionbar);
 283          $importer = new preset_existing_importer($manager, $fullname);
 284          echo $renderer->importing_preset($data, $importer);
 285          echo $OUTPUT->footer();
 286          exit;
 287  
 288      default:
 289          break;
 290  }
 291  
 292  
 293  
 294  /// Print the browsing interface
 295  
 296  ///get the list of possible fields (plugins)
 297  $plugins = core_component::get_plugin_list('datafield');
 298  $menufield = array();
 299  
 300  foreach ($plugins as $plugin=>$fulldir){
 301      if (!is_dir($fulldir)) {
 302          continue;
 303      }
 304      $menufield[$plugin] = get_string('pluginname', 'datafield_'.$plugin);    //get from language files
 305  }
 306  asort($menufield);    //sort in alphabetical order
 307  $PAGE->force_settings_menu(true);
 308  
 309  $PAGE->set_pagetype('mod-data-field-' . $newtype);
 310  $titleparts = [
 311      format_string($data->name),
 312      format_string($course->fullname),
 313  ];
 314  if (($mode == 'new') && (!empty($newtype))) { // Adding a new field.
 315      array_unshift($titleparts, get_string('newfield', 'data'));
 316      $PAGE->set_title(implode(moodle_page::TITLE_SEPARATOR, $titleparts));
 317      data_print_header($course, $cm, $data, 'fields');
 318      echo $OUTPUT->heading(get_string('newfield', 'data'));
 319  
 320      $field = data_get_field_new($newtype, $data);
 321      $field->display_edit_field();
 322  
 323  } else if ($mode == 'display' && confirm_sesskey()) { /// Display/edit existing field
 324      array_unshift($titleparts, get_string('editfield', 'data'));
 325      $PAGE->set_title(implode(moodle_page::TITLE_SEPARATOR, $titleparts));
 326      data_print_header($course, $cm, $data, 'fields');
 327      echo $OUTPUT->heading(get_string('editfield', 'data'));
 328  
 329      $field = data_get_field_from_id($fid, $data);
 330      $field->display_edit_field();
 331  
 332  } else {                                              /// Display the main listing of all fields
 333      array_unshift($titleparts, get_string('managefields', 'data'));
 334      $PAGE->set_title(implode(moodle_page::TITLE_SEPARATOR, $titleparts));
 335      $hasfields = $manager->has_fields();
 336      // Check if it is an empty database with no fields.
 337      if (!$hasfields) {
 338          echo $OUTPUT->header();
 339          echo $renderer->render_fields_zero_state($manager);
 340          echo $OUTPUT->footer();
 341          // Don't check the rest of the options. There is no field, there is nothing else to work with.
 342          exit;
 343      }
 344      $fieldactionbar = $actionbar->get_fields_action_bar(true);
 345      data_print_header($course, $cm, $data, 'fields', $fieldactionbar);
 346  
 347      echo $OUTPUT->box_start();
 348      echo get_string('fieldshelp', 'data');
 349      echo $OUTPUT->box_end();
 350      echo $OUTPUT->box_start('d-flex flex-row-reverse');
 351      echo $OUTPUT->render($actionbar->get_create_fields(true));
 352      echo $OUTPUT->box_end();
 353      $table = new html_table();
 354      $table->head = [
 355          get_string('fieldname', 'data'),
 356          get_string('type', 'data'),
 357          get_string('required', 'data'),
 358          get_string('fielddescription', 'data'),
 359          '&nbsp;',
 360      ];
 361      $table->align = ['left', 'left', 'left', 'left'];
 362      $table->wrap = [false,false,false,false];
 363      $table->responsive = false;
 364  
 365      $fieldrecords = $manager->get_field_records();
 366      $missingfieldtypes = [];
 367      foreach ($fieldrecords as $fieldrecord) {
 368  
 369          $field = data_get_field($fieldrecord, $data);
 370  
 371          $baseurl = new moodle_url('/mod/data/field.php', array(
 372              'd'         => $data->id,
 373              'fid'       => $field->field->id,
 374              'sesskey'   => sesskey(),
 375          ));
 376  
 377          $displayurl = new moodle_url($baseurl, array(
 378              'mode'      => 'display',
 379          ));
 380  
 381          $deleteurl = new moodle_url($baseurl, array(
 382              'mode'      => 'delete',
 383          ));
 384  
 385          $actionmenu = new action_menu();
 386          $actionmenu->set_kebab_trigger();
 387          $actionmenu->set_action_label(get_string('actions'));
 388          $actionmenu->set_additional_classes('fields-actions');
 389  
 390          // It display a notification when the field type does not exist.
 391          if ($field->type === 'unknown') {
 392              $missingfieldtypes[] = $field->field->name;
 393              $fieltypedata = $field->field->type;
 394          } else {
 395              $fieltypedata = $field->image() . '&nbsp;' . $field->name();
 396              // Edit icon, only displayed when the field type is known.
 397              $actionmenu->add(new action_menu_link_secondary(
 398                  $displayurl,
 399                  null,
 400                  get_string('edit'),
 401              ));
 402          }
 403  
 404          // Delete.
 405          $actionmenu->add(new action_menu_link_secondary(
 406              $deleteurl,
 407              null,
 408              get_string('delete'),
 409          ));
 410          $actionmenutemplate = $actionmenu->export_for_template($OUTPUT);
 411  
 412          $table->data[] = [
 413              $field->field->name,
 414              $fieltypedata,
 415              $field->field->required ? get_string('yes') : get_string('no'),
 416              shorten_text($field->field->description, 30),
 417              $OUTPUT->render_from_template('core/action_menu', $actionmenutemplate)
 418          ];
 419  
 420          if (!empty($missingfieldtypes)) {
 421              echo $OUTPUT->notification(get_string('missingfieldtypes', 'data') . html_writer::alist($missingfieldtypes));
 422          }
 423      }
 424      echo html_writer::table($table);
 425  
 426      echo '<div class="sortdefault">';
 427      echo '<form id="sortdefault" action="'.$CFG->wwwroot.'/mod/data/field.php" method="get">';
 428      echo '<div>';
 429      echo '<input type="hidden" name="d" value="'.$data->id.'" />';
 430      echo '<input type="hidden" name="mode" value="sort" />';
 431      echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
 432      echo '<label for="defaultsort">'.get_string('defaultsortfield','data').'</label>';
 433      echo '<select id="defaultsort" name="defaultsort" class="custom-select">';
 434      if ($fields = $DB->get_records('data_fields', array('dataid'=>$data->id))) {
 435          echo '<optgroup label="'.get_string('fields', 'data').'">';
 436          foreach ($fields as $field) {
 437              if ($data->defaultsort == $field->id) {
 438                  echo '<option value="'.$field->id.'" selected="selected">'.$field->name.'</option>';
 439              } else {
 440                  echo '<option value="'.$field->id.'">'.$field->name.'</option>';
 441              }
 442          }
 443          echo '</optgroup>';
 444      }
 445      $options = array();
 446      $options[DATA_TIMEADDED]    = get_string('timeadded', 'data');
 447  // TODO: we will need to change defaultsort db to unsinged to make these work in 2.0
 448  /*        $options[DATA_TIMEMODIFIED] = get_string('timemodified', 'data');
 449      $options[DATA_FIRSTNAME]    = get_string('authorfirstname', 'data');
 450      $options[DATA_LASTNAME]     = get_string('authorlastname', 'data');
 451      if ($data->approval and has_capability('mod/data:approve', $context)) {
 452          $options[DATA_APPROVED] = get_string('approved', 'data');
 453      }*/
 454      echo '<optgroup label="'.get_string('other', 'data').'">';
 455      foreach ($options as $key => $name) {
 456          if ($data->defaultsort == $key) {
 457              echo '<option value="'.$key.'" selected="selected">'.$name.'</option>';
 458          } else {
 459              echo '<option value="'.$key.'">'.$name.'</option>';
 460          }
 461      }
 462      echo '</optgroup>';
 463      echo '</select>';
 464  
 465      $options = array(0 => get_string('ascending', 'data'),
 466                       1 => get_string('descending', 'data'));
 467      echo html_writer::label(get_string('sortby'), 'menudefaultsortdir', false, array('class' => 'accesshide'));
 468      echo html_writer::select($options, 'defaultsortdir', $data->defaultsortdir, false, array('class' => 'custom-select'));
 469      echo '<input type="submit" class="btn btn-secondary ml-1" value="'.get_string('save', 'data').'" />';
 470      echo '</div>';
 471      echo '</form>';
 472  
 473      // Add a sticky footer.
 474      echo $renderer->render_fields_footer($manager);
 475  
 476      echo '</div>';
 477  }
 478  
 479  /// Finish the page
 480  echo $OUTPUT->footer();