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