Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

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

   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   * @package    tool_xmldb
  19   * @copyright  2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  20   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  21   */
  22  
  23  /**
  24   * This class verifies all the data introduced when editing a field for correctness,
  25   * performing changes / displaying errors depending of the results.
  26   *
  27   * @package    tool_xmldb
  28   * @copyright  2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  29   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  30   */
  31  class edit_field_save extends XMLDBAction {
  32  
  33      /**
  34       * Init method, every subclass will have its own
  35       */
  36      function init() {
  37          parent::init();
  38  
  39          // Set own custom attributes
  40  
  41          // Get needed strings
  42          $this->loadStrings(array(
  43              'fieldnameempty' => 'tool_xmldb',
  44              'incorrectfieldname' => 'tool_xmldb',
  45              'duplicatefieldname' => 'tool_xmldb',
  46              'integerincorrectlength' => 'tool_xmldb',
  47              'numberincorrectlength' => 'tool_xmldb',
  48              'floatincorrectlength' => 'tool_xmldb',
  49              'charincorrectlength' => 'tool_xmldb',
  50              'numberincorrectdecimals' => 'tool_xmldb',
  51              'numberincorrectwholepart' => 'tool_xmldb',
  52              'floatincorrectdecimals' => 'tool_xmldb',
  53              'defaultincorrect' => 'tool_xmldb',
  54              'back' => 'tool_xmldb',
  55              'administration' => ''
  56          ));
  57      }
  58  
  59      /**
  60       * Invoke method, every class will have its own
  61       * returns true/false on completion, setting both
  62       * errormsg and output as necessary
  63       */
  64      function invoke() {
  65          parent::invoke();
  66  
  67          $result = true;
  68  
  69          // Set own core attributes
  70          //$this->does_generate = ACTION_NONE;
  71          $this->does_generate = ACTION_GENERATE_HTML;
  72  
  73          // These are always here
  74          global $CFG, $XMLDB;
  75  
  76          // Do the job, setting result as needed
  77  
  78          if (!data_submitted()) { // Basic prevention
  79              throw new \moodle_exception('wrongcall', 'error');
  80          }
  81  
  82          // Get parameters
  83          $dirpath = required_param('dir', PARAM_PATH);
  84          $dirpath = $CFG->dirroot . $dirpath;
  85  
  86          $tableparam = strtolower(required_param('table', PARAM_PATH));
  87          $fieldparam = strtolower(required_param('field', PARAM_PATH));
  88          $name = substr(trim(strtolower(optional_param('name', $fieldparam, PARAM_PATH))),0,xmldb_field::NAME_MAX_LENGTH);
  89  
  90          $comment = required_param('comment', PARAM_CLEAN);
  91          $comment = trim($comment);
  92  
  93          $type       = required_param('type', PARAM_INT);
  94          $length     = strtolower(optional_param('length', NULL, PARAM_ALPHANUM));
  95          $decimals   = optional_param('decimals', NULL, PARAM_INT);
  96          $notnull    = optional_param('notnull', false, PARAM_BOOL);
  97          $sequence   = optional_param('sequence', false, PARAM_BOOL);
  98          $default    = optional_param('default', NULL, PARAM_PATH);
  99          $default    = trim($default);
 100  
 101          $editeddir = $XMLDB->editeddirs[$dirpath];
 102          $structure = $editeddir->xml_file->getStructure();
 103          $table = $structure->getTable($tableparam);
 104          $field = $table->getField($fieldparam);
 105          $oldhash = $field->getHash();
 106  
 107          $errors = array(); // To store all the errors found
 108  
 109          // Perform some automatic assumptions
 110          if ($sequence) {
 111              $notnull  = true;
 112              $default  = NULL;
 113          }
 114          if ($type != XMLDB_TYPE_NUMBER && $type != XMLDB_TYPE_FLOAT) {
 115              $decimals = NULL;
 116          }
 117          if ($type == XMLDB_TYPE_BINARY) {
 118              $default = NULL;
 119          }
 120          if ($default === '') {
 121              $default = NULL;
 122          }
 123  
 124          // Perform some checks
 125          // Check empty name
 126          if (empty($name)) {
 127              $errors[] = $this->str['fieldnameempty'];
 128          }
 129          // Check incorrect name
 130          if ($name == 'changeme') {
 131              $errors[] = $this->str['incorrectfieldname'];
 132          }
 133          // Check duplicate name
 134          if ($fieldparam != $name && $table->getField($name)) {
 135              $errors[] = $this->str['duplicatefieldname'];
 136          }
 137          // Integer checks
 138          if ($type == XMLDB_TYPE_INTEGER) {
 139              if (!(is_numeric($length) && !empty($length) && intval($length)==floatval($length) &&
 140                    $length > 0 && $length <= xmldb_field::INTEGER_MAX_LENGTH)) {
 141                  $errors[] = $this->str['integerincorrectlength'];
 142              }
 143              if (!(empty($default) || (is_numeric($default) &&
 144                                         !empty($default) &&
 145                                         intval($default)==floatval($default)))) {
 146                  $errors[] = $this->str['defaultincorrect'];
 147              }
 148          }
 149          // Number checks
 150          if ($type == XMLDB_TYPE_NUMBER) {
 151              if (!(is_numeric($length) && !empty($length) && intval($length)==floatval($length) &&
 152                    $length > 0 && $length <= xmldb_field::NUMBER_MAX_LENGTH)) {
 153                  $errors[] = $this->str['numberincorrectlength'];
 154              }
 155              if (!(empty($decimals) || (is_numeric($decimals) &&
 156                                         !empty($decimals) &&
 157                                         intval($decimals)==floatval($decimals) &&
 158                                         $decimals >= 0 &&
 159                                         $decimals < $length))) {
 160                  $errors[] = $this->str['numberincorrectdecimals'];
 161              }
 162              if (!empty($decimals) && ($length - $decimals > xmldb_field::INTEGER_MAX_LENGTH)) {
 163                  $errors[] = $this->str['numberincorrectwholepart'];
 164              }
 165              if (!(empty($default) || (is_numeric($default) &&
 166                                         !empty($default)))) {
 167                  $errors[] = $this->str['defaultincorrect'];
 168              }
 169          }
 170          // Float checks
 171          if ($type == XMLDB_TYPE_FLOAT) {
 172              if (!(empty($length) || (is_numeric($length) &&
 173                                       !empty($length) &&
 174                                       intval($length)==floatval($length) &&
 175                                       $length > 0 &&
 176                                       $length <= xmldb_field::FLOAT_MAX_LENGTH))) {
 177                  $errors[] = $this->str['floatincorrectlength'];
 178              }
 179              if (!(empty($decimals) || (is_numeric($decimals) &&
 180                                         !empty($decimals) &&
 181                                         intval($decimals)==floatval($decimals) &&
 182                                         $decimals >= 0 &&
 183                                         $decimals < $length))) {
 184                  $errors[] = $this->str['floatincorrectdecimals'];
 185              }
 186              if (!(empty($default) || (is_numeric($default) &&
 187                                         !empty($default)))) {
 188                  $errors[] = $this->str['defaultincorrect'];
 189              }
 190          }
 191          // Char checks
 192          if ($type == XMLDB_TYPE_CHAR) {
 193              if (!(is_numeric($length) && !empty($length) && intval($length)==floatval($length) &&
 194                    $length > 0 && $length <= xmldb_field::CHAR_MAX_LENGTH)) {
 195                  $errors[] = $this->str['charincorrectlength'];
 196              }
 197              if ($default !== NULL && $default !== '') {
 198                  if (substr($default, 0, 1) == "'" ||
 199                      substr($default, -1, 1) == "'") {
 200                      $errors[] = $this->str['defaultincorrect'];
 201                  }
 202              }
 203          }
 204          // No text checks
 205          // No binary checks
 206  
 207          if (!empty($errors)) {
 208              $tempfield = new xmldb_field($name);
 209              $tempfield->setType($type);
 210              $tempfield->setLength($length);
 211              $tempfield->setDecimals($decimals);
 212              $tempfield->setNotNull($notnull);
 213              $tempfield->setSequence($sequence);
 214              $tempfield->setDefault($default);
 215              // Prepare the output
 216              $o = '<p>' .implode(', ', $errors) . '</p>
 217                    <p>' . $name . ': ' . $tempfield->readableInfo() . '</p>';
 218              $o.= '<a href="index.php?action=edit_field&amp;field=' . $field->getName() . '&amp;table=' . $table->getName() .
 219                   '&amp;dir=' . urlencode(str_replace($CFG->dirroot, '', $dirpath)) . '">[' . $this->str['back'] . ']</a>';
 220              $this->output = $o;
 221          }
 222  
 223          // Continue if we aren't under errors
 224          if (empty($errors)) {
 225              // If there is one name change, do it, changing the prev and next
 226              // atributes of the adjacent fields
 227              if ($fieldparam != $name) {
 228                  $field->setName($name);
 229                  if ($field->getPrevious()) {
 230                      $prev = $table->getField($field->getPrevious());
 231                      $prev->setNext($name);
 232                      $prev->setChanged(true);
 233                  }
 234                  if ($field->getNext()) {
 235                      $next = $table->getField($field->getNext());
 236                      $next->setPrevious($name);
 237                      $next->setChanged(true);
 238                  }
 239              }
 240  
 241              // Set comment
 242              $field->setComment($comment);
 243  
 244              // Set the rest of fields
 245              $field->setType($type);
 246              $field->setLength($length);
 247              $field->setDecimals($decimals);
 248              $field->setNotNull($notnull);
 249              $field->setSequence($sequence);
 250              $field->setDefault($default);
 251  
 252              // If the hash has changed from the old one, change the version
 253              // and mark the structure as changed
 254              $field->calculateHash(true);
 255              if ($oldhash != $field->getHash()) {
 256                  $field->setChanged(true);
 257                  $table->setChanged(true);
 258                  // Recalculate the structure hash
 259                  $structure->calculateHash(true);
 260                  $structure->setVersion(userdate(time(), '%Y%m%d', 99, false));
 261                  // Mark as changed
 262                  $structure->setChanged(true);
 263              }
 264  
 265              // Launch postaction if exists (leave this here!)
 266              if ($this->getPostAction() && $result) {
 267                  return $this->launch($this->getPostAction());
 268              }
 269          }
 270  
 271          // Return ok if arrived here
 272          return $result;
 273      }
 274  }
 275