* @file
*/
+use MediaWiki\MediaWikiServices;
+use Wikimedia\Rdbms\DatabaseDomain;
+
/**
- * Helper tools for dealing with other wikis.
+ * Helper tools for dealing with other locally-hosted wikis.
*/
class WikiMap {
* @return WikiReference|null WikiReference object or null if the wiki was not found
*/
private static function getWikiWikiReferenceFromSites( $wikiID ) {
- $siteLookup = \MediaWiki\MediaWikiServices::getInstance()->getSiteLookup();
+ $siteLookup = MediaWikiServices::getInstance()->getSiteLookup();
$site = $siteLookup->getSite( $wikiID );
if ( !$site instanceof MediaWikiSite ) {
$path .= '?' . $urlParts['query'];
}
- $canonicalServer = isset( $urlParts['scheme'] ) ? $urlParts['scheme'] : 'http';
+ $canonicalServer = $urlParts['scheme'] ?? 'http';
$canonicalServer .= '://' . $urlParts['host'];
return new WikiReference( $canonicalServer, $path );
*
* @param string $wikiID Wiki'd id (generally database name)
* @param string $user User name (must be normalised before calling this function!)
- * @param string $text Link's text; optional, default to "User:$user"
+ * @param string|null $text Link's text; optional, default to "User:$user"
* @return string HTML link or false if the wiki was not found
*/
public static function foreignUserLink( $wikiID, $user, $text = null ) {
*
* @param string $wikiID Wiki'd id (generally database name)
* @param string $page Page name (must be normalised before calling this function!)
- * @param string $text Link's text; optional, default to $page
+ * @param string|null $text Link's text; optional, default to $page
* @return string|false HTML link or false if the wiki was not found
*/
public static function makeForeignLink( $wikiID, $page, $text = null ) {
return false;
}
+
+ /**
+ * Get canonical server info for all local wikis in the map that have one
+ *
+ * @return array Map of (local wiki ID => map of (url,parts))
+ * @since 1.30
+ */
+ public static function getCanonicalServerInfoForAllWikis() {
+ $cache = MediaWikiServices::getInstance()->getLocalServerObjectCache();
+
+ return $cache->getWithSetCallback(
+ $cache->makeGlobalKey( 'wikimap', 'canonical-urls' ),
+ $cache::TTL_DAY,
+ function () {
+ global $wgLocalDatabases, $wgCanonicalServer;
+
+ $infoMap = [];
+ // Make sure at least the current wiki is set, for simple configurations.
+ // This also makes it the first in the map, which is useful for common cases.
+ $wikiId = self::getWikiIdFromDbDomain( self::getCurrentWikiDbDomain() );
+ $infoMap[$wikiId] = [
+ 'url' => $wgCanonicalServer,
+ 'parts' => wfParseUrl( $wgCanonicalServer )
+ ];
+
+ foreach ( $wgLocalDatabases as $wikiId ) {
+ $wikiReference = self::getWiki( $wikiId );
+ if ( $wikiReference ) {
+ $url = $wikiReference->getCanonicalServer();
+ $infoMap[$wikiId] = [ 'url' => $url, 'parts' => wfParseUrl( $url ) ];
+ }
+ }
+
+ return $infoMap;
+ }
+ );
+ }
+
+ /**
+ * @param string $url
+ * @return bool|string Wiki ID or false
+ * @since 1.30
+ */
+ public static function getWikiFromUrl( $url ) {
+ global $wgCanonicalServer;
+
+ if ( strpos( $url, "$wgCanonicalServer/" ) === 0 ) {
+ // Optimisation: Handle the the common case.
+ // (Duplicates self::getCanonicalServerInfoForAllWikis)
+ return self::getWikiIdFromDbDomain( self::getCurrentWikiDbDomain() );
+ }
+
+ $urlPartsCheck = wfParseUrl( $url );
+ if ( $urlPartsCheck === false ) {
+ return false;
+ }
+
+ static $relevantKeys = [ 'host' => 1, 'port' => 1 ];
+ $urlPartsCheck = array_intersect_key( $urlPartsCheck, $relevantKeys );
+
+ foreach ( self::getCanonicalServerInfoForAllWikis() as $wikiId => $info ) {
+ $urlParts = $info['parts'];
+ if ( $urlParts === false ) {
+ continue; // sanity
+ }
+
+ $urlParts = array_intersect_key( $urlParts, $relevantKeys );
+ if ( $urlParts == $urlPartsCheck ) {
+ return $wikiId;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Get the wiki ID of a database domain
+ *
+ * This is like DatabaseDomain::getId() without encoding (for legacy reasons) and
+ * without the schema if it is the generic installer default of "mediawiki"/"dbo"
+ *
+ * @see $wgDBmwschema
+ * @see PostgresInstaller
+ * @see MssqlInstaller
+ *
+ * @param string|DatabaseDomain $domain
+ * @return string
+ * @since 1.31
+ */
+ public static function getWikiIdFromDbDomain( $domain ) {
+ $domain = DatabaseDomain::newFromId( $domain );
+ // Since the schema was not always part of the wiki ID, try to maintain backwards
+ // compatibility with some common cases. Assume that if the DB domain schema is just
+ // the installer default then it is probably the case that the schema is the same for
+ // all wikis in the farm. Historically, any wiki farm had to make the database/prefix
+ // combination unique per wiki. Ommit the schema if it does not seem wiki specific.
+ if ( !in_array( $domain->getSchema(), [ null, 'mediawiki', 'dbo' ], true ) ) {
+ // This means a site admin may have specifically taylored the schemas.
+ // Domain IDs might use the form <DB>-<project>- or <DB>-<project>-<language>_,
+ // meaning that the schema portion must be accounted for to disambiguate wikis.
+ return "{$domain->getDatabase()}-{$domain->getSchema()}-{$domain->getTablePrefix()}";
+ }
+ // Note that if this wiki ID is passed a a domain ID to LoadBalancer, then it can
+ // handle the schema by assuming the generic "mediawiki" schema if needed.
+ return strlen( $domain->getTablePrefix() )
+ ? "{$domain->getDatabase()}-{$domain->getTablePrefix()}"
+ : (string)$domain->getDatabase();
+ }
+
+ /**
+ * @param string $domain
+ * @return string
+ * @deprecated Since 1.33; use getWikiIdFromDbDomain()
+ */
+ public static function getWikiIdFromDomain( $domain ) {
+ return self::getWikiIdFromDbDomain( $domain );
+ }
+
+ /**
+ * @return DatabaseDomain Database domain of the current wiki
+ * @since 1.33
+ */
+ public static function getCurrentWikiDbDomain() {
+ global $wgDBname, $wgDBmwschema, $wgDBprefix;
+ // Avoid invoking LBFactory to avoid any chance of recursion
+ return new DatabaseDomain( $wgDBname, $wgDBmwschema, (string)$wgDBprefix );
+ }
+
+ /**
+ * @param DatabaseDomain|string $domain
+ * @return bool Whether $domain matches the DB domain of the current wiki
+ * @since 1.33
+ */
+ public static function isCurrentWikiDbDomain( $domain ) {
+ return self::getCurrentWikiDbDomain()->equals( DatabaseDomain::newFromId( $domain ) );
+ }
+
+ /**
+ * @param string $wikiId
+ * @return bool Whether $wikiId matches the wiki ID of the current wiki
+ * @since 1.33
+ */
+ public static function isCurrentWikiId( $wikiId ) {
+ return ( self::getWikiIdFromDbDomain( self::getCurrentWikiDbDomain() ) === $wikiId );
+ }
}