| [ Index ] |
|
Code source de eZ Publish 3.9.0 |
1 <?php 2 // 3 // Definition of eZLintSchema class 4 // 5 // Created on: <05-Nov-2004 14:03:27 jb> 6 // 7 // SOFTWARE NAME: eZ publish 8 // SOFTWARE RELEASE: 3.9.0 9 // BUILD VERSION: 17785 10 // COPYRIGHT NOTICE: Copyright (C) 1999-2006 eZ systems AS 11 // SOFTWARE LICENSE: GNU General Public License v2.0 12 // NOTICE: > 13 // This program is free software; you can redistribute it and/or 14 // modify it under the terms of version 2.0 of the GNU General 15 // Public License as published by the Free Software Foundation. 16 // 17 // This program is distributed in the hope that it will be useful, 18 // but WITHOUT ANY WARRANTY; without even the implied warranty of 19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 // GNU General Public License for more details. 21 // 22 // You should have received a copy of version 2.0 of the GNU General 23 // Public License along with this program; if not, write to the Free 24 // Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 25 // MA 02110-1301, USA. 26 // 27 // 28 29 /*! 30 \class eZLintSchema ezlintschema.php 31 \ingroup eZDBSchema 32 \brief Provides lint checking of database schemas 33 34 Checks a given schema by going trough all tables, fields and indexes 35 and corrects any mistakes. The result is a new schema which is returned 36 in schema(). The new schema can then be used to diff against the original 37 and output the changes. 38 39 The current rules apply: 40 - Table names must not exceed 26 characters, configurable in dbschema.ini (LintChecker/TableLimit) 41 - Field names must not exceed 30 characters, configurable in dbschema.ini (LintChecker/FieldLimit) 42 - Index names must not exceed 30 characters, configurable in dbschema.ini (LintChecker/IndexLimit) 43 - Index names must not be the same as table names 44 - String fields cannot have NOT NULL and an empty string as DEFAULT value. 45 - Primary keys must be named PRIMARY 46 47 The lint checker works by taking in another DB Schema object as parameter 48 to the constructor. All calls will be forwarded to this object so it will 49 work as though it were a real schema. 50 The exception are the schema(), data() and validate() methods which makes 51 sure the schema is correct. 52 53 To check if the schema has been checked yet call isLintChecked(). 54 To fetch the DB schema which is checked use otherSchema(). 55 56 */ 57 58 include_once ( 'lib/ezdbschema/classes/ezdbschemainterface.php' ); 59 60 class eZLintSchema extends eZDBSchemaInterface 61 { 62 /*! 63 Initializes the lint checker with a foreign db schema. 64 65 \param $db A dummy parameter, pass \c false. 66 \param $otherSchema The db schema that should be checked 67 */ 68 function eZLintSchema( $db, $otherSchema ) 69 { 70 $this->eZDBSchemaInterface( $db ); 71 $this->OtherSchema = $otherSchema; 72 $this->CorrectSchema = false; 73 $this->IsLintChecked = false; 74 } 75 76 /*! 77 Runs the lint checker on the database schema in otherSchema() 78 and returns the new schema that is correct. 79 */ 80 function schema( $params = array() ) 81 { 82 if ( $this->IsLintChecked ) 83 { 84 return $this->CorrectSchema; 85 } 86 87 $params = array_merge( array( 'meta_data' => false, 88 'format' => 'generic' ), 89 $params ); 90 91 $this->CorrectSchema = $this->OtherSchema->schema( $params ); 92 $this->lintCheckSchema( $this->CorrectSchema ); 93 $this->IsLintChecked = true; 94 return $this->CorrectSchema; 95 } 96 97 /*! 98 \reimp 99 Runs lint checker on all tables, indexes and fields. 100 */ 101 function validate() 102 { 103 return $this->lintCheckSchema( $this->CorrectSchema ); 104 } 105 106 /*! 107 \return The schema object which is being lint checked. 108 */ 109 function otherSchema() 110 { 111 return $this->OtherSchema; 112 } 113 114 /*! 115 \return \c true if the lint checker has been run on the schema. 116 */ 117 function isLintChecked() 118 { 119 return $this->IsLintChecked; 120 } 121 122 /*! 123 \return A modified version of \a $identifier that is guaranteed to be shorter than \a $limit 124 */ 125 function shortenIdentifier( $identifier, $limit, $shortenList ) 126 { 127 reset( $shortenList ); 128 // Replace one word at a time until we have a string that is short 129 // enough, or we run out of replace words 130 while ( strlen( $identifier ) > $limit and 131 current( $shortenList ) !== false ) 132 { 133 $from = key( $shortenList ); 134 $to = current( $shortenList ); 135 next( $shortenList ); 136 $identifier = str_replace( $from, $to, $identifier ); 137 } 138 139 // It is still to large so we just cut it off 140 if ( strlen( $identifier ) > $limit ) 141 { 142 $identifier = substr( $identifier, 0, $limit ); 143 } 144 return $identifier; 145 } 146 147 /*! 148 \private 149 Goes trough all tables, fields and indexes and makes sure they have valid names. 150 \return \c false if something was fixed, \c true otherwise. 151 */ 152 function lintCheckSchema( &$schema ) 153 { 154 $status = true; 155 156 $ini =& eZINI::instance( 'dbschema.ini' ); 157 158 // A mapping table that maps from a long name to a short name 159 // This will be used if an identifier/name is too long 160 $shortenList = $ini->variable( 'LintChecker', 'NameMap' ); 161 162 // Limitation on the length of identifiers/names 163 // Oracle is the database with the most limit (30 characters) so the 164 // limit values must be equal or lower to that. 165 $tableNameLimit = (int)$ini->variable( 'LintChecker', 'TableLimit' ); 166 $fieldNameLimit = (int)$ini->variable( 'LintChecker', 'FieldLimit' ); 167 $indexNameLimit = (int)$ini->variable( 'LintChecker', 'IndexLimit' ); 168 169 // Tables which do not get lint checked, they are currently 170 // handled with workarounds in the various schema handlers 171 // Note: The fields and indexes are still checked. 172 $ignoredTableList = $ini->variable( 'LintChecker', 'IgnoredTables' ); 173 174 // Fields which do not get lint checked, they are currently 175 // handled with workarounds in the various schema handlers 176 $list = $ini->variable( 'LintChecker', 'IgnoredFields' ); 177 $ignoredFieldList = array(); 178 foreach ( $list as $entry ) 179 { 180 list( $tableName, $fieldName ) = explode( '.', $entry, 2 ); 181 if ( !isset( $ignoredFieldList[$tableName] ) ) 182 $ignoredFieldList[$tableName] = array(); 183 $ignoredFieldList[$tableName][] = $fieldName; 184 } 185 186 // Fields which do not get lint checked, they are currently 187 // handled with workarounds in the various schema handlers 188 $list = $ini->variable( 'LintChecker', 'IgnoredFieldSyntax' ); 189 $ignoredFieldSyntaxList = array(); 190 foreach ( $list as $entry ) 191 { 192 list( $tableName, $fieldName ) = explode( '.', $entry, 2 ); 193 if ( !isset( $ignoredFieldList[$tableName] ) ) 194 $ignoredFieldSyntaxList[$tableName] = array(); 195 $ignoredFieldSyntaxList[$tableName][] = $fieldName; 196 } 197 198 // Indexes which do not get lint checked, they are currently 199 // handled with workarounds in the various schema handlers 200 $ignoredIndexList = $ini->variable( 'LintChecker', 'IgnoredIndexes' ); 201 202 $badTables = array(); 203 foreach ( $schema as $tableName => $tableDef ) 204 { 205 // Skip the info structure, this is not a table 206 if ( $tableName == '_info' ) 207 continue; 208 209 $existingTableName = $tableName; 210 $tableComments = array(); 211 212 // If table is not in ignore list we check the name 213 if ( !in_array( $tableName, $ignoredTableList ) ) 214 { 215 // identifiers must be 30 or less 216 // for tables we require 26 or less to allow adding suffix or prefix for indexes etc. 217 if ( strlen( $tableName ) > $tableNameLimit ) 218 { 219 $tableComment = "Table names must not exceed $tableNameLimit characters,\n'$tableName' is " . strlen( $tableName ) . " characters,\ndatabases like Oracle will have problems with this."; 220 $tableName = $this->shortenIdentifier( $tableName, $tableNameLimit, $shortenList ); 221 $tableComment .= "\nNew name is '$tableName'"; 222 $tableComments[] = $tableComment; 223 $status = false; 224 } 225 226 if ( strcmp( $tableName, $existingTableName ) != 0 ) 227 { 228 $badTables[] = array( 'from' => $existingTableName, 229 'to' => $tableName ); 230 } 231 } 232 233 if ( isset( $tableDef['fields'] ) ) 234 { 235 $badFields = array(); 236 foreach ( $tableDef['fields'] as $fieldName => $fieldDef ) 237 { 238 $comments = array(); 239 $existingFieldName = $fieldName; 240 241 // Do we ignore the field name? 242 if ( !isset( $ignoredFieldList[$existingTableName] ) or 243 !in_array( $fieldName, $ignoredFieldList[$existingTableName] ) ) 244 { 245 246 // identifiers must be 30 or less 247 if ( strlen( $fieldName ) > $fieldNameLimit ) 248 { 249 $comment = "Field names must not exceed $fieldNameLimit characters,\n'$fieldName' in table '$existingTableName' is " . strlen( $fieldName ) . " characters,\ndatabases like Oracle will have problems with this."; 250 $fieldName = $this->shortenIdentifier( $fieldName, $fieldNameLimit, $shortenList ); 251 $comment .= "\nNew name is '$fieldName'"; 252 $comments[] = $comment; 253 $status = false; 254 } 255 } 256 257 if ( !isset( $ignoredFieldSyntaxList[$existingTableName] ) or 258 !in_array( $fieldName, $ignoredFieldSyntaxList[$existingTableName] ) ) 259 { 260 /* Temporarily disabled 261 if ( in_array( $fieldDef['type'], 262 array( 'varchar', 'char', 263 'longtext', 'mediumtext', 'shorttext' ) ) and 264 isset( $fieldDef['not_null'] ) and 265 $fieldDef['not_null'] and 266 $fieldDef['default'] === '' ) 267 { 268 $comments[] = "The string type " . $fieldDef['type'] . " ($existingTableName.$fieldName) cannot have NOT NULL defined and an empty string as DEFAULT value\nDatabase like Oracle will have problems with this."; 269 $status = false; 270 } 271 */ 272 } 273 274 if ( strcmp( $existingFieldName, $fieldName ) != 0 ) 275 { 276 $badFields[] = array( 'from' => $existingFieldName, 277 'to' => $fieldName ); 278 } 279 280 if ( count( $comments ) > 0 ) 281 { 282 $schema[$existingTableName]['fields'][$existingFieldName]['comments'] = $comments; 283 foreach ( $comments as $comment ) 284 { 285 eZDebug::writeWarning( $comment, 'eZLintSchema::fieldComment' ); 286 } 287 } 288 } 289 290 foreach ( $badFields as $badField ) 291 { 292 $schema[$existingTableName]['fields'][$badField['to']] = $schema[$existingTableName]['fields'][$badField['from']]; 293 // unset( $schema[$existingTableName]['fields'][$badField['from']] ); 294 $schema[$existingTableName]['fields'][$badField['from']]['removed'] = true; 295 } 296 } 297 298 if ( isset( $tableDef['indexes'] ) ) 299 { 300 $badIndexes = array(); 301 foreach ( $tableDef['indexes'] as $indexName => $indexDef ) 302 { 303 // Primary key 304 if ( $indexDef['type'] == 'primary' ) 305 continue; 306 307 // Do we ignore the index? 308 if ( in_array( $indexName, $ignoredIndexList ) ) 309 continue; 310 311 $comments = array(); 312 313 $existingIndexName = $indexName; 314 if ( isset( $schema[$indexName] ) ) 315 { 316 $comment = "Index named '$indexName' has same name as an existing table,\ndatabases like PostgreSQL and Oracle will have problems with this."; 317 $indexFieldText = ''; 318 $i = 0; 319 foreach ( $indexDef['fields'] as $fieldDef ) 320 { 321 if ( $i > 0 ) 322 $indexFieldText .= '_'; 323 if ( is_array( $fieldDef ) ) 324 { 325 $indexFieldText .= $fieldDef['name']; 326 } 327 else 328 { 329 $indexFieldText .= $fieldDef; 330 } 331 } 332 $indexName = $indexName . '_' . $indexFieldText . '_i'; 333 $comment .= "\nNew name is '$indexName'"; 334 $comments[] = $comment; 335 $status = false; 336 } 337 338 // Primary indexes must be named PRIMARY 339 if ( $indexDef['type'] == 'primary' and 340 $indexName != 'PRIMARY' ) 341 { 342 $comment = "Index named '$indexName' which is a primary key must be named PRIMARY."; 343 $indexName = "PRIMARY"; 344 $comments[] = $comment; 345 $status = false; 346 } 347 348 // identifiers must be 30 or less 349 if ( strlen( $indexName ) > $indexNameLimit ) 350 { 351 $comment = "Index names must not exceed $indexNameLimit characters,\n'$indexName' is " . strlen( $indexName ) . " characters,\ndatabases like Oracle will have problems with this."; 352 $indexName = $this->shortenIdentifier( $indexName, $indexNameLimit, $shortenList ); 353 $comment .= "\nNew name is '$indexName'"; 354 $comments[] = $comment; 355 $status = false; 356 } 357 358 // Check if there are some database specific entries 359 foreach ( $indexDef['fields'] as $fieldDef ) 360 { 361 if ( is_array( $fieldDef ) ) 362 { 363 $fieldName = $fieldDef['name']; 364 foreach ( $fieldDef as $fdName => $fdValue ) 365 { 366 if ( preg_match( "#^([a-z0-9]+):#", $fdName, $matches ) ) 367 { 368 $dbName = $matches[1]; 369 $comments[] = "Found database specific entry ($dbName) at index $existingIndexName.$fieldName"; 370 $status = false; 371 } 372 } 373 } 374 } 375 376 if ( strcmp( $existingIndexName, $indexName ) != 0 ) 377 { 378 $badIndexes[] = array( 'from' => $existingIndexName, 379 'to' => $indexName ); 380 } 381 if ( count( $comments ) > 0 ) 382 { 383 $schema[$existingTableName]['indexes'][$existingIndexName]['comments'] = $comments; 384 foreach ( $comments as $comment ) 385 { 386 eZDebug::writeWarning( $comment, 'eZLintSchema::indexComment' ); 387 } 388 } 389 } 390 391 foreach ( $badIndexes as $badIndex ) 392 { 393 $schema[$existingTableName]['indexes'][$badIndex['to']] = $schema[$existingTableName]['indexes'][$badIndex['from']]; 394 $schema[$existingTableName]['indexes'][$badIndex['from']]['removed'] = true; 395 } 396 } 397 398 if ( count( $tableComments ) > 0 ) 399 { 400 $schema[$existingTableName]['comments'] = $tableComments; 401 foreach ( $tableComments as $comment ) 402 { 403 eZDebug::writeWarning( $comment, 'eZLintSchema::tableComment' ); 404 } 405 } 406 } 407 foreach ( $badTables as $badTable ) 408 { 409 $schema[$badTable['to']] = $schema[$badTable['from']]; 410 $schema[$badTable['from']]['removed'] = true; 411 } 412 return $status; 413 } 414 415 /*! 416 \reimp 417 Forwards request to data() on the otherSchema() object. 418 */ 419 function data( $schema = false, $tableNameList = false ) 420 { 421 return $this->OtherSchema->data( $schema, $tableNameList ); 422 } 423 424 /*! 425 \reimp 426 Forwards request to generateSchemaFile() on the otherSchema() object. 427 */ 428 function generateSchemaFile( $schema, $params ) 429 { 430 return $this->OtherSchema->generateSchemaFile( $schema, $params ); 431 } 432 433 /*! 434 \reimp 435 Forwards request to generateUpgradeFile() on the otherSchema() object. 436 */ 437 function generateUpgradeFile( $differences, $params ) 438 { 439 return $this->OtherSchema->generateUpgradeFile( $differences, $params ); 440 } 441 442 /*! 443 \reimp 444 Forwards request to generateDataFile() on the otherSchema() object. 445 */ 446 function generateDataFile( $schema, $data, $params ) 447 { 448 return $this->OtherSchema->generateDataFile( $schema, $data, $params ); 449 } 450 451 /*! 452 \reimp 453 Forwards request to generateTableSchema() on the otherSchema() object. 454 */ 455 function generateTableSchema( $table, $tableDef, $params ) 456 { 457 return $this->OtherSchema->generateTableSchema( $table, $tableDef, $params ); 458 } 459 460 /*! 461 \reimp 462 Forwards request to generateTableInsert() on the otherSchema() object. 463 */ 464 function generateTableInsert( $tableName, $tableDef, $dataEntries, $params ) 465 { 466 return $this->OtherSchema->generateTableInsert( $tableName, $tableDef, $dataEntries, $params ); 467 } 468 469 /*! 470 \reimp 471 Forwards request to generateDropTable() on the otherSchema() object. 472 */ 473 function generateDropTable( $table, $params ) 474 { 475 return $this->OtherSchema->generateDropTable( $table, $params ); 476 } 477 478 /*! 479 \reimp 480 Forwards request to generateAddFieldSql() on the otherSchema() object. 481 */ 482 function generateAddFieldSql( $table, $field_name, $added_field, $params ) 483 { 484 return $this->OtherSchema->generateAddFieldSql( $table, $field_name, $added_field, $params ); 485 } 486 487 /*! 488 \reimp 489 Forwards request to generateAlterFieldSql() on the otherSchema() object. 490 */ 491 function generateAlterFieldSql( $table, $field_name, $changed_field, $params ) 492 { 493 return $this->OtherSchema->generateAlterFieldSql( $table, $field_name, $changed_field, $params ); 494 } 495 496 /*! 497 \reimp 498 Forwards request to generateDropFieldSql() on the otherSchema() object. 499 */ 500 function generateDropFieldSql( $table, $field_name, $params ) 501 { 502 return $this->OtherSchema->generateDropFieldSql( $table, $field_name, $params ); 503 } 504 505 /*! 506 \reimp 507 Forwards request to generateAddIndexSql() on the otherSchema() object. 508 */ 509 function generateAddIndexSql( $table, $index_name, $added_index, $params ) 510 { 511 return $this->OtherSchema->generateAddIndexSql( $table, $index_name, $added_index, $params ); 512 } 513 514 /*! 515 \reimp 516 Forwards request to generateDropIndexSql() on the otherSchema() object. 517 */ 518 function generateDropIndexSql( $table, $index_name, $removed_index, $params ) 519 { 520 return $this->OtherSchema->generateDropIndexSql( $table, $index_name, $removed_index, $params ); 521 } 522 523 /*! 524 \reimp 525 Forwards request to isMultiInsertSupported() on the otherSchema() object. 526 */ 527 function isMultiInsertSupported() 528 { 529 return $this->OtherSchema->isMultiInsertSupported(); 530 } 531 532 /*! 533 \reimp 534 Forwards request to generateDataValueTextSQL() on the otherSchema() object. 535 */ 536 function generateDataValueTextSQL( $fieldDef, $value ) 537 { 538 return $this->OtherSchema->generateDataValueTextSQL( $fieldDef, $value ); 539 } 540 541 /*! 542 \reimp 543 Forwards request to schemaType() on the otherSchema() object. 544 */ 545 function schemaType() 546 { 547 return $this->OtherSchema->schemaType(); 548 } 549 550 /*! 551 \reimp 552 Forwards request to schemaName() on the otherSchema() object. 553 */ 554 function schemaName() 555 { 556 return $this->OtherSchema->schemaName(); 557 } 558 559 /// \privatesection 560 /// eZDBSchemaInterface object which should be lint checked 561 var $OtherSchema; 562 /// The corrected schema 563 var $CorrectSchema; 564 /// Whether the schema has been checked or not 565 var $IsLintChecked; 566 } 567 568 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Sat Feb 24 10:30:04 2007 | par Balluche grâce à PHPXref 0.7 |