MediaWiki REL1_39
DatabaseDomain.php
Go to the documentation of this file.
1<?php
20namespace Wikimedia\Rdbms;
21
22use InvalidArgumentException;
23
43 private $database;
45 private $schema;
47 private $prefix;
48
50 private $equivalentString;
51
57 public function __construct( $database, $schema, $prefix ) {
58 if ( $database !== null && ( !is_string( $database ) || $database === '' ) ) {
59 throw new InvalidArgumentException( 'Database must be null or a non-empty string.' );
60 }
61 $this->database = $database;
62 if ( $schema !== null && ( !is_string( $schema ) || $schema === '' ) ) {
63 throw new InvalidArgumentException( 'Schema must be null or a non-empty string.' );
64 } elseif ( $database === null && $schema !== null ) {
65 throw new InvalidArgumentException( 'Schema must be null if database is null.' );
66 }
67 $this->schema = $schema;
68 if ( !is_string( $prefix ) ) {
69 throw new InvalidArgumentException( "Prefix must be a string." );
70 }
71 $this->prefix = $prefix;
72 }
73
78 public static function newFromId( $domain ): self {
79 if ( $domain instanceof self ) {
80 return $domain;
81 }
82
83 if ( !is_string( $domain ) ) {
84 throw new InvalidArgumentException( "Domain must be a string or " . __CLASS__ );
85 }
86
87 $parts = array_map( [ __CLASS__, 'decode' ], explode( '-', $domain ) );
88
89 $schema = null;
90 $prefix = '';
91
92 if ( count( $parts ) == 1 ) {
93 $database = $parts[0];
94 } elseif ( count( $parts ) == 2 ) {
95 list( $database, $prefix ) = $parts;
96 } elseif ( count( $parts ) == 3 ) {
97 list( $database, $schema, $prefix ) = $parts;
98 } else {
99 throw new InvalidArgumentException( "Domain '$domain' has too few or too many parts." );
100 }
101
102 if ( $database === '' ) {
103 $database = null;
104 }
105
106 if ( $schema === '' ) {
107 $schema = null;
108 }
109
110 $instance = new self( $database, $schema, $prefix );
111 $instance->equivalentString = $domain;
112
113 return $instance;
114 }
115
119 public static function newUnspecified() {
120 return new self( null, null, '' );
121 }
122
127 public function equals( $other ) {
128 if ( $other instanceof self ) {
129 return (
130 $this->database === $other->database &&
131 $this->schema === $other->schema &&
132 $this->prefix === $other->prefix
133 );
134 }
135
136 return ( $this->getId() === $other );
137 }
138
153 public function isCompatible( $other ) {
154 if ( $this->isUnspecified() ) {
155 return true; // even the prefix doesn't matter
156 }
157
158 $other = self::newFromId( $other );
159
160 return (
161 ( $this->database === $other->database || $this->database === null ) &&
162 ( $this->schema === $other->schema || $this->schema === null ) &&
163 $this->prefix === $other->prefix
164 );
165 }
166
171 public function isUnspecified() {
172 return (
173 $this->database === null && $this->schema === null && $this->prefix === ''
174 );
175 }
176
180 public function getDatabase() {
181 return $this->database;
182 }
183
187 public function getSchema() {
188 return $this->schema;
189 }
190
194 public function getTablePrefix() {
195 return $this->prefix;
196 }
197
201 public function getId(): string {
202 if ( $this->equivalentString === null ) {
203 $this->equivalentString = $this->convertToString();
204 }
205
206 return $this->equivalentString;
207 }
208
212 private function convertToString(): string {
213 $parts = [ (string)$this->database ];
214 if ( $this->schema !== null ) {
215 $parts[] = $this->schema;
216 }
217 if ( $this->prefix != '' || $this->schema !== null ) {
218 // If there is a schema, then we need the prefix to disambiguate.
219 // For engines like Postgres that use schemas, this awkwardness is hopefully
220 // avoided since it is easy to have one DB per server (to avoid having many users)
221 // and use schema/prefix to have wiki farms. For example, a domain schemes could be
222 // wiki-<project>-<language>, e.g. "wiki-fitness-es"/"wiki-sports-fr"/"wiki-news-en".
223 $parts[] = $this->prefix;
224 }
225
226 return implode( '-', array_map( [ __CLASS__, 'encode' ], $parts ) );
227 }
228
229 private static function encode( $decoded ) {
230 $encoded = '';
231
232 $length = strlen( $decoded );
233 for ( $i = 0; $i < $length; ++$i ) {
234 $char = $decoded[$i];
235 if ( $char === '-' ) {
236 $encoded .= '?h';
237 } elseif ( $char === '?' ) {
238 $encoded .= '??';
239 } else {
240 $encoded .= $char;
241 }
242 }
243
244 return $encoded;
245 }
246
247 private static function decode( $encoded ) {
248 $decoded = '';
249
250 $length = strlen( $encoded );
251 for ( $i = 0; $i < $length; ++$i ) {
252 $char = $encoded[$i];
253 if ( $char === '?' ) {
254 $nextChar = $encoded[$i + 1] ?? null;
255 if ( $nextChar === 'h' ) {
256 $decoded .= '-';
257 ++$i;
258 } elseif ( $nextChar === '?' ) {
259 $decoded .= '?';
260 ++$i;
261 } else {
262 $decoded .= $char;
263 }
264 } else {
265 $decoded .= $char;
266 }
267 }
268
269 return $decoded;
270 }
271
275 public function __toString() {
276 return $this->getId();
277 }
278}
if(!defined('MW_SETUP_CALLBACK'))
The persistent session ID (if any) loaded at startup.
Definition WebStart.php:82
Class to handle database/schema/prefix specifications for IDatabase.
isCompatible( $other)
Check whether the domain $other meets the specifications of this domain.
__construct( $database, $schema, $prefix)