MediaWiki master
IntroMessageBuilder.php
Go to the documentation of this file.
1<?php
2
3namespace MediaWiki\EditPage;
4
27use RepoGroup;
28use Skin;
29use SkinFactory;
32
41
42 use ParametersHelper;
43
44 // Parameters for getIntroMessages()
45 public const MORE_FRAMES = 1;
46 public const LESS_FRAMES = 2;
47
48 private Config $config;
49 private LinkRenderer $linkRenderer;
50 private PermissionManager $permManager;
51 private UserNameUtils $userNameUtils;
52 private TempUserCreator $tempUserCreator;
53 private UserFactory $userFactory;
54 private RestrictionStore $restrictionStore;
55 private DatabaseBlockStore $blockStore;
56 private ReadOnlyMode $readOnlyMode;
57 private SpecialPageFactory $specialPageFactory;
58 private RepoGroup $repoGroup;
59 private NamespaceInfo $namespaceInfo;
60 private SkinFactory $skinFactory;
61 private IConnectionProvider $dbProvider;
62
63 public function __construct(
64 Config $config,
65 LinkRenderer $linkRenderer,
66 PermissionManager $permManager,
67 UserNameUtils $userNameUtils,
68 TempUserCreator $tempUserCreator,
69 UserFactory $userFactory,
70 RestrictionStore $restrictionStore,
71 DatabaseBlockStore $blockStore,
72 ReadOnlyMode $readOnlyMode,
73 SpecialPageFactory $specialPageFactory,
74 RepoGroup $repoGroup,
75 NamespaceInfo $namespaceInfo,
76 SkinFactory $skinFactory,
77 IConnectionProvider $dbProvider
78 ) {
79 $this->config = $config;
80 $this->linkRenderer = $linkRenderer;
81 $this->permManager = $permManager;
82 $this->userNameUtils = $userNameUtils;
83 $this->tempUserCreator = $tempUserCreator;
84 $this->userFactory = $userFactory;
85 $this->restrictionStore = $restrictionStore;
86 $this->blockStore = $blockStore;
87 $this->readOnlyMode = $readOnlyMode;
88 $this->specialPageFactory = $specialPageFactory;
89 $this->repoGroup = $repoGroup;
90 $this->namespaceInfo = $namespaceInfo;
91 $this->skinFactory = $skinFactory;
92 $this->dbProvider = $dbProvider;
93 }
94
107 private function getLogExtract( $types = [], $page = '', $user = '', $param = [] ): string {
108 $outString = '';
109 LogEventsList::showLogExtract( $outString, $types, $page, $user, $param );
110 return $outString;
111 }
112
137 public function getIntroMessages(
138 int $frames,
139 array $skip,
140 MessageLocalizer $localizer,
141 ProperPageIdentity $page,
142 ?RevisionRecord $revRecord,
143 Authority $performer,
144 ?string $editIntro,
145 ?string $returnToQuery,
146 bool $preview,
147 ?string $section = null
148 ): array {
149 $title = Title::newFromPageIdentity( $page );
150 $messages = new IntroMessageList( $frames, $skip );
151
152 $this->addOldRevisionWarning( $messages, $localizer, $revRecord );
153
154 if ( !$preview ) {
155 $this->addCodeEditingIntro( $messages, $localizer, $title, $performer );
156 $this->addSharedRepoHint( $messages, $localizer, $page );
157 $this->addUserWarnings( $messages, $localizer, $title, $performer );
158 $this->addEditIntro( $messages, $localizer, $page, $performer, $editIntro, $section );
159 $this->addRecreateWarning( $messages, $localizer, $page );
160 }
161
162 $this->addTalkPageText( $messages, $localizer, $title );
163 $this->addEditNotices( $messages, $localizer, $title, $revRecord );
164
165 $this->addReadOnlyWarning( $messages, $localizer );
166 $this->addAnonEditWarning( $messages, $localizer, $title, $performer, $returnToQuery, $preview );
167 $this->addUserConfigPageInfo( $messages, $localizer, $title, $performer, $preview );
168 $this->addPageProtectionWarningHeaders( $messages, $localizer, $page );
169 $this->addHeaderCopyrightWarning( $messages, $localizer );
170
171 return $messages->getList();
172 }
173
177 private function addCodeEditingIntro(
178 IntroMessageList $messages,
179 MessageLocalizer $localizer,
180 Title $title,
181 Authority $performer
182 ): void {
183 $isUserJsConfig = $title->isUserJsConfigPage();
184 $namespace = $title->getNamespace();
185 $intro = '';
186
187 if (
188 $title->isUserConfigPage() &&
189 $title->isSubpageOf( Title::makeTitle( NS_USER, $performer->getUser()->getName() ) )
190 ) {
191 $isUserCssConfig = $title->isUserCssConfigPage();
192 $isUserJsonConfig = $title->isUserJsonConfigPage();
193 $isUserJsConfig = $title->isUserJsConfigPage();
194
195 if ( $isUserCssConfig ) {
196 $warning = 'usercssispublic';
197 } elseif ( $isUserJsonConfig ) {
198 $warning = 'userjsonispublic';
199 } else {
200 $warning = 'userjsispublic';
201 }
202
203 $warningText = $localizer->msg( $warning )->parse();
204 $intro .= $warningText ? Html::rawElement(
205 'div',
206 [ 'class' => 'mw-userconfigpublic' ],
207 $warningText
208 ) : '';
209
210 }
211 $codeMsg = $localizer->msg( 'editpage-code-message' );
212 $codeMessageText = $codeMsg->isDisabled() ? '' : $codeMsg->parseAsBlock();
213 $isJavaScript = $title->hasContentModel( CONTENT_MODEL_JAVASCRIPT );
214 $isCSS = $title->hasContentModel( CONTENT_MODEL_CSS );
215
216 if ( $namespace === NS_MEDIAWIKI ) {
217 $interfaceMsg = $localizer->msg( 'editinginterface' );
218 $interfaceMsgText = $interfaceMsg->parse();
219 # Show a warning if editing an interface message
220 $intro .= $interfaceMsgText ? Html::rawElement(
221 'div',
222 [ 'class' => 'mw-editinginterface' ],
223 $interfaceMsgText
224 ) : '';
225 # If this is a default message (but not css, json, or js),
226 # show a hint that it is translatable on translatewiki.net
227 if (
228 !$isCSS
229 && !$title->hasContentModel( CONTENT_MODEL_JSON )
230 && !$isJavaScript
231 ) {
232 $defaultMessageText = $title->getDefaultMessageText();
233 if ( $defaultMessageText !== false ) {
234 $translateInterfaceText = $localizer->msg( 'translateinterface' )->parse();
235 $intro .= $translateInterfaceText ? Html::rawElement(
236 'div',
237 [ 'class' => 'mw-translateinterface' ],
238 $translateInterfaceText
239 ) : '';
240 }
241 }
242 }
243
244 if ( $isUserJsConfig ) {
245 $userConfigDangerousMsg = $localizer->msg( 'userjsdangerous' )->parse();
246 $intro .= $userConfigDangerousMsg ? Html::rawElement(
247 'div',
248 [ 'class' => 'mw-userconfigdangerous' ],
249 $userConfigDangerousMsg
250 ) : '';
251 }
252
253 // If the wiki page contains JavaScript or CSS link add message specific to code.
254 if ( $isJavaScript || $isCSS ) {
255 $intro .= $codeMessageText;
256 }
257
258 $messages->addWithKey(
259 'code-editing-intro',
260 $intro,
261 // While semantically this is a warning, given the impact of editing these pages,
262 // it's best to deter users who don't understand what they are doing by
263 // acknowledging the danger here. This is a potentially destructive action
264 // so requires destructive coloring.
265 Html::errorBox( '$1' )
266 );
267 }
268
269 private function addSharedRepoHint(
270 IntroMessageList $messages,
271 MessageLocalizer $localizer,
272 ProperPageIdentity $page
273 ): void {
274 $namespace = $page->getNamespace();
275 if ( $namespace === NS_FILE ) {
276 # Show a hint to shared repo
277 $file = $this->repoGroup->findFile( $page );
278 if ( $file && !$file->isLocal() ) {
279 $descUrl = $file->getDescriptionUrl();
280 # there must be a description url to show a hint to shared repo
281 if ( $descUrl ) {
282 if ( !$page->exists() ) {
283 $messages->add(
284 $localizer->msg(
285 'sharedupload-desc-create',
286 $file->getRepo()->getDisplayName(),
287 $descUrl
288 ),
289 "<div class=\"mw-sharedupload-desc-create\">\n$1\n</div>"
290 );
291 } else {
292 $messages->add(
293 $localizer->msg(
294 'sharedupload-desc-edit',
295 $file->getRepo()->getDisplayName(),
296 $descUrl
297 ),
298 "<div class=\"mw-sharedupload-desc-edit\">\n$1\n</div>"
299 );
300 }
301 }
302 }
303 }
304 }
305
306 private function addUserWarnings(
307 IntroMessageList $messages,
308 MessageLocalizer $localizer,
309 Title $title,
310 Authority $performer
311 ): void {
312 $namespace = $title->getNamespace();
313 # Show a warning message when someone creates/edits a user (talk) page but the user does not exist
314 # Show log extract when the user is currently blocked
315 if ( $namespace === NS_USER || $namespace === NS_USER_TALK ) {
316 $username = explode( '/', $title->getText(), 2 )[0];
317 // Allow IP users
318 $validation = UserRigorOptions::RIGOR_NONE;
319 $user = $this->userFactory->newFromName( $username, $validation );
320 $ip = $this->userNameUtils->isIP( $username );
321 $block = $this->blockStore->newFromTarget( $user, $user );
322
323 $userExists = ( $user && $user->isRegistered() );
324 if ( $userExists && $user->isHidden() && !$performer->isAllowed( 'hideuser' ) ) {
325 // If the user exists, but is hidden, and the viewer cannot see hidden
326 // users, pretend like they don't exist at all. See T120883
327 $userExists = false;
328 }
329
330 if ( !$userExists && !$ip ) {
331 $messages->addWithKey(
332 'userpage-userdoesnotexist',
333 // This wrapper frame, for whatever reason, is not optional
334 Html::warningBox(
335 $localizer->msg( 'userpage-userdoesnotexist', wfEscapeWikiText( $username ) )->parse(),
336 'mw-userpage-userdoesnotexist'
337 )
338 );
339 } elseif (
340 $block !== null &&
341 $block->getType() !== Block::TYPE_AUTO &&
342 (
343 $block->isSitewide() ||
344 $this->permManager->isBlockedFrom(
345 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable False positive
346 $user,
347 $title,
348 true
349 )
350 )
351 ) {
352 // Show log extract if the user is sitewide blocked or is partially
353 // blocked and not allowed to edit their user page or user talk page
354 $messages->addWithKey(
355 'blocked-notice-logextract',
356 $this->getLogExtract(
357 'block',
358 $this->namespaceInfo->getCanonicalName( NS_USER ) . ':' . $block->getTargetName(),
359 '',
360 [
361 'lim' => 1,
362 'showIfEmpty' => false,
363 'msgKey' => [
364 'blocked-notice-logextract',
365 $user->getName() # Support GENDER in notice
366 ],
367 ]
368 )
369 );
370 }
371 }
372 }
373
377 private function addEditIntro(
378 IntroMessageList $messages,
379 MessageLocalizer $localizer,
380 ProperPageIdentity $page,
381 Authority $performer,
382 ?string $editIntro,
383 ?string $section
384 ): void {
385 if ( ( $editIntro === null || $editIntro === '' ) && $section === 'new' ) {
386 // Custom edit intro for new sections
387 $editIntro = 'MediaWiki:addsection-editintro';
388 }
389 if ( $editIntro !== null && $editIntro !== '' ) {
390 $introTitle = Title::newFromText( $editIntro );
391
392 // (T334855) Use SpecialMyLanguage redirect so that nonexistent translated pages can
393 // fall back to the corresponding page in a suitable language
394 $introTitle = $this->getTargetTitleIfSpecialMyLanguage( $introTitle );
395
396 if ( $this->isPageExistingAndViewable( $introTitle, $performer ) ) {
397 $messages->addWithKey(
398 'editintro',
399 $localizer->msg( new RawMessage(
400 // Added using template syntax, to take <noinclude>'s into account.
401 '<div class="mw-editintro">{{:' . $introTitle->getFullText() . '}}</div>'
402 ) )
403 // Parse as content to enable language conversion (T353870)
404 ->inContentLanguage()
405 ->parse()
406 );
407 return;
408 }
409 }
410
411 if ( !$page->exists() ) {
413 $localizer->msg( 'helppage' )->inContentLanguage()->text()
414 ) );
415 if ( $performer->getUser()->isRegistered() ) {
416 $messages->add(
417 $localizer->msg( 'newarticletext', $helpLink ),
418 // Suppress the external link icon, consider the help url an internal one
419 "<div class=\"mw-newarticletext plainlinks\">\n$1\n</div>"
420 );
421 } else {
422 $messages->add(
423 $localizer->msg( 'newarticletextanon', $helpLink ),
424 // Suppress the external link icon, consider the help url an internal one
425 "<div class=\"mw-newarticletextanon plainlinks\">\n$1\n</div>"
426 );
427 }
428 }
429 }
430
431 private function addRecreateWarning(
432 IntroMessageList $messages,
433 MessageLocalizer $localizer,
434 ProperPageIdentity $page
435 ): void {
436 # Give a notice if the user is editing a deleted/moved page...
437 if ( !$page->exists() ) {
438 $dbr = $this->dbProvider->getReplicaDatabase();
439
440 $messages->addWithKey(
441 'recreate-moveddeleted-warn',
442 $this->getLogExtract( [ 'delete', 'move' ], $page, '', [
443 'lim' => 10,
444 'conds' => [ $dbr->expr( 'log_action', '!=', 'revision' ) ],
445 'showIfEmpty' => false,
446 'msgKey' => [ 'recreate-moveddeleted-warn' ],
447 ] )
448 );
449 }
450 }
451
452 private function addTalkPageText(
453 IntroMessageList $messages,
454 MessageLocalizer $localizer,
455 Title $title
456 ): void {
457 if ( $title->isTalkPage() ) {
458 $messages->add( $localizer->msg( 'talkpagetext' ) );
459 }
460 }
461
462 private function addEditNotices(
463 IntroMessageList $messages,
464 MessageLocalizer $localizer,
465 Title $title,
466 ?RevisionRecord $revRecord
467 ): void {
468 $editNotices = $title->getEditNotices( $revRecord ? $revRecord->getId() : 0 );
469 if ( count( $editNotices ) ) {
470 foreach ( $editNotices as $key => $html ) {
471 $messages->addWithKey( $key, $html );
472 }
473 } else {
474 $msg = $localizer->msg( 'editnotice-notext' );
475 if ( !$msg->isDisabled() ) {
476 $messages->addWithKey(
477 'editnotice-notext',
478 Html::rawElement(
479 'div',
480 [ 'class' => 'mw-editnotice-notext' ],
481 $msg->parseAsBlock()
482 )
483 );
484 }
485 }
486 }
487
488 private function addOldRevisionWarning(
489 IntroMessageList $messages,
490 MessageLocalizer $localizer,
491 ?RevisionRecord $revRecord
492 ): void {
493 if ( $revRecord && !$revRecord->isCurrent() ) {
494 // This wrapper frame is not optional (T337071)
495 $messages->addWithKey( 'editingold', Html::warningBox( $localizer->msg( 'editingold' )->parse() ) );
496 }
497 }
498
499 private function addReadOnlyWarning(
500 IntroMessageList $messages,
501 MessageLocalizer $localizer
502 ): void {
503 if ( $this->readOnlyMode->isReadOnly() ) {
504 $messages->add(
505 $localizer->msg( 'readonlywarning', $this->readOnlyMode->getReason() ),
506 "<div id=\"mw-read-only-warning\">\n$1\n</div>"
507 );
508 }
509 }
510
511 private function addAnonEditWarning(
512 IntroMessageList $messages,
513 MessageLocalizer $localizer,
514 Title $title,
515 Authority $performer,
516 ?string $returnToQuery,
517 bool $preview
518 ): void {
519 if ( !$performer->getUser()->isRegistered() ) {
520 $tempUserCreateActive = $this->tempUserCreator->shouldAutoCreate( $performer, 'edit' );
521 if ( !$preview ) {
522 $messages->addWithKey(
523 'anoneditwarning',
524 $localizer->msg(
525 $tempUserCreateActive ? 'autocreate-edit-warning' : 'anoneditwarning',
526 // Log-in link
527 SpecialPage::getTitleFor( 'Userlogin' )->getFullURL( [
528 'returnto' => $title->getPrefixedDBkey(),
529 'returntoquery' => $returnToQuery,
530 ] ),
531 // Sign-up link
532 SpecialPage::getTitleFor( 'CreateAccount' )->getFullURL( [
533 'returnto' => $title->getPrefixedDBkey(),
534 'returntoquery' => $returnToQuery,
535 ] )
536 )->parse(),
537 Html::warningBox( '$1', 'mw-anon-edit-warning' )
538 );
539 } else {
540 $messages->addWithKey(
541 'anoneditwarning',
542 $localizer->msg( $tempUserCreateActive ? 'autocreate-preview-warning' : 'anonpreviewwarning' )
543 ->parse(),
544 Html::warningBox( '$1', 'mw-anon-preview-warning' ) );
545 }
546 }
547 }
548
553 private function isWrongCaseUserConfigPage( Title $title ): bool {
554 if ( $title->isUserCssConfigPage() || $title->isUserJsConfigPage() ) {
555 $name = $title->getSkinFromConfigSubpage();
556 $skins = array_merge(
557 array_keys( $this->skinFactory->getInstalledSkins() ),
558 [ 'common' ]
559 );
560 return !in_array( $name, $skins, true )
561 && in_array( strtolower( $name ), $skins, true );
562 } else {
563 return false;
564 }
565 }
566
567 private function addUserConfigPageInfo(
568 IntroMessageList $messages,
569 MessageLocalizer $localizer,
570 Title $title,
571 Authority $performer,
572 bool $preview
573 ): void {
574 if ( $title->isUserConfigPage() ) {
575 # Check the skin exists
576 if ( $this->isWrongCaseUserConfigPage( $title ) ) {
577 $messages->add(
578 $localizer->msg( 'userinvalidconfigtitle', $title->getSkinFromConfigSubpage() ),
579 Html::errorBox( '$1', '', 'mw-userinvalidconfigtitle' )
580 );
581 }
582 if ( $title->isSubpageOf( Title::makeTitle( NS_USER, $performer->getUser()->getName() ) ) ) {
583 $isUserCssConfig = $title->isUserCssConfigPage();
584 $isUserJsonConfig = $title->isUserJsonConfigPage();
585 $isUserJsConfig = $title->isUserJsConfigPage();
586
587 if ( !$preview ) {
588 if ( $isUserCssConfig && $this->config->get( MainConfigNames::AllowUserCss ) ) {
589 $messages->add(
590 $localizer->msg( 'usercssyoucanpreview' ),
591 "<div id='mw-usercssyoucanpreview'>\n$1\n</div>"
592 );
593 } elseif ( $isUserJsonConfig /* No comparable 'AllowUserJson' */ ) {
594 $messages->add(
595 $localizer->msg( 'userjsonyoucanpreview' ),
596 "<div id='mw-userjsonyoucanpreview'>\n$1\n</div>"
597 );
598 } elseif ( $isUserJsConfig && $this->config->get( MainConfigNames::AllowUserJs ) ) {
599 $messages->add(
600 $localizer->msg( 'userjsyoucanpreview' ),
601 "<div id='mw-userjsyoucanpreview'>\n$1\n</div>"
602 );
603 }
604 }
605 }
606 }
607 }
608
609 private function addPageProtectionWarningHeaders(
610 IntroMessageList $messages,
611 MessageLocalizer $localizer,
612 ProperPageIdentity $page
613 ): void {
614 if ( $this->restrictionStore->isProtected( $page, 'edit' ) &&
615 $this->permManager->getNamespaceRestrictionLevels(
616 $page->getNamespace()
617 ) !== [ '' ]
618 ) {
619 # Is the title semi-protected?
620 if ( $this->restrictionStore->isSemiProtected( $page ) ) {
621 $noticeMsg = 'semiprotectedpagewarning';
622 } else {
623 # Then it must be protected based on static groups (regular)
624 $noticeMsg = 'protectedpagewarning';
625 }
626 $messages->addWithKey(
627 $noticeMsg,
628 $this->getLogExtract( 'protect', $page, '', [ 'lim' => 1, 'msgKey' => [ $noticeMsg ] ] )
629 );
630 }
631 if ( $this->restrictionStore->isCascadeProtected( $page ) ) {
632 # Is this page under cascading protection from some source pages?
633 $cascadeSources = $this->restrictionStore->getCascadeProtectionSources( $page )[0];
634 $htmlList = '';
635 # Explain, and list the titles responsible
636 foreach ( $cascadeSources as $source ) {
637 $htmlList .= Html::rawElement( 'li', [], $this->linkRenderer->makeLink( $source ) );
638 }
639 $messages->addWithKey(
640 'cascadeprotectedwarning',
641 $localizer->msg( 'cascadeprotectedwarning', count( $cascadeSources ) )->parse() .
642 ( $htmlList ? Html::rawElement( 'ul', [], $htmlList ) : '' ),
643 Html::warningBox( '$1', 'mw-cascadeprotectedwarning' )
644 );
645 }
646 if ( !$page->exists() && $this->restrictionStore->getRestrictions( $page, 'create' ) ) {
647 $messages->addWithKey(
648 'titleprotectedwarning',
649 $this->getLogExtract(
650 'protect', $page,
651 '',
652 [
653 'lim' => 1,
654 'showIfEmpty' => false,
655 'msgKey' => [ 'titleprotectedwarning' ],
656 'wrap' => "<div class=\"mw-titleprotectedwarning\">\n$1</div>"
657 ]
658 )
659 );
660 }
661 }
662
663 private function addHeaderCopyrightWarning(
664 IntroMessageList $messages,
665 MessageLocalizer $localizer
666 ): void {
667 $messages->add(
668 $localizer->msg( 'editpage-head-copy-warn' ),
669 "<div class='editpage-head-copywarn'>\n$1\n</div>"
670 );
671 }
672}
getUser()
const NS_USER
Definition Defines.php:67
const CONTENT_MODEL_CSS
Definition Defines.php:223
const NS_FILE
Definition Defines.php:71
const NS_MEDIAWIKI
Definition Defines.php:73
const CONTENT_MODEL_JSON
Definition Defines.php:225
const NS_USER_TALK
Definition Defines.php:68
const CONTENT_MODEL_JAVASCRIPT
Definition Defines.php:222
wfEscapeWikiText( $input)
Escapes the given text so that it may be output using addWikiText() without any linking,...
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL using $wgServer (or one of its alternatives).
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:81
static showLogExtract(&$out, $types=[], $page='', $user='', $param=[])
Show log extract.
Provides the intro messages (edit notices and others) to be displayed before an edit form.
__construct(Config $config, LinkRenderer $linkRenderer, PermissionManager $permManager, UserNameUtils $userNameUtils, TempUserCreator $tempUserCreator, UserFactory $userFactory, RestrictionStore $restrictionStore, DatabaseBlockStore $blockStore, ReadOnlyMode $readOnlyMode, SpecialPageFactory $specialPageFactory, RepoGroup $repoGroup, NamespaceInfo $namespaceInfo, SkinFactory $skinFactory, IConnectionProvider $dbProvider)
getIntroMessages(int $frames, array $skip, MessageLocalizer $localizer, ProperPageIdentity $page, ?RevisionRecord $revRecord, Authority $performer, ?string $editIntro, ?string $returnToQuery, bool $preview, ?string $section=null)
Return intro messages to be shown before an edit form.
Encapsulates a list of edit form intro messages (as HTML) with their identifiers.
This class is a collection of static functions that serve two purposes:
Definition Html.php:56
Variant of the Message class.
Class that generates HTML for internal links.
A class containing constants representing the names of configuration variables.
A service class for checking permissions To obtain an instance, use MediaWikiServices::getInstance()-...
Page revision base class.
Factory for handling the special page list and generating SpecialPage objects.
Parent class for all special pages.
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
Represents a title within MediaWiki.
Definition Title.php:78
Service for temporary user creation.
Creates User objects.
UserNameUtils service.
Prioritized list of file repositories.
Definition RepoGroup.php:30
Factory class to create Skin objects.
The base class for all skins.
Definition Skin.php:59
static makeInternalOrExternalUrl( $name)
If url string starts with http, consider as external URL, else internal.
Definition Skin.php:1144
Determine whether a site is currently in read-only mode.
Represents a block that may prevent users from performing specific operations.
Definition Block.php:45
Interface for configuration instances.
Definition Config.php:32
Interface for a page that is (or could be, or used to be) an editable wiki page.
This interface represents the authority associated with the current execution context,...
Definition Authority.php:37
Shared interface for rigor levels when dealing with User methods.
Interface for localizing messages in MediaWiki.
msg( $key,... $params)
This is the method for getting translated interface messages.
Provide primary and replica IDatabase connections.
$source