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