MediaWiki REL1_34
SpecialEditWatchlist.php
Go to the documentation of this file.
1<?php
32
46 const EDIT_CLEAR = 1;
47 const EDIT_RAW = 2;
48 const EDIT_NORMAL = 3;
49
50 protected $successMessage;
51
52 protected $toc;
53
54 private $badItems = [];
55
59 private $titleParser;
60
61 public function __construct() {
62 parent::__construct( 'EditWatchlist', 'editmywatchlist' );
63 }
64
69 private function initServices() {
70 if ( !$this->titleParser ) {
71 $this->titleParser = MediaWikiServices::getInstance()->getTitleParser();
72 }
73 }
74
75 public function doesWrites() {
76 return true;
77 }
78
84 public function execute( $mode ) {
85 $this->initServices();
86 $this->setHeaders();
87
88 # Anons don't get a watchlist
89 $this->requireLogin( 'watchlistanontext' );
90
91 $out = $this->getOutput();
92
93 $this->checkPermissions();
94 $this->checkReadOnly();
95
96 $this->outputHeader();
97 $this->outputSubtitle();
98 $out->addModuleStyles( 'mediawiki.special' );
99
100 # B/C: $mode used to be waaay down the parameter list, and the first parameter
101 # was $wgUser
102 if ( $mode instanceof User ) {
103 $args = func_get_args();
104 if ( count( $args ) >= 4 ) {
105 $mode = $args[3];
106 }
107 }
108 $mode = self::getMode( $this->getRequest(), $mode );
109
110 switch ( $mode ) {
111 case self::EDIT_RAW:
112 $out->setPageTitle( $this->msg( 'watchlistedit-raw-title' ) );
113 $form = $this->getRawForm();
114 if ( $form->show() ) {
115 $out->addHTML( $this->successMessage );
116 $out->addReturnTo( SpecialPage::getTitleFor( 'Watchlist' ) );
117 }
118 break;
119 case self::EDIT_CLEAR:
120 $out->setPageTitle( $this->msg( 'watchlistedit-clear-title' ) );
121 $form = $this->getClearForm();
122 if ( $form->show() ) {
123 $out->addHTML( $this->successMessage );
124 $out->addReturnTo( SpecialPage::getTitleFor( 'Watchlist' ) );
125 }
126 break;
127
129 default:
131 break;
132 }
133 }
134
138 protected function outputSubtitle() {
139 $out = $this->getOutput();
140 $out->addSubtitle( $this->msg( 'watchlistfor2', $this->getUser()->getName() )
141 ->rawParams(
142 self::buildTools(
143 $this->getLanguage(),
144 $this->getLinkRenderer()
145 )
146 )
147 );
148 }
149
153 protected function executeViewEditWatchlist() {
154 $out = $this->getOutput();
155 $out->setPageTitle( $this->msg( 'watchlistedit-normal-title' ) );
156 $form = $this->getNormalForm();
157 if ( $form->show() ) {
158 $out->addHTML( $this->successMessage );
159 $out->addReturnTo( SpecialPage::getTitleFor( 'Watchlist' ) );
160 } elseif ( $this->toc !== false ) {
161 $out->prependHTML( $this->toc );
162 $out->addModuleStyles( 'mediawiki.toc.styles' );
163 }
164 }
165
172 public function getSubpagesForPrefixSearch() {
173 // SpecialWatchlist uses SpecialEditWatchlist::getMode, so new types should be added
174 // here and there - no 'edit' here, because that the default for this page
175 return [
176 'clear',
177 'raw',
178 ];
179 }
180
188 private function extractTitles( $list ) {
189 $list = explode( "\n", trim( $list ) );
190 if ( !is_array( $list ) ) {
191 return [];
192 }
193
194 $titles = [];
195
196 foreach ( $list as $text ) {
197 $text = trim( $text );
198 if ( strlen( $text ) > 0 ) {
199 $title = Title::newFromText( $text );
200 if ( $title instanceof Title && $title->isWatchable() ) {
201 $titles[] = $title;
202 }
203 }
204 }
205
206 MediaWikiServices::getInstance()->getGenderCache()->doTitlesArray( $titles );
207
208 $list = [];
210 foreach ( $titles as $title ) {
211 $list[] = $title->getPrefixedText();
212 }
213
214 return array_unique( $list );
215 }
216
217 public function submitRaw( $data ) {
218 $wanted = $this->extractTitles( $data['Titles'] );
219 $current = $this->getWatchlist();
220
221 if ( count( $wanted ) > 0 ) {
222 $toWatch = array_diff( $wanted, $current );
223 $toUnwatch = array_diff( $current, $wanted );
224 $this->watchTitles( $toWatch );
225 $this->unwatchTitles( $toUnwatch );
226 $this->getUser()->invalidateCache();
227
228 if ( count( $toWatch ) > 0 || count( $toUnwatch ) > 0 ) {
229 $this->successMessage = $this->msg( 'watchlistedit-raw-done' )->parse();
230 } else {
231 return false;
232 }
233
234 if ( count( $toWatch ) > 0 ) {
235 $this->successMessage .= ' ' . $this->msg( 'watchlistedit-raw-added' )
236 ->numParams( count( $toWatch ) )->parse();
237 $this->showTitles( $toWatch, $this->successMessage );
238 }
239
240 if ( count( $toUnwatch ) > 0 ) {
241 $this->successMessage .= ' ' . $this->msg( 'watchlistedit-raw-removed' )
242 ->numParams( count( $toUnwatch ) )->parse();
243 $this->showTitles( $toUnwatch, $this->successMessage );
244 }
245 } else {
246
247 if ( count( $current ) === 0 ) {
248 return false;
249 }
250
251 $this->clearUserWatchedItems( $current, 'raw' );
252 $this->showTitles( $current, $this->successMessage );
253 }
254
255 return true;
256 }
257
258 public function submitClear( $data ) {
259 $current = $this->getWatchlist();
260 $this->clearUserWatchedItems( $current, 'clear' );
261 $this->showTitles( $current, $this->successMessage );
262 return true;
263 }
264
269 private function clearUserWatchedItems( $current, $messageFor ) {
270 $watchedItemStore = MediaWikiServices::getInstance()->getWatchedItemStore();
271 if ( $watchedItemStore->clearUserWatchedItems( $this->getUser() ) ) {
272 $this->successMessage = $this->msg( 'watchlistedit-' . $messageFor . '-done' )->parse();
273 $this->successMessage .= ' ' . $this->msg( 'watchlistedit-' . $messageFor . '-removed' )
274 ->numParams( count( $current ) )->parse();
275 $this->getUser()->invalidateCache();
276 } else {
277 $watchedItemStore->clearUserWatchedItemsUsingJobQueue( $this->getUser() );
278 $this->successMessage = $this->msg( 'watchlistedit-clear-jobqueue' )->parse();
279 }
280 }
281
291 private function showTitles( $titles, &$output ) {
292 $talk = $this->msg( 'talkpagelinktext' )->text();
293 // Do a batch existence check
294 $batch = new LinkBatch();
295 if ( count( $titles ) >= 100 ) {
296 $output = $this->msg( 'watchlistedit-too-many' )->parse();
297 return;
298 }
299 foreach ( $titles as $title ) {
300 if ( !$title instanceof Title ) {
301 $title = Title::newFromText( $title );
302 }
303
304 if ( $title instanceof Title ) {
305 $batch->addObj( $title );
306 $batch->addObj( $title->getTalkPage() );
307 }
308 }
309
310 $batch->execute();
311
312 // Print out the list
313 $output .= "<ul>\n";
314
316 foreach ( $titles as $title ) {
317 if ( !$title instanceof Title ) {
318 $title = Title::newFromText( $title );
319 }
320
321 if ( $title instanceof Title ) {
322 $output .= '<li>' .
323 $linkRenderer->makeLink( $title ) . ' ' .
324 $this->msg( 'parentheses' )->rawParams(
325 $linkRenderer->makeLink( $title->getTalkPage(), $talk )
326 )->escaped() .
327 "</li>\n";
328 }
329 }
330
331 $output .= "</ul>\n";
332 }
333
340 private function getWatchlist() {
341 $list = [];
342
343 $watchedItems = MediaWikiServices::getInstance()->getWatchedItemStore()->getWatchedItemsForUser(
344 $this->getUser(),
345 [ 'forWrite' => $this->getRequest()->wasPosted() ]
346 );
347
348 if ( $watchedItems ) {
350 $titles = [];
351 foreach ( $watchedItems as $watchedItem ) {
352 $namespace = $watchedItem->getLinkTarget()->getNamespace();
353 $dbKey = $watchedItem->getLinkTarget()->getDBkey();
354 $title = Title::makeTitleSafe( $namespace, $dbKey );
355
356 if ( $this->checkTitle( $title, $namespace, $dbKey )
357 && !$title->isTalkPage()
358 ) {
359 $titles[] = $title;
360 }
361 }
362
363 MediaWikiServices::getInstance()->getGenderCache()->doTitlesArray( $titles );
364
365 foreach ( $titles as $title ) {
366 $list[] = $title->getPrefixedText();
367 }
368 }
369
370 $this->cleanupWatchlist();
371
372 return $list;
373 }
374
381 protected function getWatchlistInfo() {
382 $titles = [];
383 $services = MediaWikiServices::getInstance();
384
385 $watchedItems = $services->getWatchedItemStore()
386 ->getWatchedItemsForUser( $this->getUser(), [ 'sort' => WatchedItemStore::SORT_ASC ] );
387
388 $lb = new LinkBatch();
389
390 foreach ( $watchedItems as $watchedItem ) {
391 $namespace = $watchedItem->getLinkTarget()->getNamespace();
392 $dbKey = $watchedItem->getLinkTarget()->getDBkey();
393 $lb->add( $namespace, $dbKey );
394 if ( !$services->getNamespaceInfo()->isTalk( $namespace ) ) {
395 $titles[$namespace][$dbKey] = 1;
396 }
397 }
398
399 $lb->execute();
400
401 return $titles;
402 }
403
412 private function checkTitle( $title, $namespace, $dbKey ) {
413 if ( $title
414 && ( $title->isExternal()
415 || $title->getNamespace() < 0
416 )
417 ) {
418 $title = false; // unrecoverable
419 }
420
421 if ( !$title
422 || $title->getNamespace() != $namespace
423 || $title->getDBkey() != $dbKey
424 ) {
425 $this->badItems[] = [ $title, $namespace, $dbKey ];
426 }
427
428 return (bool)$title;
429 }
430
434 private function cleanupWatchlist() {
435 if ( $this->badItems === [] ) {
436 return; // nothing to do
437 }
438
439 $user = $this->getUser();
441 DeferredUpdates::addCallableUpdate( function () use ( $user, $badItems ) {
442 $store = MediaWikiServices::getInstance()->getWatchedItemStore();
443 foreach ( $badItems as $row ) {
444 list( $title, $namespace, $dbKey ) = $row;
445 $action = $title ? 'cleaning up' : 'deleting';
446 wfDebug( "User {$user->getName()} has broken watchlist item " .
447 "ns($namespace):$dbKey, $action.\n" );
448
449 $store->removeWatch( $user, new TitleValue( (int)$namespace, $dbKey ) );
450 // Can't just do an UPDATE instead of DELETE/INSERT due to unique index
451 if ( $title ) {
452 $user->addWatch( $title );
453 }
454 }
455 } );
456 }
457
466 private function watchTitles( array $targets ) {
467 return MediaWikiServices::getInstance()->getWatchedItemStore()
468 ->addWatchBatchForUser( $this->getUser(), $this->getExpandedTargets( $targets ) )
469 && $this->runWatchUnwatchCompleteHook( 'Watch', $targets );
470 }
471
484 private function unwatchTitles( array $targets ) {
485 return MediaWikiServices::getInstance()->getWatchedItemStore()
486 ->removeWatchBatchForUser( $this->getUser(), $this->getExpandedTargets( $targets ) )
487 && $this->runWatchUnwatchCompleteHook( 'Unwatch', $targets );
488 }
489
498 private function runWatchUnwatchCompleteHook( $action, $targets ) {
499 foreach ( $targets as $target ) {
500 $title = $target instanceof TitleValue ?
501 Title::newFromTitleValue( $target ) :
502 Title::newFromText( $target );
503 $page = WikiPage::factory( $title );
504 Hooks::run( $action . 'ArticleComplete', [ $this->getUser(), &$page ] );
505 }
506 return true;
507 }
508
513 private function getExpandedTargets( array $targets ) {
514 $expandedTargets = [];
515 $services = MediaWikiServices::getInstance();
516 foreach ( $targets as $target ) {
517 if ( !$target instanceof LinkTarget ) {
518 try {
519 $target = $this->titleParser->parseTitle( $target, NS_MAIN );
520 }
521 catch ( MalformedTitleException $e ) {
522 continue;
523 }
524 }
525
526 $ns = $target->getNamespace();
527 $dbKey = $target->getDBkey();
528 $expandedTargets[] =
529 new TitleValue( $services->getNamespaceInfo()->getSubject( $ns ), $dbKey );
530 $expandedTargets[] =
531 new TitleValue( $services->getNamespaceInfo()->getTalk( $ns ), $dbKey );
532 }
533 return $expandedTargets;
534 }
535
536 public function submitNormal( $data ) {
537 $removed = [];
538
539 foreach ( $data as $titles ) {
540 $this->unwatchTitles( $titles );
541 $removed = array_merge( $removed, $titles );
542 }
543
544 if ( count( $removed ) > 0 ) {
545 $this->successMessage = $this->msg( 'watchlistedit-normal-done'
546 )->numParams( count( $removed ) )->parse();
547 $this->showTitles( $removed, $this->successMessage );
548
549 return true;
550 } else {
551 return false;
552 }
553 }
554
560 protected function getNormalForm() {
561 $fields = [];
562 $count = 0;
563
564 // Allow subscribers to manipulate the list of watched pages (or use it
565 // to preload lots of details at once)
566 $watchlistInfo = $this->getWatchlistInfo();
567 Hooks::run(
568 'WatchlistEditorBeforeFormRender',
569 [ &$watchlistInfo ]
570 );
571
572 foreach ( $watchlistInfo as $namespace => $pages ) {
573 $options = [];
574
575 foreach ( array_keys( $pages ) as $dbkey ) {
576 $title = Title::makeTitleSafe( $namespace, $dbkey );
577
578 if ( $this->checkTitle( $title, $namespace, $dbkey ) ) {
579 $text = $this->buildRemoveLine( $title );
580 $options[$text] = $title->getPrefixedText();
581 $count++;
582 }
583 }
584
585 // checkTitle can filter some options out, avoid empty sections
586 if ( count( $options ) > 0 ) {
587 $fields['TitlesNs' . $namespace] = [
588 'class' => EditWatchlistCheckboxSeriesField::class,
589 'options' => $options,
590 'section' => "ns$namespace",
591 ];
592 }
593 }
594 $this->cleanupWatchlist();
595
596 if ( count( $fields ) > 1 && $count > 30 ) {
597 $this->toc = Linker::tocIndent();
598 $tocLength = 0;
599 $contLang = MediaWikiServices::getInstance()->getContentLanguage();
600
601 foreach ( $fields as $data ) {
602 # strip out the 'ns' prefix from the section name:
603 $ns = substr( $data['section'], 2 );
604
605 $nsText = ( $ns == NS_MAIN )
606 ? $this->msg( 'blanknamespace' )->escaped()
607 : htmlspecialchars( $contLang->getFormattedNsText( $ns ) );
608 $this->toc .= Linker::tocLine( "editwatchlist-{$data['section']}", $nsText,
609 $this->getLanguage()->formatNum( ++$tocLength ), 1 ) . Linker::tocLineEnd();
610 }
611
612 $this->toc = Linker::tocList( $this->toc );
613 } else {
614 $this->toc = false;
615 }
616
617 $context = new DerivativeContext( $this->getContext() );
618 $context->setTitle( $this->getPageTitle() ); // Remove subpage
619 $form = new EditWatchlistNormalHTMLForm( $fields, $context );
620 $form->setSubmitTextMsg( 'watchlistedit-normal-submit' );
621 $form->setSubmitDestructive();
622 # Used message keys:
623 # 'accesskey-watchlistedit-normal-submit', 'tooltip-watchlistedit-normal-submit'
624 $form->setSubmitTooltip( 'watchlistedit-normal-submit' );
625 $form->setWrapperLegendMsg( 'watchlistedit-normal-legend' );
626 $form->addHeaderText( $this->msg( 'watchlistedit-normal-explain' )->parse() );
627 $form->setSubmitCallback( [ $this, 'submitNormal' ] );
628
629 return $form;
630 }
631
638 private function buildRemoveLine( $title ) {
640 $link = $linkRenderer->makeLink( $title );
641
642 $tools = [];
643 $tools['talk'] = $linkRenderer->makeLink(
644 $title->getTalkPage(),
645 $this->msg( 'talkpagelinktext' )->text()
646 );
647
648 if ( $title->exists() ) {
649 $tools['history'] = $linkRenderer->makeKnownLink(
650 $title,
651 $this->msg( 'history_small' )->text(),
652 [],
653 [ 'action' => 'history' ]
654 );
655 }
656
657 if ( $title->getNamespace() == NS_USER && !$title->isSubpage() ) {
658 $tools['contributions'] = $linkRenderer->makeKnownLink(
659 SpecialPage::getTitleFor( 'Contributions', $title->getText() ),
660 $this->msg( 'contribslink' )->text()
661 );
662 }
663
664 Hooks::run(
665 'WatchlistEditorBuildRemoveLine',
666 [ &$tools, $title, $title->isRedirect(), $this->getSkin(), &$link ]
667 );
668
669 if ( $title->isRedirect() ) {
670 // Linker already makes class mw-redirect, so this is redundant
671 $link = '<span class="watchlistredir">' . $link . '</span>';
672 }
673
674 return $link . ' ' .
675 $this->msg( 'parentheses' )->rawParams( $this->getLanguage()->pipeList( $tools ) )->escaped();
676 }
677
683 protected function getRawForm() {
684 $titles = implode( "\n", $this->getWatchlist() );
685 $fields = [
686 'Titles' => [
687 'type' => 'textarea',
688 'label-message' => 'watchlistedit-raw-titles',
689 'default' => $titles,
690 ],
691 ];
692 $context = new DerivativeContext( $this->getContext() );
693 $context->setTitle( $this->getPageTitle( 'raw' ) ); // Reset subpage
694 $form = new OOUIHTMLForm( $fields, $context );
695 $form->setSubmitTextMsg( 'watchlistedit-raw-submit' );
696 # Used message keys: 'accesskey-watchlistedit-raw-submit', 'tooltip-watchlistedit-raw-submit'
697 $form->setSubmitTooltip( 'watchlistedit-raw-submit' );
698 $form->setWrapperLegendMsg( 'watchlistedit-raw-legend' );
699 $form->addHeaderText( $this->msg( 'watchlistedit-raw-explain' )->parse() );
700 $form->setSubmitCallback( [ $this, 'submitRaw' ] );
701
702 return $form;
703 }
704
710 protected function getClearForm() {
711 $context = new DerivativeContext( $this->getContext() );
712 $context->setTitle( $this->getPageTitle( 'clear' ) ); // Reset subpage
713 $form = new OOUIHTMLForm( [], $context );
714 $form->setSubmitTextMsg( 'watchlistedit-clear-submit' );
715 # Used message keys: 'accesskey-watchlistedit-clear-submit', 'tooltip-watchlistedit-clear-submit'
716 $form->setSubmitTooltip( 'watchlistedit-clear-submit' );
717 $form->setWrapperLegendMsg( 'watchlistedit-clear-legend' );
718 $form->addHeaderText( $this->msg( 'watchlistedit-clear-explain' )->parse() );
719 $form->setSubmitCallback( [ $this, 'submitClear' ] );
720 $form->setSubmitDestructive();
721
722 return $form;
723 }
724
733 public static function getMode( $request, $par ) {
734 $mode = strtolower( $request->getVal( 'action', $par ) );
735
736 switch ( $mode ) {
737 case 'clear':
738 case self::EDIT_CLEAR:
739 return self::EDIT_CLEAR;
740 case 'raw':
741 case self::EDIT_RAW:
742 return self::EDIT_RAW;
743 case 'edit':
745 return self::EDIT_NORMAL;
746 default:
747 return false;
748 }
749 }
750
759 public static function buildTools( $lang, LinkRenderer $linkRenderer = null ) {
760 if ( !$lang instanceof Language ) {
761 // back-compat where the first parameter was $unused
762 global $wgLang;
763 $lang = $wgLang;
764 }
765 if ( !$linkRenderer ) {
766 $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
767 }
768
769 $tools = [];
770 $modes = [
771 'view' => [ 'Watchlist', false ],
772 'edit' => [ 'EditWatchlist', false ],
773 'raw' => [ 'EditWatchlist', 'raw' ],
774 'clear' => [ 'EditWatchlist', 'clear' ],
775 ];
776
777 foreach ( $modes as $mode => $arr ) {
778 // can use messages 'watchlisttools-view', 'watchlisttools-edit', 'watchlisttools-raw'
779 $tools[] = $linkRenderer->makeKnownLink(
780 SpecialPage::getTitleFor( $arr[0], $arr[1] ),
781 wfMessage( "watchlisttools-{$mode}" )->text()
782 );
783 }
784
785 return Html::rawElement(
786 'span',
787 [ 'class' => 'mw-watchlist-toollinks' ],
788 wfMessage( 'parentheses' )->rawParams( $lang->pipeList( $tools ) )->escaped()
789 );
790 }
791}
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
$wgLang
Definition Setup.php:880
if( $line===false) $args
Definition cdb.php:64
An IContextSource implementation which will inherit context from another source but allow individual ...
Extend OOUIHTMLForm purely so we can have a more sane way of getting the section headers.
Internationalisation code.
Definition Language.php:37
Class representing a list of titles The execute() method checks them all for existence and adds them ...
Definition LinkBatch.php:34
static tocLine( $anchor, $tocline, $tocnumber, $level, $sectionIndex=false)
parameter level defines if we are on an indentation level
Definition Linker.php:1643
static tocIndent()
Add another level to the Table of Contents.
Definition Linker.php:1617
static tocList( $toc, Language $lang=null)
Wraps the TOC in a table and provides the hide/collapse javascript.
Definition Linker.php:1679
static tocLineEnd()
End a Table Of Contents line.
Definition Linker.php:1667
MalformedTitleException is thrown when a TitleParser is unable to parse a title string.
Class that generates HTML links for pages.
MediaWikiServices is the service locator for the application scope of MediaWiki.
Compact stacked vertical format for forms, implemented using OOUI widgets.
Provides the UI through which users can perform editing operations on their watchlist.
getRawForm()
Get a form for editing the watchlist in "raw" mode.
extractTitles( $list)
Extract a list of titles from a blob of text, returning (prefixed) strings; unwatchable titles are ig...
getNormalForm()
Get the standard watchlist editing form.
unwatchTitles(array $targets)
Remove a list of titles from a user's watchlist.
doesWrites()
Indicates whether this special page may perform database writes.
cleanupWatchlist()
Attempts to clean up broken items.
executeViewEditWatchlist()
Executes an edit mode for the watchlist view, from which you can manage your watchlist.
runWatchUnwatchCompleteHook( $action, $targets)
getSubpagesForPrefixSearch()
Return an array of subpages that this special page will accept.
clearUserWatchedItems( $current, $messageFor)
static buildTools( $lang, LinkRenderer $linkRenderer=null)
Build a set of links for convenient navigation between watchlist viewing and editing modes.
getWatchlistInfo()
Get a list of titles on a user's watchlist, excluding talk pages, and return as a two-dimensional arr...
checkTitle( $title, $namespace, $dbKey)
Validates watchlist entry.
getClearForm()
Get a form for clearing the watchlist.
getExpandedTargets(array $targets)
const EDIT_CLEAR
Editing modes.
buildRemoveLine( $title)
Build the label for a checkbox, with a link to the title, and various additional bits.
execute( $mode)
Main execution point.
initServices()
Initialize any services we'll need (unless it has already been provided via a setter).
outputSubtitle()
Renders a subheader on the watchlist page.
showTitles( $titles, &$output)
Print out a list of linked titles.
watchTitles(array $targets)
Add a list of targets to a user's watchlist.
static getMode( $request, $par)
Determine whether we are editing the watchlist, and if so, what kind of editing operation.
getWatchlist()
Prepare a list of titles on a user's watchlist (excluding talk pages) and return an array of (prefixe...
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages Per default the message key is the canonical name o...
getName()
Get the name of this Special Page.
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
getOutput()
Get the OutputPage being used for this instance.
requireLogin( $reasonMsg='exception-nologin-text', $titleMsg='exception-nologin')
If the user is not logged in, throws UserNotLoggedIn error.
getUser()
Shortcut to get the User executing this instance.
checkPermissions()
Checks if userCanExecute, and if not throws a PermissionsError.
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
getContext()
Gets the context this SpecialPage is executed in.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getRequest()
Get the WebRequest being used for this instance.
checkReadOnly()
If the wiki is currently in readonly mode, throws a ReadOnlyError.
getPageTitle( $subpage=false)
Get a self-referential title object.
getLanguage()
Shortcut to get user's language.
MediaWiki Linker LinkRenderer null $linkRenderer
Represents a page (or page fragment) title within MediaWiki.
Represents a title within MediaWiki.
Definition Title.php:42
isWatchable()
Can this title be added to a user's watchlist?
Definition Title.php:1198
Shortcut to construct a special page which is unlisted by default.
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition User.php:51
const NS_USER
Definition Defines.php:71
const NS_MAIN
Definition Defines.php:69
A title parser service for MediaWiki.
$context
Definition load.php:45
if(!isset( $args[0])) $lang