[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/xmldb/ -> xmldb_structure.php (source)

   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 structure
  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_structure extends xmldb_object {
  30  
  31      /** @var string */
  32      protected $path;
  33  
  34      /** @var string */
  35      protected $version;
  36  
  37      /** @var array tables */
  38      protected $tables;
  39  
  40      /**
  41       * Creates one new xmldb_structure
  42       * @param string $name
  43       */
  44      public function __construct($name) {
  45          parent::__construct($name);
  46          $this->path = null;
  47          $this->version = null;
  48          $this->tables = array();
  49      }
  50  
  51      /**
  52       * Returns the path of the structure
  53       * @return string
  54       */
  55      public function getPath() {
  56          return $this->path;
  57      }
  58  
  59      /**
  60       * Returns the version of the structure
  61       * @return string
  62       */
  63      public function getVersion() {
  64          return $this->version;
  65      }
  66  
  67      /**
  68       * Returns one xmldb_table
  69       * @param string $tablename
  70       * @return xmldb_table
  71       */
  72      public function getTable($tablename) {
  73          $i = $this->findTableInArray($tablename);
  74          if ($i !== null) {
  75              return $this->tables[$i];
  76          }
  77          return null;
  78      }
  79  
  80      /**
  81       * Returns the position of one table in the array.
  82       * @param string $tablename
  83       * @return mixed
  84       */
  85      public function findTableInArray($tablename) {
  86          foreach ($this->tables as $i => $table) {
  87              if ($tablename == $table->getName()) {
  88                  return $i;
  89              }
  90          }
  91          return null;
  92      }
  93  
  94      /**
  95       * This function will reorder the array of tables
  96       * @return bool success
  97       */
  98      public function orderTables() {
  99          $result = $this->orderElements($this->tables);
 100          if ($result) {
 101              $this->setTables($result);
 102              return true;
 103          } else {
 104              return false;
 105          }
 106      }
 107  
 108      /**
 109       * Returns the tables of the structure
 110       * @return array
 111       */
 112      public function getTables() {
 113          return $this->tables;
 114      }
 115  
 116      /**
 117       * Set the structure version
 118       * @param string version
 119       */
 120      public function setVersion($version) {
 121          $this->version = $version;
 122      }
 123  
 124      /**
 125       * Add one table to the structure, allowing to specify the desired order
 126       * If it's not specified, then the table is added at the end.
 127       * @param xmldb_table $table
 128       * @param mixed $after
 129       */
 130      public function addTable($table, $after=null) {
 131  
 132          // Calculate the previous and next tables
 133          $prevtable = null;
 134          $nexttable = null;
 135  
 136          if (!$after) {
 137              if ($this->tables) {
 138                  end($this->tables);
 139                  $prevtable = $this->tables[key($this->tables)];
 140              }
 141          } else {
 142              $prevtable = $this->getTable($after);
 143          }
 144          if ($prevtable && $prevtable->getNext()) {
 145              $nexttable = $this->getTable($prevtable->getNext());
 146          }
 147  
 148          // Set current table previous and next attributes
 149          if ($prevtable) {
 150              $table->setPrevious($prevtable->getName());
 151              $prevtable->setNext($table->getName());
 152          }
 153          if ($nexttable) {
 154              $table->setNext($nexttable->getName());
 155              $nexttable->setPrevious($table->getName());
 156          }
 157          // Some more attributes
 158          $table->setLoaded(true);
 159          $table->setChanged(true);
 160          // Add the new table
 161          $this->tables[] = $table;
 162          // Reorder the whole structure
 163          $this->orderTables($this->tables);
 164          // Recalculate the hash
 165          $this->calculateHash(true);
 166          // We have one new table, so the structure has changed
 167          $this->setVersion(userdate(time(), '%Y%m%d', 99, false));
 168          $this->setChanged(true);
 169      }
 170  
 171      /**
 172       * Delete one table from the Structure
 173       * @param string $tablename
 174       */
 175      public function deleteTable($tablename) {
 176  
 177          $table = $this->getTable($tablename);
 178          if ($table) {
 179              $i = $this->findTableInArray($tablename);
 180              // Look for prev and next table
 181              $prevtable = $this->getTable($table->getPrevious());
 182              $nexttable = $this->getTable($table->getNext());
 183              // Change their previous and next attributes
 184              if ($prevtable) {
 185                  $prevtable->setNext($table->getNext());
 186              }
 187              if ($nexttable) {
 188                  $nexttable->setPrevious($table->getPrevious());
 189              }
 190              // Delete the table
 191              unset($this->tables[$i]);
 192              // Reorder the tables
 193              $this->orderTables($this->tables);
 194              // Recalculate the hash
 195              $this->calculateHash(true);
 196              // We have one deleted table, so the structure has changed
 197              $this->setVersion(userdate(time(), '%Y%m%d', 99, false));
 198              $this->setChanged(true);
 199          }
 200      }
 201  
 202      /**
 203       * Set the tables
 204       * @param array $tables
 205       */
 206      public function setTables($tables) {
 207          $this->tables = $tables;
 208      }
 209  
 210      /**
 211       * Load data from XML to the structure
 212       * @param array $xmlarr
 213       * @return bool
 214       */
 215      public function arr2xmldb_structure($xmlarr) {
 216  
 217          global $CFG;
 218  
 219          $result = true;
 220  
 221          // Debug the structure
 222          // traverse_xmlize($xmlarr);                   //Debug
 223          // print_object ($GLOBALS['traverse_array']);  //Debug
 224          // $GLOBALS['traverse_array']="";              //Debug
 225  
 226          // Process structure attributes (path, comment and version)
 227          if (isset($xmlarr['XMLDB']['@']['PATH'])) {
 228              $this->path = trim($xmlarr['XMLDB']['@']['PATH']);
 229          } else {
 230              $this->errormsg = 'Missing PATH attribute';
 231              $this->debug($this->errormsg);
 232              $result = false;
 233          }
 234          if (isset($xmlarr['XMLDB']['@']['VERSION'])) {
 235              $this->version = trim($xmlarr['XMLDB']['@']['VERSION']);
 236          } else {
 237              $this->errormsg = 'Missing VERSION attribute';
 238              $this->debug($this->errormsg);
 239              $result = false;
 240          }
 241          if (isset($xmlarr['XMLDB']['@']['COMMENT'])) {
 242              $this->comment = trim($xmlarr['XMLDB']['@']['COMMENT']);
 243          } else if (!empty($CFG->xmldbdisablecommentchecking)) {
 244              $this->comment = '';
 245          } else {
 246              $this->errormsg = 'Missing COMMENT attribute';
 247              $this->debug($this->errormsg);
 248              $result = false;
 249          }
 250  
 251          // Iterate over tables
 252          if (isset($xmlarr['XMLDB']['#']['TABLES']['0']['#']['TABLE'])) {
 253              foreach ($xmlarr['XMLDB']['#']['TABLES']['0']['#']['TABLE'] as $xmltable) {
 254                  if (!$result) { //Skip on error
 255                      continue;
 256                  }
 257                  $name = trim($xmltable['@']['NAME']);
 258                  $table = new xmldb_table($name);
 259                  $table->arr2xmldb_table($xmltable);
 260                  $this->tables[] = $table;
 261                  if (!$table->isLoaded()) {
 262                      $this->errormsg = 'Problem loading table ' . $name;
 263                      $this->debug($this->errormsg);
 264                      $result = false;
 265                  }
 266              }
 267          } else {
 268              $this->errormsg = 'Missing TABLES section';
 269              $this->debug($this->errormsg);
 270              $result = false;
 271          }
 272  
 273          // Perform some general checks over tables
 274          if ($result && $this->tables) {
 275              // Check tables names are ok (lowercase, a-z _-)
 276              if (!$this->checkNameValues($this->tables)) {
 277                  $this->errormsg = 'Some TABLES name values are incorrect';
 278                  $this->debug($this->errormsg);
 279                  $result = false;
 280              }
 281              // Compute prev/next.
 282              $this->fixPrevNext($this->tables);
 283              // Order tables
 284              if ($result && !$this->orderTables($this->tables)) {
 285                  $this->errormsg = 'Error ordering the tables';
 286                  $this->debug($this->errormsg);
 287                  $result = false;
 288              }
 289          }
 290  
 291          // Set some attributes
 292          if ($result) {
 293              $this->loaded = true;
 294          }
 295          $this->calculateHash();
 296          return $result;
 297      }
 298  
 299      /**
 300       * This function calculate and set the hash of one xmldb_structure
 301       * @param bool $recursive
 302       */
 303       public function calculateHash($recursive = false) {
 304          if (!$this->loaded) {
 305              $this->hash = null;
 306          } else {
 307              $key = $this->name . $this->path . $this->comment;
 308              if ($this->tables) {
 309                  foreach ($this->tables as $tbl) {
 310                      $table = $this->getTable($tbl->getName());
 311                      if ($recursive) {
 312                          $table->calculateHash($recursive);
 313                      }
 314                      $key .= $table->getHash();
 315                  }
 316              }
 317              $this->hash = md5($key);
 318          }
 319      }
 320  
 321      /**
 322       * This function will output the XML text for one structure
 323       * @return string
 324       */
 325      public function xmlOutput() {
 326          $o = '<?xml version="1.0" encoding="UTF-8" ?>' . "\n";
 327          $o.= '<XMLDB PATH="' . $this->path . '"';
 328          $o.= ' VERSION="' . $this->version . '"';
 329          if ($this->comment) {
 330              $o.= ' COMMENT="' . htmlspecialchars($this->comment) . '"'."\n";
 331          }
 332          $rel = array_fill(0, count(explode('/', $this->path)), '..');
 333          $rel = implode('/', $rel);
 334          $o.= '    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'."\n";
 335          $o.= '    xsi:noNamespaceSchemaLocation="'.$rel.'/lib/xmldb/xmldb.xsd"'."\n";
 336          $o.= '>' . "\n";
 337          // Now the tables
 338          if ($this->tables) {
 339              $o.= '  <TABLES>' . "\n";
 340              foreach ($this->tables as $table) {
 341                  $o.= $table->xmlOutput();
 342              }
 343              $o.= '  </TABLES>' . "\n";
 344          }
 345          $o.= '</XMLDB>';
 346  
 347          return $o;
 348      }
 349  
 350      /**
 351       * This function returns the number of uses of one table inside
 352       * a whole XMLDStructure. Useful to detect if the table must be
 353       * locked. Return false if no uses are found.
 354       * @param string $tablename
 355       * @return mixed
 356       */
 357      public function getTableUses($tablename) {
 358  
 359          $uses = array();
 360  
 361          // Check if some foreign key in the whole structure is using it
 362          // (by comparing the reftable with the tablename)
 363          if ($this->tables) {
 364              foreach ($this->tables as $table) {
 365                  $keys = $table->getKeys();
 366                  if ($keys) {
 367                      foreach ($keys as $key) {
 368                          if ($key->getType() == XMLDB_KEY_FOREIGN) {
 369                              if ($tablename == $key->getRefTable()) {
 370                                  $uses[] = 'table ' . $table->getName() . ' key ' . $key->getName();
 371                              }
 372                          }
 373                      }
 374                  }
 375              }
 376          }
 377  
 378          // Return result
 379          if (!empty($uses)) {
 380              return $uses;
 381          } else {
 382              return false;
 383          }
 384      }
 385  
 386      /**
 387       * This function returns the number of uses of one field inside
 388       * a whole xmldb_structure. Useful to detect if the field must be
 389       * locked. Return false if no uses are found.
 390       * @param string $tablename
 391       * @param string $fieldname
 392       * @return mixed
 393       */
 394      public function getFieldUses($tablename, $fieldname) {
 395  
 396          $uses = array();
 397  
 398          // Check if any key in the table is using it
 399          $table = $this->getTable($tablename);
 400          if ($keys = $table->getKeys()) {
 401              foreach ($keys as $key) {
 402                  if (in_array($fieldname, $key->getFields()) ||
 403                      in_array($fieldname, $key->getRefFields())) {
 404                          $uses[] = 'table ' . $table->getName() . ' key ' . $key->getName();
 405                  }
 406              }
 407          }
 408          // Check if any index in the table is using it
 409          $table = $this->getTable($tablename);
 410          if ($indexes = $table->getIndexes()) {
 411              foreach ($indexes as $index) {
 412                  if (in_array($fieldname, $index->getFields())) {
 413                      $uses[] = 'table ' . $table->getName() . ' index ' . $index->getName();
 414                  }
 415              }
 416          }
 417          // Check if some foreign key in the whole structure is using it
 418          // By comparing the reftable and refields with the field)
 419          if ($this->tables) {
 420              foreach ($this->tables as $table) {
 421                  $keys = $table->getKeys();
 422                  if ($keys) {
 423                      foreach ($keys as $key) {
 424                          if ($key->getType() == XMLDB_KEY_FOREIGN) {
 425                              if ($tablename == $key->getRefTable()) {
 426                                  $reffieds = $key->getRefFields();
 427                                  if (in_array($fieldname, $key->getRefFields())) {
 428                                      $uses[] = 'table ' . $table->getName() . ' key ' . $key->getName();
 429                                  }
 430                              }
 431                          }
 432                      }
 433                  }
 434              }
 435          }
 436  
 437          // Return result
 438          if (!empty($uses)) {
 439              return $uses;
 440          } else {
 441              return false;
 442          }
 443      }
 444  
 445      /**
 446       * This function returns the number of uses of one key inside
 447       * a whole xmldb_structure. Useful to detect if the key must be
 448       * locked. Return false if no uses are found.
 449       * @param string $tablename
 450       * @param string $keyname
 451       * @return mixed
 452       */
 453      public function getKeyUses($tablename, $keyname) {
 454  
 455          $uses = array();
 456  
 457          // Check if some foreign key in the whole structure is using it
 458          // (by comparing the reftable and reffields with the fields in the key)
 459          $mytable = $this->getTable($tablename);
 460          $mykey = $mytable->getKey($keyname);
 461          if ($this->tables && $mykey) {
 462              foreach ($this->tables as $table) {
 463                  $allkeys = $table->getKeys();
 464                  if ($allkeys) {
 465                      foreach ($allkeys as $key) {
 466                          if ($key->getType() != XMLDB_KEY_FOREIGN) {
 467                              continue;
 468                          }
 469                          if ($key->getRefTable() == $tablename &&
 470                              implode(',', $key->getRefFields()) == implode(',', $mykey->getFields())) {
 471                                  $uses[] = 'table ' . $table->getName() . ' key ' . $key->getName();
 472                          }
 473                      }
 474                  }
 475              }
 476          }
 477  
 478          // Return result
 479          if (!empty($uses)) {
 480              return $uses;
 481          } else {
 482              return false;
 483          }
 484      }
 485  
 486      /**
 487       * This function returns the number of uses of one index inside
 488       * a whole xmldb_structure. Useful to detect if the index must be
 489       * locked. Return false if no uses are found.
 490       * @param string $tablename
 491       * @param string $indexname
 492       * @return mixed
 493       */
 494      public function getIndexUses($tablename, $indexname) {
 495  
 496          $uses = array();
 497  
 498          // Nothing to check, because indexes haven't uses! Leave it here
 499          // for future checks...
 500  
 501          // Return result
 502          if (!empty($uses)) {
 503              return $uses;
 504          } else {
 505              return false;
 506          }
 507      }
 508  
 509      /**
 510       * This function will return all the errors found in one structure
 511       * looking recursively inside each table. Returns
 512       * an array of errors or false
 513       * @return mixed
 514       */
 515      public function getAllErrors() {
 516  
 517          $errors = array();
 518          // First the structure itself
 519          if ($this->getError()) {
 520              $errors[] = $this->getError();
 521          }
 522          // Delegate to tables
 523          if ($this->tables) {
 524              foreach ($this->tables as $table) {
 525                  if ($tableerrors = $table->getAllErrors()) {
 526  
 527                  }
 528              }
 529              // Add them to the errors array
 530              if ($tableerrors) {
 531                  $errors = array_merge($errors, $tableerrors);
 532              }
 533          }
 534          // Return decision
 535          if (count($errors)) {
 536              return $errors;
 537          } else {
 538              return false;
 539          }
 540      }
 541  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1