[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |