MediaWiki master
SchemaGenerator.php
Go to the documentation of this file.
1<?php
2
4
5use Doctrine\SqlFormatter\NullHighlighter;
6use Doctrine\SqlFormatter\SqlFormatter;
7use JsonException;
11
23 public function validateAndGetSchema( string $jsonPath ): array {
24 $json = file_get_contents( $jsonPath );
25
26 if ( !$json ) {
27 throw new AbstractSchemaValidationError( "'$jsonPath' does not exist!" );
28 }
29
30 try {
31 $abstractSchema = json_decode( $json, true, 512, JSON_THROW_ON_ERROR );
32 } catch ( JsonException $e ) {
33 throw new AbstractSchemaValidationError( "Invalid JSON schema: " . $e->getMessage(), 0, $e );
34 }
35
36 $validator = new AbstractSchemaValidator();
37 $validator->validate( $jsonPath );
38
39 return $abstractSchema;
40 }
41
45 public function generateSchema( string $platform, string $jsonPath ): string {
46 $abstractSchemaChange = $this->validateAndGetSchema( $jsonPath );
47
48 $sql = $this->makeSQLComment( 'generateSchemaSql.php', $jsonPath );
49
50 $schemaBuilder = ( new DoctrineSchemaBuilderFactory() )->getSchemaBuilder( $platform );
51
52 foreach ( $abstractSchemaChange as $table ) {
53 $schemaBuilder->addTable( $table );
54 }
55 $tableSqls = $schemaBuilder->getSql();
56
57 $sql .= $this->cleanupSqlArray( $platform, $tableSqls );
58
59 return $sql;
60 }
61
65 public function generateSchemaChange( string $platform, string $jsonPath ): string {
66 $abstractSchemaChange = $this->validateAndGetSchema( $jsonPath );
67
68 $sql = $this->makeSQLComment( 'generateSchemaChangeSql.php', $jsonPath );
69
70 $schemaChangeBuilder = ( new DoctrineSchemaBuilderFactory() )->getSchemaChangeBuilder( $platform );
71
72 $schemaChangeSqls = $schemaChangeBuilder->getSchemaChangeSql( $abstractSchemaChange );
73 if ( !$schemaChangeSqls ) {
74 throw new AbstractSchemaValidationError( "No schema changes detected!" );
75 }
76
77 $sql .= $this->cleanupSqlArray( $platform, $schemaChangeSqls );
78
79 return $sql;
80 }
81
82 private function makeSQLComment( string $scriptName, string $jsonPath ): string {
83 global $IP;
84
85 $installPath = realpath( $IP );
86 $jsonPath = realpath( $jsonPath );
87
88 // For windows
89 if ( DIRECTORY_SEPARATOR === '\\' ) {
90 $installPath = strtr( $installPath, '\\', '/' );
91 $jsonPath = strtr( $jsonPath, '\\', '/' );
92 }
93
94 $canonicalJsonPath = str_replace( "$installPath/", '', $jsonPath );
95 $canonicalJsonPath = preg_replace( '!^extensions/[^/]+/!', '', $canonicalJsonPath );
96
97 return "-- This file is automatically generated using maintenance/$scriptName.\n" .
98 "-- Source: $canonicalJsonPath\n" .
99 "-- Do not modify this file directly.\n" .
100 "-- See https://www.mediawiki.org/wiki/Manual:Schema_changes\n";
101 }
102
111 private function cleanupSqlArray( string $platform, array $sqlArray ): string {
112 if ( !$sqlArray ) {
113 return '';
114 }
115
116 // Temporary
117 $sql = implode( ";\n\n", $sqlArray ) . ';';
118 $sql = ( new SqlFormatter( new NullHighlighter() ) )->format( $sql );
119
120 // Postgres hacks
121 if ( $platform === 'postgres' ) {
122 // FIXME: Fix a lot of weird formatting issues caused by
123 // presence of partial index's WHERE clause, this should probably
124 // be done in some better way, but for now this can work temporarily
125 $sql = str_replace(
126 [ "WHERE\n ", "\n /*_*/\n ", " ", " );", "KEY(\n " ],
127 [ "WHERE", ' ', " ", ');', "KEY(\n " ],
128 $sql
129 );
130 }
131
132 // Temporary fixes until the linting issues are resolved upstream.
133 // https://github.com/doctrine/sql-formatter/issues/53
134
135 $sql = preg_replace( "!\s+/\*_\*/\s+!", " /*_*/", $sql );
136 $sql = preg_replace(
137 '!\s+/\*\$wgDBTableOptions\*/\s+;!',
138 ' /*$wgDBTableOptions*/;',
139 $sql
140 );
141
142 $sql = str_replace( "; CREATE ", ";\n\nCREATE ", $sql );
143 $sql = str_replace( ";\n\nCREATE TABLE ", ";\n\n\nCREATE TABLE ", $sql );
144 $sql = preg_replace( '/^(CREATE|DROP|ALTER)\s+(TABLE|VIEW|INDEX)\s+/m', '$1 $2 ', $sql );
145 $sql = preg_replace( '/(?<!\s|;)\s+(ADD|DROP|ALTER|MODIFY|CHANGE|RENAME)\s+/', "\n \$1 ", $sql );
146
147 $sql = str_replace( "; ", ";\n", $sql );
148
149 if ( !str_ends_with( $sql, "\n" ) ) {
150 $sql .= "\n";
151 }
152
153 // Sqlite hacks
154 if ( $platform === 'sqlite' ) {
155 // Doctrine prepends __temp__ to the table name and we set the table with the schema prefix causing invalid
156 // sqlite.
157 $sql = preg_replace( '/__temp__\s*\/\*_\*\//', '/*_*/__temp__', $sql );
158 }
159
160 return $sql;
161 }
162}
if(!defined( 'MEDIAWIKI')) if(ini_get('mbstring.func_overload')) if(!defined( 'MW_ENTRY_POINT')) global $IP
Environment checks.
Definition Setup.php:105
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:81
Validate abstract schema json files against their JSON schema.
Helper to generate abstract schema and schema changes in maintenance scripts.
generateSchemaChange(string $platform, string $jsonPath)
generateSchema(string $platform, string $jsonPath)
validateAndGetSchema(string $jsonPath)
Fetches the abstract schema.