[MCR] Introduce RevisionRenderer
[lhc/web/wiklou.git] / includes / MediaWikiServices.php
1 <?php
2 namespace MediaWiki;
3
4 use ActorMigration;
5 use CommentStore;
6 use Config;
7 use ConfigFactory;
8 use CryptHKDF;
9 use CryptRand;
10 use EventRelayerGroup;
11 use GenderCache;
12 use GlobalVarConfig;
13 use Hooks;
14 use IBufferingStatsdDataFactory;
15 use Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface;
16 use MediaWiki\Http\HttpRequestFactory;
17 use MediaWiki\Preferences\PreferencesFactory;
18 use MediaWiki\Shell\CommandFactory;
19 use MediaWiki\Revision\RevisionRenderer;
20 use MediaWiki\Special\SpecialPageFactory;
21 use MediaWiki\Storage\BlobStore;
22 use MediaWiki\Storage\BlobStoreFactory;
23 use MediaWiki\Storage\NameTableStore;
24 use MediaWiki\Storage\RevisionFactory;
25 use MediaWiki\Storage\RevisionLookup;
26 use MediaWiki\Storage\RevisionStore;
27 use OldRevisionImporter;
28 use MediaWiki\Storage\RevisionStoreFactory;
29 use UploadRevisionImporter;
30 use Wikimedia\Rdbms\LBFactory;
31 use LinkCache;
32 use Wikimedia\Rdbms\LoadBalancer;
33 use MediaHandlerFactory;
34 use MediaWiki\Config\ConfigRepository;
35 use MediaWiki\Linker\LinkRenderer;
36 use MediaWiki\Linker\LinkRendererFactory;
37 use MediaWiki\Services\SalvageableService;
38 use MediaWiki\Services\ServiceContainer;
39 use MediaWiki\Services\NoSuchServiceException;
40 use MWException;
41 use MimeAnalyzer;
42 use ObjectCache;
43 use Parser;
44 use ParserCache;
45 use ParserFactory;
46 use PasswordFactory;
47 use ProxyLookup;
48 use SearchEngine;
49 use SearchEngineConfig;
50 use SearchEngineFactory;
51 use SiteLookup;
52 use SiteStore;
53 use WatchedItemStoreInterface;
54 use WatchedItemQueryService;
55 use SkinFactory;
56 use TitleFormatter;
57 use TitleParser;
58 use VirtualRESTServiceClient;
59 use MediaWiki\Interwiki\InterwikiLookup;
60 use MagicWordFactory;
61
62 /**
63 * Service locator for MediaWiki core services.
64 *
65 * This program is free software; you can redistribute it and/or modify
66 * it under the terms of the GNU General Public License as published by
67 * the Free Software Foundation; either version 2 of the License, or
68 * (at your option) any later version.
69 *
70 * This program is distributed in the hope that it will be useful,
71 * but WITHOUT ANY WARRANTY; without even the implied warranty of
72 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
73 * GNU General Public License for more details.
74 *
75 * You should have received a copy of the GNU General Public License along
76 * with this program; if not, write to the Free Software Foundation, Inc.,
77 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
78 * http://www.gnu.org/copyleft/gpl.html
79 *
80 * @file
81 *
82 * @since 1.27
83 */
84
85 /**
86 * MediaWikiServices is the service locator for the application scope of MediaWiki.
87 * Its implemented as a simple configurable DI container.
88 * MediaWikiServices acts as a top level factory/registry for top level services, and builds
89 * the network of service objects that defines MediaWiki's application logic.
90 * It acts as an entry point to MediaWiki's dependency injection mechanism.
91 *
92 * Services are defined in the "wiring" array passed to the constructor,
93 * or by calling defineService().
94 *
95 * @see docs/injection.txt for an overview of using dependency injection in the
96 * MediaWiki code base.
97 */
98 class MediaWikiServices extends ServiceContainer {
99
100 /**
101 * @var MediaWikiServices|null
102 */
103 private static $instance = null;
104
105 /**
106 * Returns the global default instance of the top level service locator.
107 *
108 * @since 1.27
109 *
110 * The default instance is initialized using the service instantiator functions
111 * defined in ServiceWiring.php.
112 *
113 * @note This should only be called by static functions! The instance returned here
114 * should not be passed around! Objects that need access to a service should have
115 * that service injected into the constructor, never a service locator!
116 *
117 * @return MediaWikiServices
118 */
119 public static function getInstance() {
120 if ( self::$instance === null ) {
121 // NOTE: constructing GlobalVarConfig here is not particularly pretty,
122 // but some information from the global scope has to be injected here,
123 // even if it's just a file name or database credentials to load
124 // configuration from.
125 $bootstrapConfig = new GlobalVarConfig();
126 self::$instance = self::newInstance( $bootstrapConfig, 'load' );
127 }
128
129 return self::$instance;
130 }
131
132 /**
133 * Replaces the global MediaWikiServices instance.
134 *
135 * @since 1.28
136 *
137 * @note This is for use in PHPUnit tests only!
138 *
139 * @throws MWException if called outside of PHPUnit tests.
140 *
141 * @param MediaWikiServices $services The new MediaWikiServices object.
142 *
143 * @return MediaWikiServices The old MediaWikiServices object, so it can be restored later.
144 */
145 public static function forceGlobalInstance( MediaWikiServices $services ) {
146 if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
147 throw new MWException( __METHOD__ . ' must not be used outside unit tests.' );
148 }
149
150 $old = self::getInstance();
151 self::$instance = $services;
152
153 return $old;
154 }
155
156 /**
157 * Creates a new instance of MediaWikiServices and sets it as the global default
158 * instance. getInstance() will return a different MediaWikiServices object
159 * after every call to resetGlobalInstance().
160 *
161 * @since 1.28
162 *
163 * @warning This should not be used during normal operation. It is intended for use
164 * when the configuration has changed significantly since bootstrap time, e.g.
165 * during the installation process or during testing.
166 *
167 * @warning Calling resetGlobalInstance() may leave the application in an inconsistent
168 * state. Calling this is only safe under the ASSUMPTION that NO REFERENCE to
169 * any of the services managed by MediaWikiServices exist. If any service objects
170 * managed by the old MediaWikiServices instance remain in use, they may INTERFERE
171 * with the operation of the services managed by the new MediaWikiServices.
172 * Operating with a mix of services created by the old and the new
173 * MediaWikiServices instance may lead to INCONSISTENCIES and even DATA LOSS!
174 * Any class implementing LAZY LOADING is especially prone to this problem,
175 * since instances would typically retain a reference to a storage layer service.
176 *
177 * @see forceGlobalInstance()
178 * @see resetGlobalInstance()
179 * @see resetBetweenTest()
180 *
181 * @param Config|null $bootstrapConfig The Config object to be registered as the
182 * 'BootstrapConfig' service. This has to contain at least the information
183 * needed to set up the 'ConfigFactory' service. If not given, the bootstrap
184 * config of the old instance of MediaWikiServices will be re-used. If there
185 * was no previous instance, a new GlobalVarConfig object will be used to
186 * bootstrap the services.
187 *
188 * @param string $quick Set this to "quick" to allow expensive resources to be re-used.
189 * See SalvageableService for details.
190 *
191 * @throws MWException If called after MW_SERVICE_BOOTSTRAP_COMPLETE has been defined in
192 * Setup.php (unless MW_PHPUNIT_TEST or MEDIAWIKI_INSTALL or RUN_MAINTENANCE_IF_MAIN
193 * is defined).
194 */
195 public static function resetGlobalInstance( Config $bootstrapConfig = null, $quick = '' ) {
196 if ( self::$instance === null ) {
197 // no global instance yet, nothing to reset
198 return;
199 }
200
201 self::failIfResetNotAllowed( __METHOD__ );
202
203 if ( $bootstrapConfig === null ) {
204 $bootstrapConfig = self::$instance->getBootstrapConfig();
205 }
206
207 $oldInstance = self::$instance;
208
209 self::$instance = self::newInstance( $bootstrapConfig, 'load' );
210 self::$instance->importWiring( $oldInstance, [ 'BootstrapConfig' ] );
211
212 if ( $quick === 'quick' ) {
213 self::$instance->salvage( $oldInstance );
214 } else {
215 $oldInstance->destroy();
216 }
217 }
218
219 /**
220 * Salvages the state of any salvageable service instances in $other.
221 *
222 * @note $other will have been destroyed when salvage() returns.
223 *
224 * @param MediaWikiServices $other
225 */
226 private function salvage( self $other ) {
227 foreach ( $this->getServiceNames() as $name ) {
228 // The service could be new in the new instance and not registered in the
229 // other instance (e.g. an extension that was loaded after the instantiation of
230 // the other instance. Skip this service in this case. See T143974
231 try {
232 $oldService = $other->peekService( $name );
233 } catch ( NoSuchServiceException $e ) {
234 continue;
235 }
236
237 if ( $oldService instanceof SalvageableService ) {
238 /** @var SalvageableService $newService */
239 $newService = $this->getService( $name );
240 $newService->salvage( $oldService );
241 }
242 }
243
244 $other->destroy();
245 }
246
247 /**
248 * Creates a new MediaWikiServices instance and initializes it according to the
249 * given $bootstrapConfig. In particular, all wiring files defined in the
250 * ServiceWiringFiles setting are loaded, and the MediaWikiServices hook is called.
251 *
252 * @param Config|null $bootstrapConfig The Config object to be registered as the
253 * 'BootstrapConfig' service.
254 *
255 * @param string $loadWiring set this to 'load' to load the wiring files specified
256 * in the 'ServiceWiringFiles' setting in $bootstrapConfig.
257 *
258 * @return MediaWikiServices
259 * @throws MWException
260 * @throws \FatalError
261 */
262 private static function newInstance( Config $bootstrapConfig, $loadWiring = '' ) {
263 $instance = new self( $bootstrapConfig );
264
265 // Load the default wiring from the specified files.
266 if ( $loadWiring === 'load' ) {
267 $wiringFiles = $bootstrapConfig->get( 'ServiceWiringFiles' );
268 $instance->loadWiringFiles( $wiringFiles );
269 }
270
271 // Provide a traditional hook point to allow extensions to configure services.
272 Hooks::run( 'MediaWikiServices', [ $instance ] );
273
274 return $instance;
275 }
276
277 /**
278 * Disables all storage layer services. After calling this, any attempt to access the
279 * storage layer will result in an error. Use resetGlobalInstance() to restore normal
280 * operation.
281 *
282 * @since 1.28
283 *
284 * @warning This is intended for extreme situations only and should never be used
285 * while serving normal web requests. Legitimate use cases for this method include
286 * the installation process. Test fixtures may also use this, if the fixture relies
287 * on globalState.
288 *
289 * @see resetGlobalInstance()
290 * @see resetChildProcessServices()
291 */
292 public static function disableStorageBackend() {
293 // TODO: also disable some Caches, JobQueues, etc
294 $destroy = [ 'DBLoadBalancer', 'DBLoadBalancerFactory' ];
295 $services = self::getInstance();
296
297 foreach ( $destroy as $name ) {
298 $services->disableService( $name );
299 }
300
301 ObjectCache::clear();
302 }
303
304 /**
305 * Resets any services that may have become stale after a child process
306 * returns from after pcntl_fork(). It's also safe, but generally unnecessary,
307 * to call this method from the parent process.
308 *
309 * @since 1.28
310 *
311 * @note This is intended for use in the context of process forking only!
312 *
313 * @see resetGlobalInstance()
314 * @see disableStorageBackend()
315 */
316 public static function resetChildProcessServices() {
317 // NOTE: for now, just reset everything. Since we don't know the interdependencies
318 // between services, we can't do this more selectively at this time.
319 self::resetGlobalInstance();
320
321 // Child, reseed because there is no bug in PHP:
322 // https://bugs.php.net/bug.php?id=42465
323 mt_srand( getmypid() );
324 }
325
326 /**
327 * Resets the given service for testing purposes.
328 *
329 * @since 1.28
330 *
331 * @warning This is generally unsafe! Other services may still retain references
332 * to the stale service instance, leading to failures and inconsistencies. Subclasses
333 * may use this method to reset specific services under specific instances, but
334 * it should not be exposed to application logic.
335 *
336 * @note With proper dependency injection used throughout the codebase, this method
337 * should not be needed. It is provided to allow tests that pollute global service
338 * instances to clean up.
339 *
340 * @param string $name
341 * @param bool $destroy Whether the service instance should be destroyed if it exists.
342 * When set to false, any existing service instance will effectively be detached
343 * from the container.
344 *
345 * @throws MWException if called outside of PHPUnit tests.
346 */
347 public function resetServiceForTesting( $name, $destroy = true ) {
348 if ( !defined( 'MW_PHPUNIT_TEST' ) && !defined( 'MW_PARSER_TEST' ) ) {
349 throw new MWException( 'resetServiceForTesting() must not be used outside unit tests.' );
350 }
351
352 $this->resetService( $name, $destroy );
353 }
354
355 /**
356 * Convenience method that throws an exception unless it is called during a phase in which
357 * resetting of global services is allowed. In general, services should not be reset
358 * individually, since that may introduce inconsistencies.
359 *
360 * @since 1.28
361 *
362 * This method will throw an exception if:
363 *
364 * - self::$resetInProgress is false (to allow all services to be reset together
365 * via resetGlobalInstance)
366 * - and MEDIAWIKI_INSTALL is not defined (to allow services to be reset during installation)
367 * - and MW_PHPUNIT_TEST is not defined (to allow services to be reset during testing)
368 *
369 * This method is intended to be used to safeguard against accidentally resetting
370 * global service instances that are not yet managed by MediaWikiServices. It is
371 * defined here in the MediaWikiServices services class to have a central place
372 * for managing service bootstrapping and resetting.
373 *
374 * @param string $method the name of the caller method, as given by __METHOD__.
375 *
376 * @throws MWException if called outside bootstrap mode.
377 *
378 * @see resetGlobalInstance()
379 * @see forceGlobalInstance()
380 * @see disableStorageBackend()
381 */
382 public static function failIfResetNotAllowed( $method ) {
383 if ( !defined( 'MW_PHPUNIT_TEST' )
384 && !defined( 'MW_PARSER_TEST' )
385 && !defined( 'MEDIAWIKI_INSTALL' )
386 && !defined( 'RUN_MAINTENANCE_IF_MAIN' )
387 && defined( 'MW_SERVICE_BOOTSTRAP_COMPLETE' )
388 ) {
389 throw new MWException( $method . ' may only be called during bootstrapping and unit tests!' );
390 }
391 }
392
393 /**
394 * @param Config $config The Config object to be registered as the 'BootstrapConfig' service.
395 * This has to contain at least the information needed to set up the 'ConfigFactory'
396 * service.
397 */
398 public function __construct( Config $config ) {
399 parent::__construct();
400
401 // Register the given Config object as the bootstrap config service.
402 $this->defineService( 'BootstrapConfig', function () use ( $config ) {
403 return $config;
404 } );
405 }
406
407 // CONVENIENCE GETTERS ////////////////////////////////////////////////////
408
409 /**
410 * @since 1.31
411 * @return ActorMigration
412 */
413 public function getActorMigration() {
414 return $this->getService( 'ActorMigration' );
415 }
416
417 /**
418 * @since 1.31
419 * @return BlobStore
420 */
421 public function getBlobStore() {
422 return $this->getService( '_SqlBlobStore' );
423 }
424
425 /**
426 * @since 1.31
427 * @return BlobStoreFactory
428 */
429 public function getBlobStoreFactory() {
430 return $this->getService( 'BlobStoreFactory' );
431 }
432
433 /**
434 * Returns the Config object containing the bootstrap configuration.
435 * Bootstrap configuration would typically include database credentials
436 * and other information that may be needed before the ConfigFactory
437 * service can be instantiated.
438 *
439 * @note This should only be used during bootstrapping, in particular
440 * when creating the MainConfig service. Application logic should
441 * use getMainConfig() to get a Config instances.
442 *
443 * @since 1.27
444 * @return Config
445 */
446 public function getBootstrapConfig() {
447 return $this->getService( 'BootstrapConfig' );
448 }
449
450 /**
451 * @since 1.32
452 * @return NameTableStore
453 */
454 public function getChangeTagDefStore() {
455 return $this->getService( 'ChangeTagDefStore' );
456 }
457
458 /**
459 * @since 1.31
460 * @return CommentStore
461 */
462 public function getCommentStore() {
463 return $this->getService( 'CommentStore' );
464 }
465
466 /**
467 * @since 1.27
468 * @return ConfigFactory
469 */
470 public function getConfigFactory() {
471 return $this->getService( 'ConfigFactory' );
472 }
473
474 /**
475 * @since 1.32
476 * @return ConfigRepository
477 */
478 public function getConfigRepository() {
479 return $this->getService( 'ConfigRepository' );
480 }
481
482 /**
483 * @since 1.29
484 * @return \ConfiguredReadOnlyMode
485 */
486 public function getConfiguredReadOnlyMode() {
487 return $this->getService( 'ConfiguredReadOnlyMode' );
488 }
489
490 /**
491 * @since 1.32
492 * @return \Language
493 */
494 public function getContentLanguage() {
495 return $this->getService( 'ContentLanguage' );
496 }
497
498 /**
499 * @since 1.31
500 * @return NameTableStore
501 */
502 public function getContentModelStore() {
503 return $this->getService( 'ContentModelStore' );
504 }
505
506 /**
507 * @since 1.28
508 * @return CryptHKDF
509 */
510 public function getCryptHKDF() {
511 return $this->getService( 'CryptHKDF' );
512 }
513
514 /**
515 * @since 1.28
516 * @deprecated since 1.32, use random_bytes()/random_int()
517 * @return CryptRand
518 */
519 public function getCryptRand() {
520 return $this->getService( 'CryptRand' );
521 }
522
523 /**
524 * @since 1.28
525 * @return LoadBalancer The main DB load balancer for the local wiki.
526 */
527 public function getDBLoadBalancer() {
528 return $this->getService( 'DBLoadBalancer' );
529 }
530
531 /**
532 * @since 1.28
533 * @return LBFactory
534 */
535 public function getDBLoadBalancerFactory() {
536 return $this->getService( 'DBLoadBalancerFactory' );
537 }
538
539 /**
540 * @since 1.27
541 * @return EventRelayerGroup
542 */
543 public function getEventRelayerGroup() {
544 return $this->getService( 'EventRelayerGroup' );
545 }
546
547 /**
548 * @since 1.31
549 * @return \ExternalStoreFactory
550 */
551 public function getExternalStoreFactory() {
552 return $this->getService( 'ExternalStoreFactory' );
553 }
554
555 /**
556 * @since 1.28
557 * @return GenderCache
558 */
559 public function getGenderCache() {
560 return $this->getService( 'GenderCache' );
561 }
562
563 /**
564 * @since 1.31
565 * @return HttpRequestFactory
566 */
567 public function getHttpRequestFactory() {
568 return $this->getService( 'HttpRequestFactory' );
569 }
570
571 /**
572 * @since 1.28
573 * @return InterwikiLookup
574 */
575 public function getInterwikiLookup() {
576 return $this->getService( 'InterwikiLookup' );
577 }
578
579 /**
580 * @since 1.28
581 * @return LinkCache
582 */
583 public function getLinkCache() {
584 return $this->getService( 'LinkCache' );
585 }
586
587 /**
588 * LinkRenderer instance that can be used
589 * if no custom options are needed
590 *
591 * @since 1.28
592 * @return LinkRenderer
593 */
594 public function getLinkRenderer() {
595 return $this->getService( 'LinkRenderer' );
596 }
597
598 /**
599 * @since 1.28
600 * @return LinkRendererFactory
601 */
602 public function getLinkRendererFactory() {
603 return $this->getService( 'LinkRendererFactory' );
604 }
605
606 /**
607 * @since 1.28
608 * @return \BagOStuff
609 */
610 public function getLocalServerObjectCache() {
611 return $this->getService( 'LocalServerObjectCache' );
612 }
613
614 /**
615 * @since 1.32
616 * @return MagicWordFactory
617 */
618 public function getMagicWordFactory() {
619 return $this->getService( 'MagicWordFactory' );
620 }
621
622 /**
623 * Returns the Config object that provides configuration for MediaWiki core.
624 * This may or may not be the same object that is returned by getBootstrapConfig().
625 *
626 * @since 1.27
627 * @return Config
628 */
629 public function getMainConfig() {
630 return $this->getService( 'MainConfig' );
631 }
632
633 /**
634 * @since 1.28
635 * @return \BagOStuff
636 */
637 public function getMainObjectStash() {
638 return $this->getService( 'MainObjectStash' );
639 }
640
641 /**
642 * @since 1.28
643 * @return \WANObjectCache
644 */
645 public function getMainWANObjectCache() {
646 return $this->getService( 'MainWANObjectCache' );
647 }
648
649 /**
650 * @since 1.28
651 * @return MediaHandlerFactory
652 */
653 public function getMediaHandlerFactory() {
654 return $this->getService( 'MediaHandlerFactory' );
655 }
656
657 /**
658 * @since 1.28
659 * @return MimeAnalyzer
660 */
661 public function getMimeAnalyzer() {
662 return $this->getService( 'MimeAnalyzer' );
663 }
664
665 /**
666 * @since 1.32
667 * @return OldRevisionImporter
668 */
669 public function getOldRevisionImporter() {
670 return $this->getService( 'OldRevisionImporter' );
671 }
672
673 /**
674 * @since 1.29
675 * @return Parser
676 */
677 public function getParser() {
678 return $this->getService( 'Parser' );
679 }
680
681 /**
682 * @since 1.30
683 * @return ParserCache
684 */
685 public function getParserCache() {
686 return $this->getService( 'ParserCache' );
687 }
688
689 /**
690 * @since 1.32
691 * @return ParserFactory
692 */
693 public function getParserFactory() {
694 return $this->getService( 'ParserFactory' );
695 }
696
697 /**
698 * @since 1.32
699 * @return PasswordFactory
700 */
701 public function getPasswordFactory() {
702 return $this->getService( 'PasswordFactory' );
703 }
704
705 /**
706 * @since 1.32
707 * @return StatsdDataFactoryInterface
708 */
709 public function getPerDbNameStatsdDataFactory() {
710 return $this->getService( 'PerDbNameStatsdDataFactory' );
711 }
712
713 /**
714 * @since 1.31
715 * @return PreferencesFactory
716 */
717 public function getPreferencesFactory() {
718 return $this->getService( 'PreferencesFactory' );
719 }
720
721 /**
722 * @since 1.28
723 * @return ProxyLookup
724 */
725 public function getProxyLookup() {
726 return $this->getService( 'ProxyLookup' );
727 }
728
729 /**
730 * @since 1.29
731 * @return \ReadOnlyMode
732 */
733 public function getReadOnlyMode() {
734 return $this->getService( 'ReadOnlyMode' );
735 }
736
737 /**
738 * @since 1.31
739 * @return RevisionFactory
740 */
741 public function getRevisionFactory() {
742 return $this->getService( 'RevisionFactory' );
743 }
744
745 /**
746 * @since 1.31
747 * @return RevisionLookup
748 */
749 public function getRevisionLookup() {
750 return $this->getService( 'RevisionLookup' );
751 }
752
753 /**
754 * @since 1.32
755 * @return RevisionRenderer
756 */
757 public function getRevisionRenderer() {
758 return $this->getService( 'RevisionRenderer' );
759 }
760
761 /**
762 * @since 1.31
763 * @return RevisionStore
764 */
765 public function getRevisionStore() {
766 return $this->getService( 'RevisionStore' );
767 }
768
769 /**
770 * @since 1.32
771 * @return RevisionStoreFactory
772 */
773 public function getRevisionStoreFactory() {
774 return $this->getService( 'RevisionStoreFactory' );
775 }
776
777 /**
778 * @since 1.27
779 * @return SearchEngine
780 */
781 public function newSearchEngine() {
782 // New engine object every time, since they keep state
783 return $this->getService( 'SearchEngineFactory' )->create();
784 }
785
786 /**
787 * @since 1.27
788 * @return SearchEngineConfig
789 */
790 public function getSearchEngineConfig() {
791 return $this->getService( 'SearchEngineConfig' );
792 }
793
794 /**
795 * @since 1.27
796 * @return SearchEngineFactory
797 */
798 public function getSearchEngineFactory() {
799 return $this->getService( 'SearchEngineFactory' );
800 }
801
802 /**
803 * @since 1.30
804 * @return CommandFactory
805 */
806 public function getShellCommandFactory() {
807 return $this->getService( 'ShellCommandFactory' );
808 }
809
810 /**
811 * @since 1.27
812 * @return SiteLookup
813 */
814 public function getSiteLookup() {
815 return $this->getService( 'SiteLookup' );
816 }
817
818 /**
819 * @since 1.27
820 * @return SiteStore
821 */
822 public function getSiteStore() {
823 return $this->getService( 'SiteStore' );
824 }
825
826 /**
827 * @since 1.27
828 * @return SkinFactory
829 */
830 public function getSkinFactory() {
831 return $this->getService( 'SkinFactory' );
832 }
833
834 /**
835 * @since 1.31
836 * @return NameTableStore
837 */
838 public function getSlotRoleStore() {
839 return $this->getService( 'SlotRoleStore' );
840 }
841
842 /**
843 * @since 1.32
844 * @return SpecialPageFactory
845 */
846 public function getSpecialPageFactory() : SpecialPageFactory {
847 return $this->getService( 'SpecialPageFactory' );
848 }
849
850 /**
851 * @since 1.27
852 * @return IBufferingStatsdDataFactory
853 */
854 public function getStatsdDataFactory() {
855 return $this->getService( 'StatsdDataFactory' );
856 }
857
858 /**
859 * @since 1.28
860 * @return TitleFormatter
861 */
862 public function getTitleFormatter() {
863 return $this->getService( 'TitleFormatter' );
864 }
865
866 /**
867 * @since 1.28
868 * @return TitleParser
869 */
870 public function getTitleParser() {
871 return $this->getService( 'TitleParser' );
872 }
873
874 /**
875 * @since 1.32
876 * @return UploadRevisionImporter
877 */
878 public function getUploadRevisionImporter() {
879 return $this->getService( 'UploadRevisionImporter' );
880 }
881
882 /**
883 * @since 1.28
884 * @return VirtualRESTServiceClient
885 */
886 public function getVirtualRESTServiceClient() {
887 return $this->getService( 'VirtualRESTServiceClient' );
888 }
889
890 /**
891 * @since 1.28
892 * @return WatchedItemQueryService
893 */
894 public function getWatchedItemQueryService() {
895 return $this->getService( 'WatchedItemQueryService' );
896 }
897
898 /**
899 * @since 1.28
900 * @return WatchedItemStoreInterface
901 */
902 public function getWatchedItemStore() {
903 return $this->getService( 'WatchedItemStore' );
904 }
905
906 /**
907 * @since 1.31
908 * @return \OldRevisionImporter
909 */
910 public function getWikiRevisionOldRevisionImporter() {
911 return $this->getService( 'OldRevisionImporter' );
912 }
913
914 /**
915 * @since 1.31
916 * @return \OldRevisionImporter
917 */
918 public function getWikiRevisionOldRevisionImporterNoUpdates() {
919 return $this->getService( 'WikiRevisionOldRevisionImporterNoUpdates' );
920 }
921
922 /**
923 * @since 1.31
924 * @return \UploadRevisionImporter
925 */
926 public function getWikiRevisionUploadImporter() {
927 return $this->getService( 'UploadRevisionImporter' );
928 }
929
930 }