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   * This class represent one XMLDB Key
  19   *
  20   * @package    core_xmldb
  21   * @copyright  1999 onwards Martin Dougiamas     http://dougiamas.com
  22   *             2001-3001 Eloy Lafuente (stronk7) http://contiento.com
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  
  29  class xmldb_key extends xmldb_object {
  30  
  31      /** @var int type of key */
  32      protected $type;
  33  
  34      /** @var array of fields */
  35      protected $fields;
  36  
  37      /** @var string referenced table */
  38      protected $reftable;
  39  
  40      /** @var array referenced fields */
  41      protected $reffields;
  42  
  43      /**
  44       * Creates one new xmldb_key
  45       * @param string $name
  46       * @param string $type XMLDB_KEY_[PRIMARY|UNIQUE|FOREIGN|FOREIGN_UNIQUE]
  47       * @param array $fields an array of fieldnames to build the key over
  48       * @param string $reftable name of the table the FK points to or null
  49       * @param array $reffields an array of fieldnames in the FK table or null
  50       */
  51      public function __construct($name, $type=null, $fields=array(), $reftable=null, $reffields=null) {
  52          $this->type = null;
  53          $this->fields = array();
  54          $this->reftable = null;
  55          $this->reffields = array();
  56          parent::__construct($name);
  57          $this->set_attributes($type, $fields, $reftable, $reffields);
  58      }
  59  
  60      /**
  61       * Set all the attributes of one xmldb_key
  62       *
  63       * @param string $type XMLDB_KEY_[PRIMARY|UNIQUE|FOREIGN|FOREIGN_UNIQUE]
  64       * @param array $fields an array of fieldnames to build the key over
  65       * @param string $reftable name of the table the FK points to or null
  66       * @param array $reffields an array of fieldnames in the FK table or null
  67       */
  68      public function set_attributes($type, $fields, $reftable=null, $reffields=null) {
  69          $this->type = $type;
  70          $this->fields = $fields;
  71          $this->reftable = $reftable;
  72          $this->reffields = empty($reffields) ? array() : $reffields;
  73      }
  74  
  75      /**
  76       * Get the key type
  77       * @return int
  78       */
  79      public function getType() {
  80          return $this->type;
  81      }
  82  
  83      /**
  84       * Set the key type
  85       * @param int $type
  86       */
  87      public function setType($type) {
  88          $this->type = $type;
  89      }
  90  
  91      /**
  92       * Set the key fields
  93       * @param array $fields
  94       */
  95      public function setFields($fields) {
  96          $this->fields = $fields;
  97      }
  98  
  99      /**
 100       * Set the key reftable
 101       * @param string $reftable
 102       */
 103      public function setRefTable($reftable) {
 104          $this->reftable = $reftable;
 105      }
 106  
 107      /**
 108       * Set the key reffields
 109       * @param array $reffields
 110       */
 111      public function setRefFields($reffields) {
 112          $this->reffields = $reffields;
 113      }
 114  
 115      /**
 116       * Get the key fields
 117       * @return array
 118       */
 119      public function getFields() {
 120          return $this->fields;
 121      }
 122  
 123      /**
 124       * Get the key reftable
 125       * @return string
 126       */
 127      public function getRefTable() {
 128          return $this->reftable;
 129      }
 130  
 131      /**
 132       * Get the key reffields
 133       * @return array reference to ref fields
 134       */
 135      public function getRefFields() {
 136          return $this->reffields;
 137      }
 138  
 139      /**
 140       * Load data from XML to the key
 141       * @param array $xmlarr
 142       * @return bool success
 143       */
 144      public function arr2xmldb_key($xmlarr) {
 145  
 146          $result = true;
 147  
 148          // Debug the table
 149          // traverse_xmlize($xmlarr);                   //Debug
 150          // print_object ($GLOBALS['traverse_array']);  //Debug
 151          // $GLOBALS['traverse_array']="";              //Debug
 152  
 153          // Process key attributes (name, type, fields, reftable,
 154          // reffields, comment, previous, next)
 155          if (isset($xmlarr['@']['NAME'])) {
 156              $this->name = trim($xmlarr['@']['NAME']);
 157          } else {
 158              $this->errormsg = 'Missing NAME attribute';
 159              $this->debug($this->errormsg);
 160              $result = false;
 161          }
 162  
 163          if (isset($xmlarr['@']['TYPE'])) {
 164              // Check for valid type
 165              $type = $this->getXMLDBKeyType(trim($xmlarr['@']['TYPE']));
 166              if ($type) {
 167                  $this->type = $type;
 168              } else {
 169                  $this->errormsg = 'Invalid TYPE attribute';
 170                  $this->debug($this->errormsg);
 171                  $result = false;
 172              }
 173          } else {
 174              $this->errormsg = 'Missing TYPE attribute';
 175              $this->debug($this->errormsg);
 176              $result = false;
 177          }
 178  
 179          if (isset($xmlarr['@']['FIELDS'])) {
 180              $fields = strtolower(trim($xmlarr['@']['FIELDS']));
 181              if ($fields) {
 182                  $fieldsarr = explode(',',$fields);
 183                  if ($fieldsarr) {
 184                      foreach ($fieldsarr as $key => $element) {
 185                          $fieldsarr [$key] = trim($element);
 186                      }
 187                  } else {
 188                      $this->errormsg = 'Incorrect FIELDS attribute (comma separated of fields)';
 189                      $this->debug($this->errormsg);
 190                      $result = false;
 191                  }
 192              } else {
 193                  $this->errormsg = 'Empty FIELDS attribute';
 194                  $this->debug($this->errormsg);
 195                  $result = false;
 196              }
 197          } else {
 198              $this->errormsg = 'Missing FIELDS attribute';
 199              $this->debug($this->errormsg);
 200              $result = false;
 201          }
 202          // Finally, set the array of fields
 203          $this->fields = $fieldsarr;
 204  
 205          if (isset($xmlarr['@']['REFTABLE'])) {
 206              // Check we are in a FK
 207              if ($this->type == XMLDB_KEY_FOREIGN ||
 208                  $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
 209                  $reftable = strtolower(trim($xmlarr['@']['REFTABLE']));
 210                  if (!$reftable) {
 211                      $this->errormsg = 'Empty REFTABLE attribute';
 212                      $this->debug($this->errormsg);
 213                      $result = false;
 214                  }
 215              } else {
 216                  $this->errormsg = 'Wrong REFTABLE attribute (only FK can have it)';
 217                  $this->debug($this->errormsg);
 218                  $result = false;
 219              }
 220          } else if ($this->type == XMLDB_KEY_FOREIGN ||
 221                     $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
 222              $this->errormsg = 'Missing REFTABLE attribute';
 223              $this->debug($this->errormsg);
 224              $result = false;
 225          }
 226          // Finally, set the reftable
 227          if ($this->type == XMLDB_KEY_FOREIGN ||
 228              $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
 229              $this->reftable = $reftable;
 230          }
 231  
 232          if (isset($xmlarr['@']['REFFIELDS'])) {
 233              // Check we are in a FK
 234              if ($this->type == XMLDB_KEY_FOREIGN ||
 235                  $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
 236                  $reffields = strtolower(trim($xmlarr['@']['REFFIELDS']));
 237                  if ($reffields) {
 238                      $reffieldsarr = explode(',',$reffields);
 239                      if ($reffieldsarr) {
 240                          foreach ($reffieldsarr as $key => $element) {
 241                              $reffieldsarr [$key] = trim($element);
 242                          }
 243                      } else {
 244                          $this->errormsg = 'Incorrect REFFIELDS attribute (comma separated of fields)';
 245                          $this->debug($this->errormsg);
 246                          $result = false;
 247                      }
 248                  } else {
 249                      $this->errormsg = 'Empty REFFIELDS attribute';
 250                      $this->debug($this->errormsg);
 251                      $result = false;
 252                  }
 253              } else {
 254                  $this->errormsg = 'Wrong REFFIELDS attribute (only FK can have it)';
 255                  $this->debug($this->errormsg);
 256                  $result = false;
 257              }
 258          } else if ($this->type == XMLDB_KEY_FOREIGN ||
 259                     $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
 260              $this->errormsg = 'Missing REFFIELDS attribute';
 261              $this->debug($this->errormsg);
 262              $result = false;
 263          }
 264          // Finally, set the array of reffields
 265          if ($this->type == XMLDB_KEY_FOREIGN ||
 266              $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
 267              $this->reffields = $reffieldsarr;
 268          }
 269  
 270          if (isset($xmlarr['@']['COMMENT'])) {
 271              $this->comment = trim($xmlarr['@']['COMMENT']);
 272          }
 273  
 274          // Set some attributes
 275          if ($result) {
 276              $this->loaded = true;
 277          }
 278          $this->calculateHash();
 279          return $result;
 280      }
 281  
 282      /**
 283       * This function returns the correct XMLDB_KEY_XXX value for the
 284       * string passed as argument
 285       * @param string $type
 286       * @return int
 287       */
 288      public function getXMLDBKeyType($type) {
 289  
 290          $result = XMLDB_KEY_INCORRECT;
 291  
 292          switch (strtolower($type)) {
 293              case 'primary':
 294                  $result = XMLDB_KEY_PRIMARY;
 295                  break;
 296              case 'unique':
 297                  $result = XMLDB_KEY_UNIQUE;
 298                  break;
 299              case 'foreign':
 300                  $result = XMLDB_KEY_FOREIGN;
 301                  break;
 302              case 'foreign-unique':
 303                  $result = XMLDB_KEY_FOREIGN_UNIQUE;
 304                  break;
 305              // case 'check':  //Not supported
 306              //     $result = XMLDB_KEY_CHECK;
 307              //     break;
 308          }
 309          // Return the normalized XMLDB_KEY
 310          return $result;
 311      }
 312  
 313      /**
 314       * This function returns the correct name value for the
 315       * XMLDB_KEY_XXX passed as argument
 316       * @param int $type
 317       * @return string
 318       */
 319      public function getXMLDBKeyName($type) {
 320  
 321          $result = '';
 322  
 323          switch ($type) {
 324              case XMLDB_KEY_PRIMARY:
 325                  $result = 'primary';
 326                  break;
 327              case XMLDB_KEY_UNIQUE:
 328                  $result = 'unique';
 329                  break;
 330              case XMLDB_KEY_FOREIGN:
 331                  $result = 'foreign';
 332                  break;
 333              case XMLDB_KEY_FOREIGN_UNIQUE:
 334                  $result = 'foreign-unique';
 335                  break;
 336              // case XMLDB_KEY_CHECK:  //Not supported
 337              //     $result = 'check';
 338              //     break;
 339          }
 340          // Return the normalized name
 341          return $result;
 342      }
 343  
 344      /**
 345       * This function calculate and set the hash of one xmldb_key
 346       * @param bool $recursive
 347       */
 348       public function calculateHash($recursive = false) {
 349          if (!$this->loaded) {
 350              $this->hash = null;
 351          } else {
 352              $key = $this->type . implode(', ', $this->fields);
 353              if ($this->type == XMLDB_KEY_FOREIGN ||
 354                  $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
 355                  $key .= $this->reftable . implode(', ', $this->reffields);
 356              }
 357                      ;
 358              $this->hash = md5($key);
 359          }
 360      }
 361  
 362      /**
 363       *This function will output the XML text for one key
 364       * @return string
 365       */
 366      public function xmlOutput() {
 367          $o = '';
 368          $o.= '        <KEY NAME="' . $this->name . '"';
 369          $o.= ' TYPE="' . $this->getXMLDBKeyName($this->type) . '"';
 370          $o.= ' FIELDS="' . implode(', ', $this->fields) . '"';
 371          if ($this->type == XMLDB_KEY_FOREIGN ||
 372              $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
 373              $o.= ' REFTABLE="' . $this->reftable . '"';
 374              $o.= ' REFFIELDS="' . implode(', ', $this->reffields) . '"';
 375          }
 376          if ($this->comment) {
 377              $o.= ' COMMENT="' . htmlspecialchars($this->comment, ENT_COMPAT) . '"';
 378          }
 379          $o.= '/>' . "\n";
 380  
 381          return $o;
 382      }
 383  
 384      /**
 385       * This function will set all the attributes of the xmldb_key object
 386       * based on information passed in one ADOkey
 387       * @oaram array $adokey
 388       */
 389      public function setFromADOKey($adokey) {
 390  
 391          // Calculate the XMLDB_KEY
 392          switch (strtolower($adokey['name'])) {
 393              case 'primary':
 394                  $this->type = XMLDB_KEY_PRIMARY;
 395                  break;
 396              default:
 397                  $this->type = XMLDB_KEY_UNIQUE;
 398          }
 399          // Set the fields, converting all them to lowercase
 400          $fields = array_flip(array_change_key_case(array_flip($adokey['columns'])));
 401          $this->fields = $fields;
 402          // Some more fields
 403          $this->loaded = true;
 404          $this->changed = true;
 405      }
 406  
 407      /**
 408       * Returns the PHP code needed to define one xmldb_key
 409       * @return string
 410       */
 411      public function getPHP() {
 412  
 413          $result = '';
 414  
 415          // The type
 416          switch ($this->getType()) {
 417              case XMLDB_KEY_PRIMARY:
 418                  $result .= 'XMLDB_KEY_PRIMARY' . ', ';
 419                  break;
 420              case XMLDB_KEY_UNIQUE:
 421                  $result .= 'XMLDB_KEY_UNIQUE' . ', ';
 422                  break;
 423              case XMLDB_KEY_FOREIGN:
 424                  $result .= 'XMLDB_KEY_FOREIGN' . ', ';
 425                  break;
 426              case XMLDB_KEY_FOREIGN_UNIQUE:
 427                  $result .= 'XMLDB_KEY_FOREIGN_UNIQUE' . ', ';
 428                  break;
 429          }
 430          // The fields
 431          $keyfields = $this->getFields();
 432          if (!empty($keyfields)) {
 433              $result .= "['".  implode("', '", $keyfields) . "']";
 434          } else {
 435              $result .= 'null';
 436          }
 437          // The FKs attributes
 438          if ($this->getType() == XMLDB_KEY_FOREIGN ||
 439              $this->getType() == XMLDB_KEY_FOREIGN_UNIQUE) {
 440              // The reftable
 441              $reftable = $this->getRefTable();
 442              if (!empty($reftable)) {
 443                  $result .= ", '" . $reftable . "', ";
 444              } else {
 445                  $result .= 'null, ';
 446              }
 447              // The reffields
 448              $reffields = $this->getRefFields();
 449              if (!empty($reffields)) {
 450                  $result .= "['".  implode("', '", $reffields) . "']";
 451              } else {
 452                  $result .= 'null';
 453              }
 454          }
 455          // Return result
 456          return $result;
 457      }
 458  
 459      /**
 460       * Shows info in a readable format
 461       * @return string
 462       */
 463      public function readableInfo() {
 464          $o = '';
 465          // type
 466          $o .= $this->getXMLDBKeyName($this->type);
 467          // fields
 468          $o .= ' (' . implode(', ', $this->fields) . ')';
 469          // foreign key
 470          if ($this->type == XMLDB_KEY_FOREIGN ||
 471              $this->type == XMLDB_KEY_FOREIGN_UNIQUE) {
 472              $o .= ' references ' . $this->reftable . ' (' . implode(', ', $this->reffields) . ')';
 473          }
 474  
 475          return $o;
 476      }
 477  }