MediaWiki  master
ExternalStoreFactory.php
Go to the documentation of this file.
1 <?php
2 
4 use Psr\Log\LoggerAwareInterface;
5 use Psr\Log\LoggerInterface;
6 use Psr\Log\NullLogger;
7 
14 class ExternalStoreFactory implements LoggerAwareInterface {
16  private $protocols;
18  private $writeBaseUrls;
20  private $localDomainId;
22  private $logger;
23 
30  public function __construct(
31  array $externalStores,
32  array $defaultStores,
33  string $localDomainId,
34  LoggerInterface $logger = null
35  ) {
36  $this->protocols = array_map( 'strtolower', $externalStores );
37  $this->writeBaseUrls = $defaultStores;
38  $this->localDomainId = $localDomainId;
39  $this->logger = $logger ?: new NullLogger();
40  }
41 
42  public function setLogger( LoggerInterface $logger ) {
43  $this->logger = $logger;
44  }
45 
50  public function getProtocols() {
51  return $this->protocols;
52  }
53 
58  public function getWriteBaseUrls() {
59  return $this->writeBaseUrls;
60  }
61 
74  public function getStore( $proto, array $params = [] ) {
75  $protoLowercase = strtolower( $proto ); // normalize
76  if ( !$this->protocols || !in_array( $protoLowercase, $this->protocols ) ) {
77  throw new ExternalStoreException( "Protocol '$proto' is not enabled." );
78  }
79 
80  if ( $protoLowercase === 'db' ) {
81  $class = 'ExternalStoreDB';
82  } else {
83  $class = 'ExternalStore' . ucfirst( $proto );
84  }
85  if ( isset( $params['wiki'] ) ) {
86  $params += [ 'domain' => $params['wiki'] ]; // b/c
87  }
88  if ( !isset( $params['domain'] ) || $params['domain'] === false ) {
89  $params['domain'] = $this->localDomainId; // default
90  $params['isDomainImplicit'] = true; // b/c for ExternalStoreDB
91  }
92  // @TODO: ideally, this class should not hardcode what classes need what backend factory
93  // objects. For now, inject the factory instances into __construct() for those that do.
94  if ( $protoLowercase === 'db' ) {
95  $params['lbFactory'] = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
96  } elseif ( $protoLowercase === 'mwstore' ) {
97  $params['fbGroup'] = MediaWikiServices::getInstance()->getFileBackendGroup();
98  }
99  $params['logger'] = $this->logger;
100 
101  if ( !class_exists( $class ) ) {
102  throw new ExternalStoreException( "Class '$class' is not defined." );
103  }
104 
105  // Any custom modules should be added to $wgAutoLoadClasses for on-demand loading
106  return new $class( $params );
107  }
108 
122  public function getStoreForUrl( $url, array $params = [] ) {
123  [ $proto, $path ] = self::splitStorageUrl( $url );
124  if ( $path == '' ) { // bad URL
125  throw new ExternalStoreException( "Invalid URL '$url'" );
126  }
127 
128  return $this->getStore( $proto, $params );
129  }
130 
139  public function getStoreLocationFromUrl( $url ) {
140  [ , $location ] = self::splitStorageUrl( $url );
141  if ( $location == '' ) { // bad URL
142  throw new ExternalStoreException( "Invalid URL '$url'" );
143  }
144 
145  return $location;
146  }
147 
154  public function getUrlsByProtocol( array $urls ) {
155  $urlsByProtocol = [];
156  foreach ( $urls as $url ) {
157  [ $proto, ] = self::splitStorageUrl( $url );
158  $urlsByProtocol[$proto][] = $url;
159  }
160 
161  return $urlsByProtocol;
162  }
163 
169  private static function splitStorageUrl( $storeUrl ) {
170  $parts = explode( '://', $storeUrl );
171  if ( count( $parts ) != 2 || $parts[0] === '' || $parts[1] === '' ) {
172  throw new ExternalStoreException( "Invalid storage URL '$storeUrl'" );
173  }
174 
175  return $parts;
176  }
177 }
setLogger(LoggerInterface $logger)
__construct(array $externalStores, array $defaultStores, string $localDomainId, LoggerInterface $logger=null)
getStore( $proto, array $params=[])
Get an external store object of the given type, with the given parameters.
getStoreForUrl( $url, array $params=[])
Get the ExternalStoreMedium for a given URL.
getStoreLocationFromUrl( $url)
Get the location within the appropriate store for a given a URL.
Service locator for MediaWiki core services.