3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
21 namespace MediaWiki\Site
;
23 use InvalidArgumentException
;
24 use MediaWiki\MainConfigNames
;
25 use MediaWiki\MediaWikiServices
;
27 use UnexpectedValueException
;
30 * Represents a single site.
34 * @author Jeroen De Dauw < jeroendedauw@gmail.com >
37 public const TYPE_UNKNOWN
= 'unknown';
38 public const TYPE_MEDIAWIKI
= 'mediawiki';
40 public const GROUP_NONE
= 'none';
42 public const ID_INTERWIKI
= 'interwiki';
43 public const ID_EQUIVALENT
= 'equivalent';
45 public const SOURCE_LOCAL
= 'local';
47 public const PATH_LINK
= 'link';
50 * A version ID that identifies the serialization structure used by getSerializationData()
51 * and unserialize(). This is useful for constructing cache keys in cases where the cache relies
52 * on serialization for storing the SiteList.
54 * @var string A string uniquely identifying the version of the serialization structure.
56 public const SERIAL_VERSION_ID
= '2013-01-23';
63 protected $globalId = null;
70 protected $type = self
::TYPE_UNKNOWN
;
77 protected $group = self
::GROUP_NONE
;
84 protected $source = self
::SOURCE_LOCAL
;
91 protected $languageCode = null;
94 * Holds the local ids for this site.
95 * local id type => [ ids for this type (strings) ]
99 * @var string[][]|false
101 protected $localIds = [];
108 protected $extraData = [];
115 protected $extraConfig = [];
122 protected $forward = false;
129 protected $internalId = null;
134 * @param string $type
136 public function __construct( $type = self
::TYPE_UNKNOWN
) {
141 * Returns the global site identifier (ie enwiktionary).
145 * @return string|null
147 public function getGlobalId() {
148 return $this->globalId
;
152 * Sets the global site identifier (ie enwiktionary).
155 * @param string|null $globalId
157 public function setGlobalId( ?
string $globalId ) {
158 $this->globalId
= $globalId;
162 * Returns the type of the site (ie mediawiki).
168 public function getType() {
173 * Gets the group of the site (ie wikipedia).
179 public function getGroup() {
184 * Sets the group of the site (ie wikipedia).
187 * @param string $group
189 public function setGroup( string $group ) {
190 $this->group
= $group;
194 * Returns the source of the site data (ie 'local', 'wikidata', 'my-magical-repo').
200 public function getSource() {
201 return $this->source
;
205 * Sets the source of the site data (ie 'local', 'wikidata', 'my-magical-repo').
208 * @param string $source
210 public function setSource( string $source ) {
211 $this->source
= $source;
215 * Gets if site.tld/path/key:pageTitle should forward users to the page on
216 * the actual site, where "key" is the local identifier.
222 public function shouldForward() {
223 return $this->forward
;
227 * Sets if site.tld/path/key:pageTitle should forward users to the page on
228 * the actual site, where "key" is the local identifier.
231 * @param bool $shouldForward
233 public function setForward( bool $shouldForward ) {
234 $this->forward
= $shouldForward;
238 * Returns the domain of the site, ie en.wikipedia.org
239 * Or null if it's not known.
243 * @return string|null
245 public function getDomain(): ?
string {
246 $path = $this->getLinkPath();
248 if ( $path === null ) {
252 $domain = parse_url( $path, PHP_URL_HOST
);
254 if ( $domain === false ) {
262 * Returns the protocol of the site.
267 public function getProtocol() {
268 $path = $this->getLinkPath();
270 if ( $path === null ) {
274 $protocol = parse_url( $path, PHP_URL_SCHEME
);
277 if ( $protocol === false ) {
278 throw new UnexpectedValueException( "failed to parse URL '$path'" );
281 // Used for protocol relative URLs
282 return $protocol ??
'';
286 * Set the path used to construct links with.
288 * Shall be equivalent to setPath( getLinkPathType(), $fullUrl ).
290 * @param string $fullUrl
293 public function setLinkPath( $fullUrl ) {
294 $type = $this->getLinkPathType();
296 if ( $type === null ) {
297 throw new RuntimeException( "This Site does not support link paths." );
300 $this->setPath( $type, $fullUrl );
304 * Returns the path used to construct links with or false if there is no such path.
306 * Shall be equivalent to getPath( getLinkPathType() ).
308 * @return string|null
310 public function getLinkPath() {
311 $type = $this->getLinkPathType();
312 return $type === null ?
null : $this->getPath( $type );
316 * Returns the main path type, that is the type of the path that should
317 * generally be used to construct links to the target site.
319 * This default implementation returns Site::PATH_LINK as the default path
320 * type. Subclasses can override this to define a different default path
321 * type, or return false to disable site links.
325 * @return string|null
327 public function getLinkPathType() {
328 return self
::PATH_LINK
;
332 * Get the full URL for the given page on the site.
334 * Returns null if the needed information is not known.
336 * This generated URL is usually based upon the path returned by getLinkPath(),
337 * but this is not a requirement.
339 * This implementation returns a URL constructed using the path returned by getLinkPath().
342 * @param string|false $pageName
343 * @return string|null
345 public function getPageUrl( $pageName = false ) {
346 $url = $this->getLinkPath();
348 if ( $url === null ) {
352 if ( $pageName !== false ) {
353 $url = str_replace( '$1', rawurlencode( $pageName ), $url );
360 * Attempt to normalize the page name in some fashion.
361 * May return false to indicate various kinds of failure.
363 * This implementation returns $pageName without changes.
365 * @see Site::normalizePageName
368 * @since 1.37 Added $followRedirect
370 * @param string $pageName
371 * @param int $followRedirect either MediaWikiPageNameNormalizer::FOLLOW_REDIRECT or
372 * MediaWikiPageNameNormalizer::NOFOLLOW_REDIRECT
374 * @return string|false
376 public function normalizePageName( $pageName, $followRedirect = MediaWikiPageNameNormalizer
::FOLLOW_REDIRECT
) {
381 * Returns the type specific fields.
387 public function getExtraData() {
388 return $this->extraData
;
392 * Sets the type specific fields.
396 * @param array $extraData
398 public function setExtraData( array $extraData ) {
399 $this->extraData
= $extraData;
403 * Returns the type specific config.
409 public function getExtraConfig() {
410 return $this->extraConfig
;
414 * Sets the type specific config.
418 * @param array $extraConfig
420 public function setExtraConfig( array $extraConfig ) {
421 $this->extraConfig
= $extraConfig;
425 * Returns language code of the sites primary language.
426 * Or null if it's not known.
430 * @return string|null
432 public function getLanguageCode() {
433 return $this->languageCode
;
437 * Sets language code of the sites primary language.
441 * @param string|null $languageCode
443 public function setLanguageCode( $languageCode ) {
444 if ( $languageCode !== null &&
445 !MediaWikiServices
::getInstance()->getLanguageNameUtils()->isValidCode( $languageCode ) ) {
446 throw new InvalidArgumentException( "$languageCode is not a valid language code." );
448 $this->languageCode
= $languageCode;
452 * Returns the set internal identifier for the site.
458 public function getInternalId() {
459 return $this->internalId
;
463 * Sets the internal identifier for the site.
464 * This typically is a primary key in a db table.
468 * @param int|null $internalId
470 public function setInternalId( $internalId = null ) {
471 $this->internalId
= $internalId;
475 * Adds a local identifier.
479 * @param string $type
480 * @param string $identifier
482 public function addLocalId( $type, $identifier ) {
483 if ( $this->localIds
=== false ) {
484 $this->localIds
= [];
487 $this->localIds
[$type] ??
= [];
489 if ( !in_array( $identifier, $this->localIds
[$type] ) ) {
490 $this->localIds
[$type][] = $identifier;
495 * Adds an interwiki id to the site.
499 * @param string $identifier
501 public function addInterwikiId( $identifier ) {
502 $this->addLocalId( self
::ID_INTERWIKI
, $identifier );
506 * Adds a navigation id to the site.
510 * @param string $identifier
512 public function addNavigationId( $identifier ) {
513 $this->addLocalId( self
::ID_EQUIVALENT
, $identifier );
517 * Returns the interwiki link identifiers that can be used for this site.
523 public function getInterwikiIds() {
524 return $this->localIds
[self
::ID_INTERWIKI
] ??
[];
528 * Returns the equivalent link identifiers that can be used to make
529 * the site show up in interfaces such as the "language links" section.
535 public function getNavigationIds() {
536 return $this->localIds
[self
::ID_EQUIVALENT
] ??
[];
540 * Returns all local ids
546 public function getLocalIds() {
547 return $this->localIds
;
551 * Set the path used to construct links with.
553 * Shall be equivalent to setPath( getLinkPathType(), $fullUrl ).
556 * @param string $pathType
557 * @param string $fullUrl
559 public function setPath( $pathType, string $fullUrl ) {
560 $this->extraData
['paths'][$pathType] = $fullUrl;
564 * Returns the path of the provided type or null if there is no such path.
568 * @param string $pathType
570 * @return string|null
572 public function getPath( $pathType ) {
573 $paths = $this->getAllPaths();
574 return $paths[$pathType] ??
null;
578 * Returns the paths as associative array.
579 * The keys are path types, the values are the path urls.
585 public function getAllPaths() {
586 return $this->extraData
['paths'] ??
[];
590 * Removes the path of the provided type if it's set.
594 * @param string $pathType
596 public function removePath( $pathType ) {
597 if ( array_key_exists( 'paths', $this->extraData
) ) {
598 unset( $this->extraData
['paths'][$pathType] );
605 * @param string $siteType
609 public static function newForType( $siteType ) {
610 /** @var class-string<Site>[] $siteTypes */
611 $siteTypes = MediaWikiServices
::getInstance()->getMainConfig()->get(
612 MainConfigNames
::SiteTypes
615 if ( array_key_exists( $siteType, $siteTypes ) ) {
616 return new $siteTypes[$siteType]();
623 * @see Serializable::serialize
629 public function __serialize() {
631 'globalid' => $this->globalId
,
632 'type' => $this->type
,
633 'group' => $this->group
,
634 'source' => $this->source
,
635 'language' => $this->languageCode
,
636 'localids' => $this->localIds
,
637 'config' => $this->extraConfig
,
638 'data' => $this->extraData
,
639 'forward' => $this->forward
,
640 'internalid' => $this->internalId
,
645 * @see Serializable::unserialize
649 * @param array $fields
651 public function __unserialize( $fields ) {
652 $this->__construct( $fields['type'] );
654 $this->setGlobalId( $fields['globalid'] );
655 $this->setGroup( $fields['group'] );
656 $this->setSource( $fields['source'] );
657 $this->setLanguageCode( $fields['language'] );
658 $this->localIds
= $fields['localids'];
659 $this->setExtraConfig( $fields['config'] );
660 $this->setExtraData( $fields['data'] );
661 $this->setForward( $fields['forward'] );
662 $this->setInternalId( $fields['internalid'] );
666 /** @deprecated class alias since 1.42 */
667 class_alias( Site
::class, 'Site' );