WikiMap   A
last analyzed

Complexity

Total Complexity 24

Size/Duplication

Total Lines 152
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 152
rs 10
wmc 24
lcom 1
cbo 5

7 Methods

Rating   Name   Duplication   Size   Complexity  
A getWiki() 0 9 2
C getWikiReferenceFromWgConf() 0 30 7
C getWikiWikiReferenceFromSites() 0 26 7
A getWikiName() 0 8 2
A foreignUserLink() 0 3 1
A makeForeignLink() 0 12 3
A getForeignURL() 0 9 2
1
<?php
2
/**
3
 * Tools for dealing with other locally-hosted wikis.
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License along
16
 * with this program; if not, write to the Free Software Foundation, Inc.,
17
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
 * http://www.gnu.org/copyleft/gpl.html
19
 *
20
 * @file
21
 */
22
23
/**
24
 * Helper tools for dealing with other wikis.
25
 */
26
class WikiMap {
27
28
	/**
29
	 * Get a WikiReference object for $wikiID
30
	 *
31
	 * @param string $wikiID Wiki'd id (generally database name)
32
	 * @return WikiReference|null WikiReference object or null if the wiki was not found
33
	 */
34
	public static function getWiki( $wikiID ) {
35
		$wikiReference = self::getWikiReferenceFromWgConf( $wikiID );
36
		if ( $wikiReference ) {
37
			return $wikiReference;
38
		}
39
40
		// Try sites, if $wgConf failed
41
		return self::getWikiWikiReferenceFromSites( $wikiID );
42
	}
43
44
	/**
45
	 * @param string $wikiID
46
	 * @return WikiReference|null WikiReference object or null if the wiki was not found
47
	 */
48
	private static function getWikiReferenceFromWgConf( $wikiID ) {
49
		global $wgConf;
50
51
		$wgConf->loadFullData();
52
53
		list( $major, $minor ) = $wgConf->siteFromDB( $wikiID );
54
		if ( $major === null ) {
55
			return null;
56
		}
57
		$server = $wgConf->get( 'wgServer', $wikiID, $major,
58
			[ 'lang' => $minor, 'site' => $major ] );
59
60
		$canonicalServer = $wgConf->get( 'wgCanonicalServer', $wikiID, $major,
61
			[ 'lang' => $minor, 'site' => $major ] );
62
		if ( $canonicalServer === false || $canonicalServer === null ) {
63
			$canonicalServer = $server;
64
		}
65
66
		$path = $wgConf->get( 'wgArticlePath', $wikiID, $major,
67
			[ 'lang' => $minor, 'site' => $major ] );
68
69
		// If we don't have a canonical server or a path containing $1, the
70
		// WikiReference isn't going to function properly. Just return null in
71
		// that case.
72
		if ( !is_string( $canonicalServer ) || !is_string( $path ) || strpos( $path, '$1' ) === false ) {
73
			return null;
74
		}
75
76
		return new WikiReference( $canonicalServer, $path, $server );
77
	}
78
79
	/**
80
	 * @param string $wikiID
81
	 * @return WikiReference|null WikiReference object or null if the wiki was not found
82
	 */
83
	private static function getWikiWikiReferenceFromSites( $wikiID ) {
84
		$siteLookup = \MediaWiki\MediaWikiServices::getInstance()->getSiteLookup();
85
		$site = $siteLookup->getSite( $wikiID );
86
87
		if ( !$site instanceof MediaWikiSite ) {
88
			// Abort if not a MediaWikiSite, as this is about Wikis
89
			return null;
90
		}
91
92
		$urlParts = wfParseUrl( $site->getPageUrl() );
0 ignored issues
show
Bug introduced by
It seems like $site->getPageUrl() targeting MediaWikiSite::getPageUrl() can also be of type false or null; however, wfParseUrl() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
93
		if ( $urlParts === false || !isset( $urlParts['path'] ) || !isset( $urlParts['host'] ) ) {
94
			// We can't create a meaningful WikiReference without URLs
95
			return null;
96
		}
97
98
		// XXX: Check whether path contains a $1?
99
		$path = $urlParts['path'];
100
		if ( isset( $urlParts['query'] ) ) {
101
			$path .= '?' . $urlParts['query'];
102
		}
103
104
		$canonicalServer = isset( $urlParts['scheme'] ) ? $urlParts['scheme'] : 'http';
105
		$canonicalServer .= '://' . $urlParts['host'];
106
107
		return new WikiReference( $canonicalServer, $path );
108
	}
109
110
	/**
111
	 * Convenience to get the wiki's display name
112
	 *
113
	 * @todo We can give more info than just the wiki id!
114
	 * @param string $wikiID Wiki'd id (generally database name)
115
	 * @return string|int Wiki's name or $wiki_id if the wiki was not found
116
	 */
117
	public static function getWikiName( $wikiID ) {
118
		$wiki = WikiMap::getWiki( $wikiID );
119
120
		if ( $wiki ) {
121
			return $wiki->getDisplayName();
122
		}
123
		return $wikiID;
124
	}
125
126
	/**
127
	 * Convenience to get a link to a user page on a foreign wiki
128
	 *
129
	 * @param string $wikiID Wiki'd id (generally database name)
130
	 * @param string $user User name (must be normalised before calling this function!)
131
	 * @param string $text Link's text; optional, default to "User:$user"
132
	 * @return string HTML link or false if the wiki was not found
133
	 */
134
	public static function foreignUserLink( $wikiID, $user, $text = null ) {
135
		return self::makeForeignLink( $wikiID, "User:$user", $text );
136
	}
137
138
	/**
139
	 * Convenience to get a link to a page on a foreign wiki
140
	 *
141
	 * @param string $wikiID Wiki'd id (generally database name)
142
	 * @param string $page Page name (must be normalised before calling this function!)
143
	 * @param string $text Link's text; optional, default to $page
144
	 * @return string HTML link or false if the wiki was not found
145
	 */
146
	public static function makeForeignLink( $wikiID, $page, $text = null ) {
147
		if ( !$text ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $text of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
148
			$text = $page;
149
		}
150
151
		$url = self::getForeignURL( $wikiID, $page );
152
		if ( $url === false ) {
153
			return false;
154
		}
155
156
		return Linker::makeExternalLink( $url, $text );
157
	}
158
159
	/**
160
	 * Convenience to get a url to a page on a foreign wiki
161
	 *
162
	 * @param string $wikiID Wiki'd id (generally database name)
163
	 * @param string $page Page name (must be normalised before calling this function!)
164
	 * @param string|null $fragmentId
165
	 *
166
	 * @return string|bool URL or false if the wiki was not found
167
	 */
168
	public static function getForeignURL( $wikiID, $page, $fragmentId = null ) {
169
		$wiki = WikiMap::getWiki( $wikiID );
170
171
		if ( $wiki ) {
172
			return $wiki->getFullUrl( $page, $fragmentId );
173
		}
174
175
		return false;
176
	}
177
}
178
179
/**
180
 * Reference to a locally-hosted wiki
181
 */
