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