Merge "By default, keep users in HTTPS with wgSecureLogin"
[lhc/web/wiklou.git] / includes / site / Site.php
1 <?php
2
3 /**
4 * Represents a single site.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 * @since 1.21
22 *
23 * @file
24 * @ingroup Site
25 *
26 * @license GNU GPL v2+
27 * @author Jeroen De Dauw < jeroendedauw@gmail.com >
28 */
29 class Site implements Serializable {
30
31 const TYPE_UNKNOWN = 'unknown';
32 const TYPE_MEDIAWIKI = 'mediawiki';
33
34 const GROUP_NONE = 'none';
35
36 const ID_INTERWIKI = 'interwiki';
37 const ID_EQUIVALENT = 'equivalent';
38
39 const SOURCE_LOCAL = 'local';
40
41 const PATH_LINK = 'link';
42
43
44 /**
45 * A version ID that identifies the serialization structure used by getSerializationData()
46 * and unserialize(). This is useful for constructing cache keys in cases where the cache relies
47 * on serialization for storing the SiteList.
48 *
49 * @var string A string uniquely identifying the version of the serialization structure.
50 */
51 const SERIAL_VERSION_ID = '2013-01-23';
52
53 /**
54 * @since 1.21
55 *
56 * @var string|null
57 */
58 protected $globalId = null;
59
60 /**
61 * @since 1.21
62 *
63 * @var string
64 */
65 protected $type = self::TYPE_UNKNOWN;
66
67 /**
68 * @since 1.21
69 *
70 * @var string
71 */
72 protected $group = self::GROUP_NONE;
73
74 /**
75 * @since 1.21
76 *
77 * @var string
78 */
79 protected $source = self::SOURCE_LOCAL;
80
81 /**
82 * @since 1.21
83 *
84 * @var string|null
85 */
86 protected $languageCode = null;
87
88 /**
89 * Holds the local ids for this site.
90 * local id type => [ ids for this type (strings) ]
91 *
92 * @since 1.21
93 *
94 * @var array[]
95 */
96 protected $localIds = array();
97
98 /**
99 * @since 1.21
100 *
101 * @var array
102 */
103 protected $extraData = array();
104
105 /**
106 * @since 1.21
107 *
108 * @var array
109 */
110 protected $extraConfig = array();
111
112 /**
113 * @since 1.21
114 *
115 * @var bool
116 */
117 protected $forward = false;
118
119 /**
120 * @since 1.21
121 *
122 * @var int|null
123 */
124 protected $internalId = null;
125
126 /**
127 * Constructor.
128 *
129 * @since 1.21
130 *
131 * @param string $type
132 */
133 public function __construct( $type = self::TYPE_UNKNOWN ) {
134 $this->type = $type;
135 }
136
137 /**
138 * Returns the global site identifier (ie enwiktionary).
139 *
140 * @since 1.21
141 *
142 * @return string|null
143 */
144 public function getGlobalId() {
145 return $this->globalId;
146 }
147
148 /**
149 * Sets the global site identifier (ie enwiktionary).
150 *
151 * @since 1.21
152 *
153 * @param string|null $globalId
154 *
155 * @throws MWException
156 */
157 public function setGlobalId( $globalId ) {
158 if ( $globalId !== null && !is_string( $globalId ) ) {
159 throw new MWException( '$globalId needs to be string or null' );
160 }
161
162 $this->globalId = $globalId;
163 }
164
165 /**
166 * Returns the type of the site (ie mediawiki).
167 *
168 * @since 1.21
169 *
170 * @return string
171 */
172 public function getType() {
173 return $this->type;
174 }
175
176 /**
177 * Gets the type of the site (ie wikipedia).
178 *
179 * @since 1.21
180 *
181 * @return string
182 */
183 public function getGroup() {
184 return $this->group;
185 }
186
187 /**
188 * Sets the type of the site (ie wikipedia).
189 *
190 * @since 1.21
191 *
192 * @param string $group
193 *
194 * @throws MWException
195 */
196 public function setGroup( $group ) {
197 if ( !is_string( $group ) ) {
198 throw new MWException( '$group needs to be a string' );
199 }
200
201 $this->group = $group;
202 }
203
204 /**
205 * Returns the source of the site data (ie 'local', 'wikidata', 'my-magical-repo').
206 *
207 * @since 1.21
208 *
209 * @return string
210 */
211 public function getSource() {
212 return $this->source;
213 }
214
215 /**
216 * Sets the source of the site data (ie 'local', 'wikidata', 'my-magical-repo').
217 *
218 * @since 1.21
219 *
220 * @param string $source
221 *
222 * @throws MWException
223 */
224 public function setSource( $source ) {
225 if ( !is_string( $source ) ) {
226 throw new MWException( '$source needs to be a string' );
227 }
228
229 $this->source = $source;
230 }
231
232 /**
233 * Gets if site.tld/path/key:pageTitle should forward users to the page on
234 * the actual site, where "key" is the local identifier.
235 *
236 * @since 1.21
237 *
238 * @return boolean
239 */
240 public function shouldForward() {
241 return $this->forward;
242 }
243
244 /**
245 * Sets if site.tld/path/key:pageTitle should forward users to the page on
246 * the actual site, where "key" is the local identifier.
247 *
248 * @since 1.21
249 *
250 * @param boolean $shouldForward
251 *
252 * @throws MWException
253 */
254 public function setForward( $shouldForward ) {
255 if ( !is_bool( $shouldForward ) ) {
256 throw new MWException( '$shouldForward needs to be a boolean' );
257 }
258
259 $this->forward = $shouldForward;
260 }
261
262 /**
263 * Returns the domain of the site, ie en.wikipedia.org
264 * Or false if it's not known.
265 *
266 * @since 1.21
267 *
268 * @return string|null
269 */
270 public function getDomain() {
271 $path = $this->getLinkPath();
272
273 if ( $path === null ) {
274 return null;
275 }
276
277 return parse_url( $path, PHP_URL_HOST );
278 }
279
280 /**
281 * Returns the protocol of the site.
282 *
283 * @since 1.21
284 *
285 * @throws MWException
286 * @return string
287 */
288 public function getProtocol() {
289 $path = $this->getLinkPath();
290
291 if ( $path === null ) {
292 return '';
293 }
294
295 $protocol = parse_url( $path, PHP_URL_SCHEME );
296
297 // Malformed URL
298 if ( $protocol === false ) {
299 throw new MWException( "failed to parse URL '$path'" );
300 }
301
302 // No schema
303 if ( $protocol === null ) {
304 // Used for protocol relative URLs
305 $protocol = '';
306 }
307
308 return $protocol;
309 }
310
311 /**
312 * Sets the path used to construct links with.
313 * Shall be equivalent to setPath( getLinkPathType(), $fullUrl ).
314 *
315 * @param string $fullUrl
316 *
317 * @since 1.21
318 *
319 * @throws MWException
320 */
321 public function setLinkPath( $fullUrl ) {
322 $type = $this->getLinkPathType();
323
324 if ( $type === null ) {
325 throw new MWException( "This Site does not support link paths." );
326 }
327
328 $this->setPath( $type, $fullUrl );
329 }
330
331 /**
332 * Returns the path used to construct links with or false if there is no such path.
333 *
334 * Shall be equivalent to getPath( getLinkPathType() ).
335 *
336 * @return string|null
337 */
338 public function getLinkPath() {
339 $type = $this->getLinkPathType();
340 return $type === null ? null: $this->getPath( $type );
341 }
342
343 /**
344 * Returns the main path type, that is the type of the path that should generally be used to construct links
345 * to the target site.
346 *
347 * This default implementation returns Site::PATH_LINK as the default path type. Subclasses can override this
348 * to define a different default path type, or return false to disable site links.
349 *
350 * @since 1.21
351 *
352 * @return string|null
353 */
354 public function getLinkPathType() {
355 return self::PATH_LINK;
356 }
357
358 /**
359 * Returns the full URL for the given page on the site.
360 * Or false if the needed information is not known.
361 *
362 * This generated URL is usually based upon the path returned by getLinkPath(),
363 * but this is not a requirement.
364 *
365 * This implementation returns a URL constructed using the path returned by getLinkPath().
366 *
367 * @since 1.21
368 *
369 * @param bool|String $pageName
370 *
371 * @return string|boolean false
372 */
373 public function getPageUrl( $pageName = false ) {
374 $url = $this->getLinkPath();
375
376 if ( $url === false ) {
377 return false;
378 }
379
380 if ( $pageName !== false ) {
381 $url = str_replace( '$1', rawurlencode( $pageName ), $url ) ;
382 }
383
384 return $url;
385 }
386
387 /**
388 * Returns $pageName without changes.
389 * Subclasses may override this to apply some kind of normalization.
390 *
391 * @see Site::normalizePageName
392 *
393 * @since 1.21
394 *
395 * @param string $pageName
396 *
397 * @return string
398 */
399 public function normalizePageName( $pageName ) {
400 return $pageName;
401 }
402
403 /**
404 * Returns the type specific fields.
405 *
406 * @since 1.21
407 *
408 * @return array
409 */
410 public function getExtraData() {
411 return $this->extraData;
412 }
413
414 /**
415 * Sets the type specific fields.
416 *
417 * @since 1.21
418 *
419 * @param array $extraData
420 */
421 public function setExtraData( array $extraData ) {
422 $this->extraData = $extraData;
423 }
424
425 /**
426 * Returns the type specific config.
427 *
428 * @since 1.21
429 *
430 * @return array
431 */
432 public function getExtraConfig() {
433 return $this->extraConfig;
434 }
435
436 /**
437 * Sets the type specific config.
438 *
439 * @since 1.21
440 *
441 * @param array $extraConfig
442 */
443 public function setExtraConfig( array $extraConfig ) {
444 $this->extraConfig = $extraConfig;
445 }
446
447 /**
448 * Returns language code of the sites primary language.
449 * Or null if it's not known.
450 *
451 * @since 1.21
452 *
453 * @return string|null
454 */
455 public function getLanguageCode() {
456 return $this->languageCode;
457 }
458
459 /**
460 * Sets language code of the sites primary language.
461 *
462 * @since 1.21
463 *
464 * @param string $languageCode
465 */
466 public function setLanguageCode( $languageCode ) {
467 $this->languageCode = $languageCode;
468 }
469
470 /**
471 * Returns the set internal identifier for the site.
472 *
473 * @since 1.21
474 *
475 * @return string|null
476 */
477 public function getInternalId() {
478 return $this->internalId;
479 }
480
481 /**
482 * Sets the internal identifier for the site.
483 * This typically is a primary key in a db table.
484 *
485 * @since 1.21
486 *
487 * @param int|null $internalId
488 */
489 public function setInternalId( $internalId = null ) {
490 $this->internalId = $internalId;
491 }
492
493 /**
494 * Adds a local identifier.
495 *
496 * @since 1.21
497 *
498 * @param string $type
499 * @param string $identifier
500 */
501 public function addLocalId( $type, $identifier ) {
502 if ( $this->localIds === false ) {
503 $this->localIds = array();
504 }
505
506 if ( !array_key_exists( $type, $this->localIds ) ) {
507 $this->localIds[$type] = array();
508 }
509
510 if ( !in_array( $identifier, $this->localIds[$type] ) ) {
511 $this->localIds[$type][] = $identifier;
512 }
513 }
514
515 /**
516 * Adds an interwiki id to the site.
517 *
518 * @since 1.21
519 *
520 * @param string $identifier
521 */
522 public function addInterwikiId( $identifier ) {
523 $this->addLocalId( self::ID_INTERWIKI, $identifier );
524 }
525
526 /**
527 * Adds a navigation id to the site.
528 *
529 * @since 1.21
530 *
531 * @param string $identifier
532 */
533 public function addNavigationId( $identifier ) {
534 $this->addLocalId( self::ID_EQUIVALENT, $identifier );
535 }
536
537 /**
538 * Returns the interwiki link identifiers that can be used for this site.
539 *
540 * @since 1.21
541 *
542 * @return string[]
543 */
544 public function getInterwikiIds() {
545 return array_key_exists( self::ID_INTERWIKI, $this->localIds ) ? $this->localIds[self::ID_INTERWIKI] : array();
546 }
547
548 /**
549 * Returns the equivalent link identifiers that can be used to make
550 * the site show up in interfaces such as the "language links" section.
551 *
552 * @since 1.21
553 *
554 * @return string[]
555 */
556 public function getNavigationIds() {
557 return array_key_exists( self::ID_EQUIVALENT, $this->localIds ) ? $this->localIds[self::ID_EQUIVALENT] : array();
558 }
559
560 /**
561 * Returns all local ids
562 *
563 * @since 1.21
564 *
565 * @return array[]
566 */
567 public function getLocalIds() {
568 return $this->localIds;
569 }
570
571 /**
572 * Sets the path used to construct links with.
573 * Shall be equivalent to setPath( getLinkPathType(), $fullUrl ).
574 *
575 * @since 1.21
576 *
577 * @param string $pathType
578 * @param string $fullUrl
579 *
580 * @throws MWException
581 */
582 public function setPath( $pathType, $fullUrl ) {
583 if ( !is_string( $fullUrl ) ) {
584 throw new MWException( '$fullUrl needs to be a string' );
585 }
586
587 if ( !array_key_exists( 'paths', $this->extraData ) ) {
588 $this->extraData['paths'] = array();
589 }
590
591 $this->extraData['paths'][$pathType] = $fullUrl;
592 }
593
594 /**
595 * Returns the path of the provided type or false if there is no such path.
596 *
597 * @since 1.21
598 *
599 * @param string $pathType
600 *
601 * @return string|null
602 */
603 public function getPath( $pathType ) {
604 $paths = $this->getAllPaths();
605 return array_key_exists( $pathType, $paths ) ? $paths[$pathType] : null;
606 }
607
608 /**
609 * Returns the paths as associative array.
610 * The keys are path types, the values are the path urls.
611 *
612 * @since 1.21
613 *
614 * @return string[]
615 */
616 public function getAllPaths() {
617 return array_key_exists( 'paths', $this->extraData ) ? $this->extraData['paths'] : array();
618 }
619
620 /**
621 * Removes the path of the provided type if it's set.
622 *
623 * @since 1.21
624 *
625 * @param string $pathType
626 */
627 public function removePath( $pathType ) {
628 if ( array_key_exists( 'paths', $this->extraData ) ) {
629 unset( $this->extraData['paths'][$pathType] );
630 }
631 }
632
633 /**
634 * @since 1.21
635 *
636 * @param string $siteType
637 *
638 * @return Site
639 */
640 public static function newForType( $siteType ) {
641 global $wgSiteTypes;
642
643 if ( array_key_exists( $siteType, $wgSiteTypes ) ) {
644 return new $wgSiteTypes[$siteType]();
645 }
646
647 return new Site();
648 }
649
650 /**
651 * @see Serializable::serialize
652 *
653 * @since 1.21
654 *
655 * @return string
656 */
657 public function serialize() {
658 $fields = array(
659 'globalid' => $this->globalId,
660 'type' => $this->type,
661 'group' => $this->group,
662 'source' => $this->source,
663 'language' => $this->languageCode,
664 'localids' => $this->localIds,
665 'config' => $this->extraConfig,
666 'data' => $this->extraData,
667 'forward' => $this->forward,
668 'internalid' => $this->internalId,
669
670 );
671
672 return serialize( $fields );
673 }
674
675 /**
676 * @see Serializable::unserialize
677 *
678 * @since 1.21
679 *
680 * @param string $serialized
681 */
682 public function unserialize( $serialized ) {
683 $fields = unserialize( $serialized );
684
685 $this->__construct( $fields['type'] );
686
687 $this->setGlobalId( $fields['globalid'] );
688 $this->setGroup( $fields['group'] );
689 $this->setSource( $fields['source'] );
690 $this->setLanguageCode( $fields['language'] );
691 $this->localIds = $fields['localids'];
692 $this->setExtraConfig( $fields['config'] );
693 $this->setExtraData( $fields['data'] );
694 $this->setForward( $fields['forward'] );
695 $this->setInternalId( $fields['internalid'] );
696 }
697
698 }
699
700 /**
701 * @deprecated
702 */
703 class SiteObject extends Site {}