182
class WikiReference {
183
	private $mCanonicalServer; ///< canonical server URL, e.g. 'https://www.mediawiki.org'
184
	private $mServer; ///< server URL, may be protocol-relative, e.g. '//www.mediawiki.org'
185
	private $mPath;   ///< path, '/wiki/$1'
186
187
	/**
188
	 * @param string $canonicalServer
189
	 * @param string $path
190
	 * @param null|string $server
191
	 */
192
	public function __construct( $canonicalServer, $path, $server = null ) {
193
		$this->mCanonicalServer = $canonicalServer;
194
		$this->mPath = $path;
195
		$this->mServer = $server === null ? $canonicalServer : $server;
196
	}
197
198
	/**
199
	 * Get the URL in a way to be displayed to the user
200
	 * More or less Wikimedia specific
201
	 *
202
	 * @return string
203
	 */
204
	public function getDisplayName() {
205
		$parsed = wfParseUrl( $this->mCanonicalServer );
206
		if ( $parsed ) {
207
			return $parsed['host'];
208
		} else {
209
			// Invalid server spec.
210
			// There's no sane thing to do here, so just return the canonical server name in full.
211
			return $this->mCanonicalServer;
212
		}
213
	}
214
215
	/**
216
	 * Helper function for getUrl()
217
	 *
218
	 * @todo FIXME: This may be generalized...
219
	 *
220
	 * @param string $page Page name (must be normalised before calling this function!
221
	 *  May contain a section part.)
222
	 * @param string|null $fragmentId
223
	 *
224
	 * @return string relative URL, without the server part.
225
	 */
226
	private function getLocalUrl( $page, $fragmentId = null ) {
227
		$page = wfUrlencode( str_replace( ' ', '_', $page ) );
228
229
		if ( is_string( $fragmentId ) && $fragmentId !== '' ) {
230
			$page .= '#' . wfUrlencode( $fragmentId );
231
		}
232
233
		return str_replace( '$1', $page, $this->mPath );
234
	}
235
236
	/**
237
	 * Get a canonical (i.e. based on $wgCanonicalServer) URL to a page on this foreign wiki
238
	 *
239
	 * @param string $page Page name (must be normalised before calling this function!)
240
	 * @param string|null $fragmentId
241
	 *
242
	 * @return string Url
243
	 */
244
	public function getCanonicalUrl( $page, $fragmentId = null ) {
245
		return $this->mCanonicalServer . $this->getLocalUrl( $page, $fragmentId );
246
	}
247
248
	/**
249
	 * Get a canonical server URL
250
	 * @return string
251
	 */
252
	public function getCanonicalServer() {
253
		return $this->mCanonicalServer;
254
	}
255
256
	/**
257
	 * Alias for getCanonicalUrl(), for backwards compatibility.
258
	 * @param string $page
259
	 * @param string|null $fragmentId
260
	 *
261
	 * @return string
262
	 */
263
	public function getUrl( $page, $fragmentId = null ) {
264
		return $this->getCanonicalUrl( $page, $fragmentId );
265
	}
266
267
	/**
268
	 * Get a URL based on $wgServer, like Title::getFullURL() would produce
269
	 * when called locally on the wiki.
270
	 *
271
	 * @param string $page Page name (must be normalized before calling this function!)
272
	 * @param string|null $fragmentId
273
	 *
274
	 * @return string URL
275
	 */
276
	public function getFullUrl( $page, $fragmentId = null ) {
277
		return $this->mServer .
278
			$this->getLocalUrl( $page, $fragmentId );
279
	}
280
}
281