MediaWiki  1.29.0
SpecialWatchlist.php
Go to the documentation of this file.
1 <?php
27 
35  public function __construct( $page = 'Watchlist', $restriction = 'viewmywatchlist' ) {
36  parent::__construct( $page, $restriction );
37  }
38 
39  public function doesWrites() {
40  return true;
41  }
42 
48  function execute( $subpage ) {
49  // Anons don't get a watchlist
50  $this->requireLogin( 'watchlistanontext' );
51 
52  $output = $this->getOutput();
53  $request = $this->getRequest();
54  $this->addHelpLink( 'Help:Watching pages' );
55  $output->addModules( [
56  'mediawiki.special.changeslist.visitedstatus',
57  'mediawiki.special.watchlist',
58  ] );
59 
60  $mode = SpecialEditWatchlist::getMode( $request, $subpage );
61  if ( $mode !== false ) {
62  if ( $mode === SpecialEditWatchlist::EDIT_RAW ) {
63  $title = SpecialPage::getTitleFor( 'EditWatchlist', 'raw' );
64  } elseif ( $mode === SpecialEditWatchlist::EDIT_CLEAR ) {
65  $title = SpecialPage::getTitleFor( 'EditWatchlist', 'clear' );
66  } else {
67  $title = SpecialPage::getTitleFor( 'EditWatchlist' );
68  }
69 
70  $output->redirect( $title->getLocalURL() );
71 
72  return;
73  }
74 
75  $this->checkPermissions();
76 
77  $user = $this->getUser();
78  $opts = $this->getOptions();
79 
80  $config = $this->getConfig();
81  if ( ( $config->get( 'EnotifWatchlist' ) || $config->get( 'ShowUpdatedMarker' ) )
82  && $request->getVal( 'reset' )
83  && $request->wasPosted()
84  && $user->matchEditToken( $request->getVal( 'token' ) )
85  ) {
86  $user->clearAllNotifications();
87  $output->redirect( $this->getPageTitle()->getFullURL( $opts->getChangedValues() ) );
88 
89  return;
90  }
91 
92  parent::execute( $subpage );
93  }
94 
101  public function getSubpagesForPrefixSearch() {
102  return [
103  'clear',
104  'edit',
105  'raw',
106  ];
107  }
108 
112  protected function transformFilterDefinition( array $filterDefinition ) {
113  if ( isset( $filterDefinition['showHideSuffix'] ) ) {
114  $filterDefinition['showHide'] = 'wl' . $filterDefinition['showHideSuffix'];
115  }
116 
117  return $filterDefinition;
118  }
119 
123  protected function registerFilters() {
124  parent::registerFilters();
125 
126  $user = $this->getUser();
127 
128  $significance = $this->getFilterGroup( 'significance' );
129  $hideMinor = $significance->getFilter( 'hideminor' );
130  $hideMinor->setDefault( $user->getBoolOption( 'watchlisthideminor' ) );
131 
132  $automated = $this->getFilterGroup( 'automated' );
133  $hideBots = $automated->getFilter( 'hidebots' );
134  $hideBots->setDefault( $user->getBoolOption( 'watchlisthidebots' ) );
135 
136  $registration = $this->getFilterGroup( 'registration' );
137  $hideAnons = $registration->getFilter( 'hideanons' );
138  $hideAnons->setDefault( $user->getBoolOption( 'watchlisthideanons' ) );
139  $hideLiu = $registration->getFilter( 'hideliu' );
140  $hideLiu->setDefault( $user->getBoolOption( 'watchlisthideliu' ) );
141 
142  $reviewStatus = $this->getFilterGroup( 'reviewStatus' );
143  if ( $reviewStatus !== null ) {
144  // Conditional on feature being available and rights
145  $hidePatrolled = $reviewStatus->getFilter( 'hidepatrolled' );
146  $hidePatrolled->setDefault( $user->getBoolOption( 'watchlisthidepatrolled' ) );
147  }
148 
149  $authorship = $this->getFilterGroup( 'authorship' );
150  $hideMyself = $authorship->getFilter( 'hidemyself' );
151  $hideMyself->setDefault( $user->getBoolOption( 'watchlisthideown' ) );
152 
153  $changeType = $this->getFilterGroup( 'changeType' );
154  $hideCategorization = $changeType->getFilter( 'hidecategorization' );
155  if ( $hideCategorization !== null ) {
156  // Conditional on feature being available
157  $hideCategorization->setDefault( $user->getBoolOption( 'watchlisthidecategorization' ) );
158  }
159  }
160 
166  public function getDefaultOptions() {
167  $opts = parent::getDefaultOptions();
168  $user = $this->getUser();
169 
170  $opts->add( 'days', $user->getOption( 'watchlistdays' ), FormOptions::FLOAT );
171  $opts->add( 'extended', $user->getBoolOption( 'extendwatchlist' ) );
172 
173  return $opts;
174  }
175 
181  protected function getCustomFilters() {
182  if ( $this->customFilters === null ) {
183  $this->customFilters = parent::getCustomFilters();
184  Hooks::run( 'SpecialWatchlistFilters', [ $this, &$this->customFilters ], '1.23' );
185  }
186 
187  return $this->customFilters;
188  }
189 
199  protected function fetchOptionsFromRequest( $opts ) {
200  static $compatibilityMap = [
201  'hideMinor' => 'hideminor',
202  'hideBots' => 'hidebots',
203  'hideAnons' => 'hideanons',
204  'hideLiu' => 'hideliu',
205  'hidePatrolled' => 'hidepatrolled',
206  'hideOwn' => 'hidemyself',
207  ];
208 
209  $params = $this->getRequest()->getValues();
210  foreach ( $compatibilityMap as $from => $to ) {
211  if ( isset( $params[$from] ) ) {
212  $params[$to] = $params[$from];
213  unset( $params[$from] );
214  }
215  }
216 
217  if ( $this->getRequest()->getVal( 'action' ) == 'submit' ) {
218  $allBooleansFalse = [];
219 
220  // If the user submitted the form, start with a baseline of "all
221  // booleans are false", then change the ones they checked. This
222  // means we ignore the defaults.
223 
224  // This is how we handle the fact that HTML forms don't submit
225  // unchecked boxes.
226  foreach ( $this->filterGroups as $filterGroup ) {
227  if ( $filterGroup instanceof ChangesListBooleanFilterGroup ) {
228  foreach ( $filterGroup->getFilters() as $filter ) {
229  $allBooleansFalse[$filter->getName()] = false;
230  }
231  }
232  }
233 
234  $params = $params + $allBooleansFalse;
235  }
236 
237  // Not the prettiest way to achieve this… FormOptions internally depends on data sanitization
238  // methods defined on WebRequest and removing this dependency would cause some code duplication.
239  $request = new DerivativeRequest( $this->getRequest(), $params );
240  $opts->fetchValuesFromRequest( $request );
241 
242  return $opts;
243  }
244 
248  protected function buildQuery( &$tables, &$fields, &$conds, &$query_options,
249  &$join_conds, FormOptions $opts ) {
250 
251  $dbr = $this->getDB();
252  parent::buildQuery( $tables, $fields, $conds, $query_options, $join_conds,
253  $opts );
254 
255  // Calculate cutoff
256  if ( $opts['days'] > 0 ) {
257  $conds[] = 'rc_timestamp > ' .
258  $dbr->addQuotes( $dbr->timestamp( time() - intval( $opts['days'] * 86400 ) ) );
259  }
260  }
261 
265  protected function doMainQuery( $tables, $fields, $conds, $query_options,
266  $join_conds, FormOptions $opts ) {
267 
268  $dbr = $this->getDB();
269  $user = $this->getUser();
270 
271  # Toggle watchlist content (all recent edits or just the latest)
272  if ( $opts['extended'] ) {
273  $limitWatchlist = $user->getIntOption( 'wllimit' );
274  $usePage = false;
275  } else {
276  # Top log Ids for a page are not stored
277  $nonRevisionTypes = [ RC_LOG ];
278  Hooks::run( 'SpecialWatchlistGetNonRevisionTypes', [ &$nonRevisionTypes ] );
279  if ( $nonRevisionTypes ) {
280  $conds[] = $dbr->makeList(
281  [
282  'rc_this_oldid=page_latest',
283  'rc_type' => $nonRevisionTypes,
284  ],
285  LIST_OR
286  );
287  }
288  $limitWatchlist = 0;
289  $usePage = true;
290  }
291 
292  $tables = array_merge( [ 'recentchanges', 'watchlist' ], $tables );
293  $fields = array_merge( RecentChange::selectFields(), $fields );
294 
295  $query_options = array_merge( [ 'ORDER BY' => 'rc_timestamp DESC' ], $query_options );
296  $join_conds = array_merge(
297  [
298  'watchlist' => [
299  'INNER JOIN',
300  [
301  'wl_user' => $user->getId(),
302  'wl_namespace=rc_namespace',
303  'wl_title=rc_title'
304  ],
305  ],
306  ],
307  $join_conds
308  );
309 
310  if ( $this->getConfig()->get( 'ShowUpdatedMarker' ) ) {
311  $fields[] = 'wl_notificationtimestamp';
312  }
313  if ( $limitWatchlist ) {
314  $query_options['LIMIT'] = $limitWatchlist;
315  }
316 
317  $rollbacker = $user->isAllowed( 'rollback' );
318  if ( $usePage || $rollbacker ) {
319  $tables[] = 'page';
320  $join_conds['page'] = [ 'LEFT JOIN', 'rc_cur_id=page_id' ];
321  if ( $rollbacker ) {
322  $fields[] = 'page_latest';
323  }
324  }
325 
326  // Log entries with DELETED_ACTION must not show up unless the user has
327  // the necessary rights.
328  if ( !$user->isAllowed( 'deletedhistory' ) ) {
329  $bitmask = LogPage::DELETED_ACTION;
330  } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
332  } else {
333  $bitmask = 0;
334  }
335  if ( $bitmask ) {
336  $conds[] = $dbr->makeList( [
337  'rc_type != ' . RC_LOG,
338  $dbr->bitAnd( 'rc_deleted', $bitmask ) . " != $bitmask",
339  ], LIST_OR );
340  }
341 
343  $tables,
344  $fields,
345  $conds,
346  $join_conds,
347  $query_options,
348  ''
349  );
350 
351  $this->runMainQueryHook( $tables, $fields, $conds, $query_options, $join_conds, $opts );
352 
353  return $dbr->select(
354  $tables,
355  $fields,
356  $conds,
357  __METHOD__,
358  $query_options,
359  $join_conds
360  );
361  }
362 
363  protected function runMainQueryHook( &$tables, &$fields, &$conds, &$query_options,
364  &$join_conds, $opts
365  ) {
366  return parent::runMainQueryHook( $tables, $fields, $conds, $query_options, $join_conds, $opts )
367  && Hooks::run(
368  'SpecialWatchlistQuery',
369  [ &$conds, &$tables, &$join_conds, &$fields, $opts ],
370  '1.23'
371  );
372  }
373 
379  protected function getDB() {
380  return wfGetDB( DB_REPLICA, 'watchlist' );
381  }
382 
386  public function outputFeedLinks() {
387  $user = $this->getUser();
388  $wlToken = $user->getTokenFromOption( 'watchlisttoken' );
389  if ( $wlToken ) {
390  $this->addFeedLinks( [
391  'action' => 'feedwatchlist',
392  'allrev' => 1,
393  'wlowner' => $user->getName(),
394  'wltoken' => $wlToken,
395  ] );
396  }
397  }
398 
405  public function outputChangesList( $rows, $opts ) {
406  $dbr = $this->getDB();
407  $user = $this->getUser();
408  $output = $this->getOutput();
409 
410  # Show a message about replica DB lag, if applicable
411  $lag = wfGetLB()->safeGetLag( $dbr );
412  if ( $lag > 0 ) {
413  $output->showLagWarning( $lag );
414  }
415 
416  # If no rows to display, show message before try to render the list
417  if ( $rows->numRows() == 0 ) {
418  $output->wrapWikiMsg(
419  "<div class='mw-changeslist-empty'>\n$1\n</div>", 'recentchanges-noresult'
420  );
421  return;
422  }
423 
424  $dbr->dataSeek( $rows, 0 );
425 
426  $list = ChangesList::newFromContext( $this->getContext(), $this->filterGroups );
427  $list->setWatchlistDivs();
428  $list->initChangesListRows( $rows );
429  $dbr->dataSeek( $rows, 0 );
430 
431  if ( $this->getConfig()->get( 'RCShowWatchingUsers' )
432  && $user->getOption( 'shownumberswatching' )
433  ) {
434  $watchedItemStore = MediaWikiServices::getInstance()->getWatchedItemStore();
435  }
436 
437  $s = $list->beginRecentChangesList();
438  $userShowHiddenCats = $this->getUser()->getBoolOption( 'showhiddencats' );
439  $counter = 1;
440  foreach ( $rows as $obj ) {
441  # Make RC entry
442  $rc = RecentChange::newFromRow( $obj );
443 
444  # Skip CatWatch entries for hidden cats based on user preference
445  if (
446  $rc->getAttribute( 'rc_type' ) == RC_CATEGORIZE &&
447  !$userShowHiddenCats &&
448  $rc->getParam( 'hidden-cat' )
449  ) {
450  continue;
451  }
452 
453  $rc->counter = $counter++;
454 
455  if ( $this->getConfig()->get( 'ShowUpdatedMarker' ) ) {
456  $updated = $obj->wl_notificationtimestamp;
457  } else {
458  $updated = false;
459  }
460 
461  if ( isset( $watchedItemStore ) ) {
462  $rcTitleValue = new TitleValue( (int)$obj->rc_namespace, $obj->rc_title );
463  $rc->numberofWatchingusers = $watchedItemStore->countWatchers( $rcTitleValue );
464  } else {
465  $rc->numberofWatchingusers = 0;
466  }
467 
468  $changeLine = $list->recentChangesLine( $rc, $updated, $counter );
469  if ( $changeLine !== false ) {
470  $s .= $changeLine;
471  }
472  }
473  $s .= $list->endRecentChangesList();
474 
475  $output->addHTML( $s );
476  }
477 
484  public function doHeader( $opts, $numRows ) {
485  $user = $this->getUser();
486  $out = $this->getOutput();
487 
488  $out->addSubtitle(
489  $this->msg( 'watchlistfor2', $user->getName() )
491  $this->getLanguage(),
492  $this->getLinkRenderer()
493  ) )
494  );
495 
496  $this->setTopText( $opts );
497 
498  $lang = $this->getLanguage();
499  if ( $opts['days'] > 0 ) {
500  $days = $opts['days'];
501  } else {
502  $days = $this->getConfig()->get( 'RCMaxAge' ) / ( 3600 * 24 );
503  }
504  $timestamp = wfTimestampNow();
505  $wlInfo = $this->msg( 'wlnote' )->numParams( $numRows, round( $days * 24 ) )->params(
506  $lang->userDate( $timestamp, $user ), $lang->userTime( $timestamp, $user )
507  )->parse() . "<br />\n";
508 
509  $nondefaults = $opts->getChangedValues();
510  $cutofflinks = $this->msg( 'wlshowtime' ) . ' ' . $this->cutoffselector( $opts );
511 
512  # Spit out some control panel links
513  $links = [];
514  $context = $this->getContext();
515  $namesOfDisplayedFilters = [];
516  foreach ( $this->getFilterGroups() as $groupName => $group ) {
517  if ( !$group->isPerGroupRequestParameter() ) {
518  foreach ( $group->getFilters() as $filterName => $filter ) {
519  if ( $filter->displaysOnUnstructuredUi( $this ) ) {
520  $namesOfDisplayedFilters[] = $filterName;
521  $links[] = $this->showHideCheck(
522  $nondefaults,
523  $filter->getShowHide(),
524  $filterName,
525  $opts[$filterName]
526  );
527  }
528  }
529  }
530  }
531 
532  $hiddenFields = $nondefaults;
533  $hiddenFields['action'] = 'submit';
534  unset( $hiddenFields['namespace'] );
535  unset( $hiddenFields['invert'] );
536  unset( $hiddenFields['associated'] );
537  unset( $hiddenFields['days'] );
538  foreach ( $namesOfDisplayedFilters as $filterName ) {
539  unset( $hiddenFields[$filterName] );
540  }
541 
542  # Create output
543  $form = '';
544 
545  # Namespace filter and put the whole form together.
546  $form .= $wlInfo;
547  $form .= $cutofflinks;
548  $form .= $this->msg( 'watchlist-hide' ) .
549  $this->msg( 'colon-separator' )->escaped() .
550  implode( ' ', $links );
551  $form .= "\n<br />\n";
552  $form .= Html::namespaceSelector(
553  [
554  'selected' => $opts['namespace'],
555  'all' => '',
556  'label' => $this->msg( 'namespace' )->text()
557  ], [
558  'name' => 'namespace',
559  'id' => 'namespace',
560  'class' => 'namespaceselector',
561  ]
562  ) . "\n";
563  $form .= '<span class="mw-input-with-label">' . Xml::checkLabel(
564  $this->msg( 'invert' )->text(),
565  'invert',
566  'nsinvert',
567  $opts['invert'],
568  [ 'title' => $this->msg( 'tooltip-invert' )->text() ]
569  ) . "</span>\n";
570  $form .= '<span class="mw-input-with-label">' . Xml::checkLabel(
571  $this->msg( 'namespace_association' )->text(),
572  'associated',
573  'nsassociated',
574  $opts['associated'],
575  [ 'title' => $this->msg( 'tooltip-namespace_association' )->text() ]
576  ) . "</span>\n";
577  $form .= Xml::submitButton( $this->msg( 'watchlist-submit' )->text() ) . "\n";
578  foreach ( $hiddenFields as $key => $value ) {
579  $form .= Html::hidden( $key, $value ) . "\n";
580  }
581  $form .= Xml::closeElement( 'fieldset' ) . "\n";
582  $form .= Xml::closeElement( 'form' ) . "\n";
583  $this->getOutput()->addHTML( $form );
584 
585  $this->setBottomText( $opts );
586  }
587 
588  function cutoffselector( $options ) {
589  // Cast everything to strings immediately, so that we know all of the values have the same
590  // precision, and can be compared with '==='. 2/24 has a few more decimal places than its
591  // default string representation, for example, and would confuse comparisons.
592 
593  // Misleadingly, the 'days' option supports hours too.
594  $days = array_map( 'strval', [ 1/24, 2/24, 6/24, 12/24, 1, 3, 7 ] );
595 
596  $userWatchlistOption = (string)$this->getUser()->getOption( 'watchlistdays' );
597  // add the user preference, if it isn't available already
598  if ( !in_array( $userWatchlistOption, $days ) && $userWatchlistOption !== '0' ) {
599  $days[] = $userWatchlistOption;
600  }
601 
602  $maxDays = (string)( $this->getConfig()->get( 'RCMaxAge' ) / ( 3600 * 24 ) );
603  // add the maximum possible value, if it isn't available already
604  if ( !in_array( $maxDays, $days ) ) {
605  $days[] = $maxDays;
606  }
607 
608  $selected = (string)$options['days'];
609  if ( $selected <= 0 ) {
610  $selected = $maxDays;
611  }
612 
613  // add the currently selected value, if it isn't available already
614  if ( !in_array( $selected, $days ) ) {
615  $days[] = $selected;
616  }
617 
618  $select = new XmlSelect( 'days', 'days', $selected );
619 
620  asort( $days );
621  foreach ( $days as $value ) {
622  if ( $value < 1 ) {
623  $name = $this->msg( 'hours' )->numParams( $value * 24 )->text();
624  } else {
625  $name = $this->msg( 'days' )->numParams( $value )->text();
626  }
627  $select->addOption( $name, $value );
628  }
629 
630  return $select->getHTML() . "\n<br />\n";
631  }
632 
633  function setTopText( FormOptions $opts ) {
634  $nondefaults = $opts->getChangedValues();
635  $form = "";
636  $user = $this->getUser();
637 
638  $numItems = $this->countItems();
639  $showUpdatedMarker = $this->getConfig()->get( 'ShowUpdatedMarker' );
640 
641  // Show watchlist header
642  $form .= "<p>";
643  if ( $numItems == 0 ) {
644  $form .= $this->msg( 'nowatchlist' )->parse() . "\n";
645  } else {
646  $form .= $this->msg( 'watchlist-details' )->numParams( $numItems )->parse() . "\n";
647  if ( $this->getConfig()->get( 'EnotifWatchlist' )
648  && $user->getOption( 'enotifwatchlistpages' )
649  ) {
650  $form .= $this->msg( 'wlheader-enotif' )->parse() . "\n";
651  }
652  if ( $showUpdatedMarker ) {
653  $form .= $this->msg( 'wlheader-showupdated' )->parse() . "\n";
654  }
655  }
656  $form .= "</p>";
657 
658  if ( $numItems > 0 && $showUpdatedMarker ) {
659  $form .= Xml::openElement( 'form', [ 'method' => 'post',
660  'action' => $this->getPageTitle()->getLocalURL(),
661  'id' => 'mw-watchlist-resetbutton' ] ) . "\n" .
662  Xml::submitButton( $this->msg( 'enotif_reset' )->text(),
663  [ 'name' => 'mw-watchlist-reset-submit' ] ) . "\n" .
664  Html::hidden( 'token', $user->getEditToken() ) . "\n" .
665  Html::hidden( 'reset', 'all' ) . "\n";
666  foreach ( $nondefaults as $key => $value ) {
667  $form .= Html::hidden( $key, $value ) . "\n";
668  }
669  $form .= Xml::closeElement( 'form' ) . "\n";
670  }
671 
672  $form .= Xml::openElement( 'form', [
673  'method' => 'get',
674  'action' => wfScript(),
675  'id' => 'mw-watchlist-form'
676  ] );
677  $form .= Html::hidden( 'title', $this->getPageTitle()->getPrefixedText() );
678  $form .= Xml::fieldset(
679  $this->msg( 'watchlist-options' )->text(),
680  false,
681  [ 'id' => 'mw-watchlist-options' ]
682  );
683 
684  $form .= $this->makeLegend();
685 
686  $this->getOutput()->addHTML( $form );
687  }
688 
689  protected function showHideCheck( $options, $message, $name, $value ) {
690  $options[$name] = 1 - (int)$value;
691 
692  return '<span class="mw-input-with-label">' . Xml::checkLabel(
693  $this->msg( $message, '' )->text(),
694  $name,
695  $name,
696  (int)$value
697  ) . '</span>';
698  }
699 
707  protected function countItems() {
708  $store = MediaWikiServices::getInstance()->getWatchedItemStore();
709  $count = $store->countWatchedItems( $this->getUser() );
710  return floor( $count / 2 );
711  }
712 }
DerivativeRequest
Similar to FauxRequest, but only fakes URL parameters and method (POST or GET) and use the base reque...
Definition: DerivativeRequest.php:34
SpecialPage\getPageTitle
getPageTitle( $subpage=false)
Get a self-referential title object.
Definition: SpecialPage.php:628
SpecialEditWatchlist\EDIT_CLEAR
const EDIT_CLEAR
Editing modes.
Definition: SpecialEditWatchlist.php:46
$context
error also a ContextSource you ll probably need to make sure the header is varied on and they can depend only on the ResourceLoaderContext $context
Definition: hooks.txt:2612
$request
error also a ContextSource you ll probably need to make sure the header is varied on $request
Definition: hooks.txt:2612
SpecialEditWatchlist\EDIT_RAW
const EDIT_RAW
Definition: SpecialEditWatchlist.php:47
$tables
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist Do not use this to implement individual filters if they are compatible with the ChangesListFilter and ChangesListFilterGroup structure use sub classes of those in conjunction with the ChangesListSpecialPageStructuredFilters hook This hook can be used to implement filters that do not implement that or custom behavior that is not an individual filter e g Watchlist & $tables
Definition: hooks.txt:990
FormOptions\FLOAT
const FLOAT
Float type, maps guessType() to WebRequest::getFloat()
Definition: FormOptions.php:48
SpecialPage\getOutput
getOutput()
Get the OutputPage being used for this instance.
Definition: SpecialPage.php:675
$lang
if(!isset( $args[0])) $lang
Definition: testCompression.php:33
ChangesListSpecialPage\makeLegend
makeLegend()
Return the legend displayed within the fieldset.
Definition: ChangesListSpecialPage.php:1137
wfGetLB
wfGetLB( $wiki=false)
Get a load balancer object.
Definition: GlobalFunctions.php:3073
text
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at etc Handles the details of getting and saving to the user table of the and dealing with sessions and cookies OutputPage Encapsulates the entire HTML page that will be sent in response to any server request It is used by calling its functions to add text
Definition: design.txt:12
SpecialWatchlist\getSubpagesForPrefixSearch
getSubpagesForPrefixSearch()
Return an array of subpages that this special page will accept.
Definition: SpecialWatchlist.php:101
SpecialWatchlist\getDB
getDB()
Return a IDatabase object for reading.
Definition: SpecialWatchlist.php:379
RC_LOG
const RC_LOG
Definition: Defines.php:142
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
ChangesListSpecialPage
Special page which uses a ChangesList to show query results.
Definition: ChangesListSpecialPage.php:33
$user
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a account $user
Definition: hooks.txt:246
SpecialPage\checkPermissions
checkPermissions()
Checks if userCanExecute, and if not throws a PermissionsError.
Definition: SpecialPage.php:306
$params
$params
Definition: styleTest.css.php:40
$s
$s
Definition: mergeMessageFileList.php:188
SpecialPage\getTitleFor
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,...
Definition: SpecialPage.php:82
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:304
SpecialWatchlist\__construct
__construct( $page='Watchlist', $restriction='viewmywatchlist')
Definition: SpecialWatchlist.php:35
Wikimedia\Rdbms\ResultWrapper
Result wrapper for grabbing data queried from an IDatabase object.
Definition: ResultWrapper.php:24
SpecialWatchlist\getDefaultOptions
getDefaultOptions()
Get a FormOptions object containing the default options.
Definition: SpecialWatchlist.php:166
SpecialPage\getLanguage
getLanguage()
Shortcut to get user's language.
Definition: SpecialPage.php:705
SpecialWatchlist\doHeader
doHeader( $opts, $numRows)
Set the text to be displayed above the changes.
Definition: SpecialWatchlist.php:484
Xml\openElement
static openElement( $element, $attribs=null)
This opens an XML element.
Definition: Xml.php:109
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
SpecialWatchlist\doMainQuery
doMainQuery( $tables, $fields, $conds, $query_options, $join_conds, FormOptions $opts)
Process the query.Array of tables; see IDatabase::select $table Array of fields; see IDatabase::selec...
Definition: SpecialWatchlist.php:265
Wikimedia\Rdbms\IDatabase
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:40
XmlSelect
Class for generating HTML <select> or <datalist> elements.
Definition: XmlSelect.php:26
$dbr
$dbr
Definition: testCompression.php:50
Xml\fieldset
static fieldset( $legend=false, $content=false, $attribs=[])
Shortcut for creating fieldsets.
Definition: Xml.php:577
SpecialPage\addHelpLink
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
Definition: SpecialPage.php:785
LIST_OR
const LIST_OR
Definition: Defines.php:44
SpecialWatchlist\transformFilterDefinition
transformFilterDefinition(array $filterDefinition)
Transforms filter definition to prepare it for constructor.See overrides of this method as well....
Definition: SpecialWatchlist.php:112
SpecialPage\getConfig
getConfig()
Shortcut to get main config object.
Definition: SpecialPage.php:714
$title
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:934
SpecialPage\addFeedLinks
addFeedLinks( $params)
Adds RSS/atom links.
Definition: SpecialPage.php:767
ChangeTags\modifyDisplayQuery
static modifyDisplayQuery(&$tables, &$fields, &$conds, &$join_conds, &$options, $filter_tag=false)
Applies all tags-related changes to a query.
Definition: ChangeTags.php:632
wfScript
wfScript( $script='index')
Get the path to a specified script file, respecting file extensions; this is a wrapper around $wgScri...
Definition: GlobalFunctions.php:3138
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:3060
$page
do that in ParserLimitReportFormat instead use this to modify the parameters of the image and a DIV can begin in one section and end in another Make sure your code can handle that case gracefully See the EditSectionClearerLink extension for an example zero but section is usually empty its values are the globals values before the output is cached $page
Definition: hooks.txt:2536
SpecialWatchlist\countItems
countItems()
Count the number of paired items on a user's watchlist.
Definition: SpecialWatchlist.php:707
RecentChange\newFromRow
static newFromRow( $row)
Definition: RecentChange.php:115
ChangesListSpecialPage\getFilterGroups
getFilterGroups()
Gets the currently registered filters groups.
Definition: ChangesListSpecialPage.php:792
$output
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist Do not use this to implement individual filters if they are compatible with the ChangesListFilter and ChangesListFilterGroup structure use sub classes of those in conjunction with the ChangesListSpecialPageStructuredFilters hook This hook can be used to implement filters that do not implement that or custom behavior that is not an individual filter e g Watchlist and Watchlist you will want to construct new ChangesListBooleanFilter or ChangesListStringOptionsFilter objects When constructing you specify which group they belong to You can reuse existing or create your you must register them with $special registerFilterGroup removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context the output can only depend on parameters provided to this hook not on global state indicating whether full HTML should be generated If generation of HTML may be but other information should still be present in the ParserOutput object & $output
Definition: hooks.txt:1049
SpecialWatchlist\cutoffselector
cutoffselector( $options)
Definition: SpecialWatchlist.php:588
SpecialPage\getUser
getUser()
Shortcut to get the User executing this instance.
Definition: SpecialPage.php:685
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
wfTimestampNow
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
Definition: GlobalFunctions.php:2023
SpecialWatchlist\registerFilters
registerFilters()
Register all filters and their groups (including those from hooks), plus handle conflicts and default...
Definition: SpecialWatchlist.php:123
string
This code would result in ircNotify being run twice when an article is and once for brion Hooks can return three possible true was required This is the default since MediaWiki *some string
Definition: hooks.txt:177
LogPage\DELETED_ACTION
const DELETED_ACTION
Definition: LogPage.php:32
SpecialPage\getContext
getContext()
Gets the context this SpecialPage is executed in.
Definition: SpecialPage.php:648
SpecialPage\requireLogin
requireLogin( $reasonMsg='exception-nologin-text', $titleMsg='exception-nologin')
If the user is not logged in, throws UserNotLoggedIn error.
Definition: SpecialPage.php:336
SpecialWatchlist
A special page that lists last changes made to the wiki, limited to user-defined list of titles.
Definition: SpecialWatchlist.php:34
ChangesList\newFromContext
static newFromContext(IContextSource $context, array $groups=[])
Fetch an appropriate changes list class for the specified context Some users might want to use an enh...
Definition: ChangesList.php:85
execute
$batch execute()
Html\hidden
static hidden( $name, $value, array $attribs=[])
Convenience function to produce an input element with type=hidden.
Definition: Html.php:746
SpecialWatchlist\execute
execute( $subpage)
Main execution point.
Definition: SpecialWatchlist.php:48
SpecialEditWatchlist\getMode
static getMode( $request, $par)
Determine whether we are editing the watchlist, and if so, what kind of editing operation.
Definition: SpecialEditWatchlist.php:714
$value
$value
Definition: styleTest.css.php:45
SpecialPage\msg
msg()
Wrapper around wfMessage that sets the current context.
Definition: SpecialPage.php:746
Html\namespaceSelector
static namespaceSelector(array $params=[], array $selectAttribs=[])
Build a drop-down box for selecting a namespace.
Definition: Html.php:834
ChangesListSpecialPage\getFilterGroup
getFilterGroup( $groupName)
Gets a specified ChangesListFilterGroup by name.
Definition: ChangesListSpecialPage.php:803
SpecialPage\getRequest
getRequest()
Get the WebRequest being used for this instance.
Definition: SpecialPage.php:665
SpecialWatchlist\outputFeedLinks
outputFeedLinks()
Output feed links.
Definition: SpecialWatchlist.php:386
SpecialPage\getLinkRenderer
getLinkRenderer()
Definition: SpecialPage.php:856
SpecialEditWatchlist\buildTools
static buildTools( $lang, LinkRenderer $linkRenderer=null)
Build a set of links for convenient navigation between watchlist viewing and editing modes.
Definition: SpecialEditWatchlist.php:740
SpecialWatchlist\doesWrites
doesWrites()
Indicates whether this special page may perform database writes.
Definition: SpecialWatchlist.php:39
ChangesListBooleanFilterGroup
If the group is active, any unchecked filters will translate to hide parameters in the URL.
Definition: ChangesListBooleanFilterGroup.php:10
RecentChange\selectFields
static selectFields()
Return the list of recentchanges fields that should be selected to create a new recentchanges object.
Definition: RecentChange.php:204
Xml\closeElement
static closeElement( $element)
Shortcut to close an XML element.
Definition: Xml.php:118
SpecialWatchlist\outputChangesList
outputChangesList( $rows, $opts)
Build and output the actual changes list.
Definition: SpecialWatchlist.php:405
SpecialWatchlist\buildQuery
buildQuery(&$tables, &$fields, &$conds, &$query_options, &$join_conds, FormOptions $opts)
Sets appropriate tables, fields, conditions, etc.depending on which filters the user requested....
Definition: SpecialWatchlist.php:248
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
SpecialWatchlist\runMainQueryHook
runMainQueryHook(&$tables, &$fields, &$conds, &$query_options, &$join_conds, $opts)
Definition: SpecialWatchlist.php:363
LogPage\DELETED_RESTRICTED
const DELETED_RESTRICTED
Definition: LogPage.php:35
SpecialWatchlist\getCustomFilters
getCustomFilters()
Get all custom filters.
Definition: SpecialWatchlist.php:181
RC_CATEGORIZE
const RC_CATEGORIZE
Definition: Defines.php:144
FormOptions
Helper class to keep track of options when mixing links and form elements.
Definition: FormOptions.php:35
MediaWikiServices
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency MediaWikiServices
Definition: injection.txt:23
FormOptions\getChangedValues
getChangedValues()
Return options modified as an array ( name => value )
Definition: FormOptions.php:303
SpecialWatchlist\setTopText
setTopText(FormOptions $opts)
Send the text to be displayed before the options.
Definition: SpecialWatchlist.php:633
SpecialWatchlist\fetchOptionsFromRequest
fetchOptionsFromRequest( $opts)
Fetch values for a FormOptions object from the WebRequest associated with this instance.
Definition: SpecialWatchlist.php:199
Hooks\run
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:131
SpecialWatchlist\showHideCheck
showHideCheck( $options, $message, $name, $value)
Definition: SpecialWatchlist.php:689
ChangesListSpecialPage\setBottomText
setBottomText(FormOptions $opts)
Send the text to be displayed after the options.
Definition: ChangesListSpecialPage.php:1115
ChangesListSpecialPage\getOptions
getOptions()
Get the current FormOptions for this request.
Definition: ChangesListSpecialPage.php:553
$options
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist Do not use this to implement individual filters if they are compatible with the ChangesListFilter and ChangesListFilterGroup structure use sub classes of those in conjunction with the ChangesListSpecialPageStructuredFilters hook This hook can be used to implement filters that do not implement that or custom behavior that is not an individual filter e g Watchlist and Watchlist you will want to construct new ChangesListBooleanFilter or ChangesListStringOptionsFilter objects When constructing you specify which group they belong to You can reuse existing or create your you must register them with $special registerFilterGroup removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context $options
Definition: hooks.txt:1049
ChangesListSpecialPage\$customFilters
array $customFilters
Definition: ChangesListSpecialPage.php:41
array
the array() calling protocol came about after MediaWiki 1.4rc1.
Xml\submitButton
static submitButton( $value, $attribs=[])
Convenience function to build an HTML submit button When $wgUseMediaWikiUIEverywhere is true it will ...
Definition: Xml.php:459
Xml\checkLabel
static checkLabel( $label, $name, $id, $checked=false, $attribs=[])
Convenience function to build an HTML checkbox with a label.
Definition: Xml.php:419
TitleValue
Represents a page (or page fragment) title within MediaWiki.
Definition: TitleValue.php:36
$out
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output $out
Definition: hooks.txt:783