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