MediaWiki  master
Article.php
Go to the documentation of this file.
1 <?php
34 class Article implements Page {
36  protected $mContext;
37 
39  protected $mPage;
40 
43 
48  public $mContent;
49 
55 
57  public $mContentLoaded = false;
58 
60  public $mOldId;
61 
63  public $mRedirectedFrom = null;
64 
66  public $mRedirectUrl = false;
67 
69  public $mRevIdFetched = 0;
70 
72  public $mRevision = null;
73 
76 
82  public function __construct( Title $title, $oldId = null ) {
83  $this->mOldId = $oldId;
84  $this->mPage = $this->newPage( $title );
85  }
86 
91  protected function newPage( Title $title ) {
92  return new WikiPage( $title );
93  }
94 
100  public static function newFromID( $id ) {
101  $t = Title::newFromID( $id );
102  return $t == null ? null : new static( $t );
103  }
104 
112  public static function newFromTitle( $title, IContextSource $context ) {
113  if ( NS_MEDIA == $title->getNamespace() ) {
114  // FIXME: where should this go?
115  $title = Title::makeTitle( NS_FILE, $title->getDBkey() );
116  }
117 
118  $page = null;
119  Hooks::run( 'ArticleFromTitle', [ &$title, &$page, $context ] );
120  if ( !$page ) {
121  switch ( $title->getNamespace() ) {
122  case NS_FILE:
123  $page = new ImagePage( $title );
124  break;
125  case NS_CATEGORY:
126  $page = new CategoryPage( $title );
127  break;
128  default:
129  $page = new Article( $title );
130  }
131  }
132  $page->setContext( $context );
133 
134  return $page;
135  }
136 
144  public static function newFromWikiPage( WikiPage $page, IContextSource $context ) {
145  $article = self::newFromTitle( $page->getTitle(), $context );
146  $article->mPage = $page; // override to keep process cached vars
147  return $article;
148  }
149 
155  public function getRedirectedFrom() {
156  return $this->mRedirectedFrom;
157  }
158 
164  public function setRedirectedFrom( Title $from ) {
165  $this->mRedirectedFrom = $from;
166  }
167 
173  public function getTitle() {
174  return $this->mPage->getTitle();
175  }
176 
183  public function getPage() {
184  return $this->mPage;
185  }
186 
190  public function clear() {
191  $this->mContentLoaded = false;
192 
193  $this->mRedirectedFrom = null; # Title object if set
194  $this->mRevIdFetched = 0;
195  $this->mRedirectUrl = false;
196 
197  $this->mPage->clear();
198  }
199 
215  protected function getContentObject() {
216 
217  if ( $this->mPage->getId() === 0 ) {
218  # If this is a MediaWiki:x message, then load the messages
219  # and return the message value for x.
220  if ( $this->getTitle()->getNamespace() == NS_MEDIAWIKI ) {
221  $text = $this->getTitle()->getDefaultMessageText();
222  if ( $text === false ) {
223  $text = '';
224  }
225 
226  $content = ContentHandler::makeContent( $text, $this->getTitle() );
227  } else {
228  $message = $this->getContext()->getUser()->isLoggedIn() ? 'noarticletext' : 'noarticletextanon';
229  $content = new MessageContent( $message, null, 'parsemag' );
230  }
231  } else {
232  $this->fetchContentObject();
234  }
235 
236  return $content;
237  }
238 
242  public function getOldID() {
243  if ( is_null( $this->mOldId ) ) {
244  $this->mOldId = $this->getOldIDFromRequest();
245  }
246 
247  return $this->mOldId;
248  }
249 
255  public function getOldIDFromRequest() {
256  $this->mRedirectUrl = false;
257 
258  $request = $this->getContext()->getRequest();
259  $oldid = $request->getIntOrNull( 'oldid' );
260 
261  if ( $oldid === null ) {
262  return 0;
263  }
264 
265  if ( $oldid !== 0 ) {
266  # Load the given revision and check whether the page is another one.
267  # In that case, update this instance to reflect the change.
268  if ( $oldid === $this->mPage->getLatest() ) {
269  $this->mRevision = $this->mPage->getRevision();
270  } else {
271  $this->mRevision = Revision::newFromId( $oldid );
272  if ( $this->mRevision !== null ) {
273  // Revision title doesn't match the page title given?
274  if ( $this->mPage->getId() != $this->mRevision->getPage() ) {
275  $function = [ get_class( $this->mPage ), 'newFromID' ];
276  $this->mPage = call_user_func( $function, $this->mRevision->getPage() );
277  }
278  }
279  }
280  }
281 
282  if ( $request->getVal( 'direction' ) == 'next' ) {
283  $nextid = $this->getTitle()->getNextRevisionID( $oldid );
284  if ( $nextid ) {
285  $oldid = $nextid;
286  $this->mRevision = null;
287  } else {
288  $this->mRedirectUrl = $this->getTitle()->getFullURL( 'redirect=no' );
289  }
290  } elseif ( $request->getVal( 'direction' ) == 'prev' ) {
291  $previd = $this->getTitle()->getPreviousRevisionID( $oldid );
292  if ( $previd ) {
293  $oldid = $previd;
294  $this->mRevision = null;
295  }
296  }
297 
298  return $oldid;
299  }
300 
313  protected function fetchContentObject() {
314  if ( $this->mContentLoaded ) {
315  return $this->mContentObject;
316  }
317 
318  $this->mContentLoaded = true;
319  $this->mContent = null;
320 
321  $oldid = $this->getOldID();
322 
323  # Pre-fill content with error message so that if something
324  # fails we'll have something telling us what we intended.
325  // XXX: this isn't page content but a UI message. horrible.
326  $this->mContentObject = new MessageContent( 'missing-revision', [ $oldid ] );
327 
328  if ( $oldid ) {
329  # $this->mRevision might already be fetched by getOldIDFromRequest()
330  if ( !$this->mRevision ) {
331  $this->mRevision = Revision::newFromId( $oldid );
332  if ( !$this->mRevision ) {
333  wfDebug( __METHOD__ . " failed to retrieve specified revision, id $oldid\n" );
334  return false;
335  }
336  }
337  } else {
338  $oldid = $this->mPage->getLatest();
339  if ( !$oldid ) {
340  wfDebug( __METHOD__ . " failed to find page data for title " .
341  $this->getTitle()->getPrefixedText() . "\n" );
342  return false;
343  }
344 
345  # Update error message with correct oldid
346  $this->mContentObject = new MessageContent( 'missing-revision', [ $oldid ] );
347 
348  $this->mRevision = $this->mPage->getRevision();
349 
350  if ( !$this->mRevision ) {
351  wfDebug( __METHOD__ . " failed to retrieve current page, rev_id $oldid\n" );
352  return false;
353  }
354  }
355 
356  // @todo FIXME: Horrible, horrible! This content-loading interface just plain sucks.
357  // We should instead work with the Revision object when we need it...
358  // Loads if user is allowed
359  $content = $this->mRevision->getContent(
361  $this->getContext()->getUser()
362  );
363 
364  if ( !$content ) {
365  wfDebug( __METHOD__ . " failed to retrieve content of revision " .
366  $this->mRevision->getId() . "\n" );
367  return false;
368  }
369 
370  $this->mContentObject = $content;
371  $this->mRevIdFetched = $this->mRevision->getId();
372 
373  // Avoid PHP 7.1 warning of passing $this by reference
374  $articlePage = $this;
375 
376  Hooks::run(
377  'ArticleAfterFetchContentObject',
378  [ &$articlePage, &$this->mContentObject ]
379  );
380 
381  return $this->mContentObject;
382  }
383 
389  public function isCurrent() {
390  # If no oldid, this is the current version.
391  if ( $this->getOldID() == 0 ) {
392  return true;
393  }
394 
395  return $this->mPage->exists() && $this->mRevision && $this->mRevision->isCurrent();
396  }
397 
405  public function getRevisionFetched() {
406  $this->fetchContentObject();
407 
408  return $this->mRevision;
409  }
410 
416  public function getRevIdFetched() {
417  if ( $this->mRevIdFetched ) {
418  return $this->mRevIdFetched;
419  } else {
420  return $this->mPage->getLatest();
421  }
422  }
423 
428  public function view() {
429  global $wgUseFileCache, $wgDebugToolbar;
430 
431  # Get variables from query string
432  # As side effect this will load the revision and update the title
433  # in a revision ID is passed in the request, so this should remain
434  # the first call of this method even if $oldid is used way below.
435  $oldid = $this->getOldID();
436 
437  $user = $this->getContext()->getUser();
438  # Another whitelist check in case getOldID() is altering the title
439  $permErrors = $this->getTitle()->getUserPermissionsErrors( 'read', $user );
440  if ( count( $permErrors ) ) {
441  wfDebug( __METHOD__ . ": denied on secondary read check\n" );
442  throw new PermissionsError( 'read', $permErrors );
443  }
444 
445  $outputPage = $this->getContext()->getOutput();
446  # getOldID() may as well want us to redirect somewhere else
447  if ( $this->mRedirectUrl ) {
448  $outputPage->redirect( $this->mRedirectUrl );
449  wfDebug( __METHOD__ . ": redirecting due to oldid\n" );
450 
451  return;
452  }
453 
454  # If we got diff in the query, we want to see a diff page instead of the article.
455  if ( $this->getContext()->getRequest()->getCheck( 'diff' ) ) {
456  wfDebug( __METHOD__ . ": showing diff page\n" );
457  $this->showDiffPage();
458 
459  return;
460  }
461 
462  # Set page title (may be overridden by DISPLAYTITLE)
463  $outputPage->setPageTitle( $this->getTitle()->getPrefixedText() );
464 
465  $outputPage->setArticleFlag( true );
466  # Allow frames by default
467  $outputPage->allowClickjacking();
468 
469  $parserCache = ParserCache::singleton();
470 
471  $parserOptions = $this->getParserOptions();
472  # Render printable version, use printable version cache
473  if ( $outputPage->isPrintable() ) {
474  $parserOptions->setIsPrintable( true );
475  $parserOptions->setEditSection( false );
476  } elseif ( !$this->isCurrent() || !$this->getTitle()->quickUserCan( 'edit', $user ) ) {
477  $parserOptions->setEditSection( false );
478  }
479 
480  # Try client and file cache
481  if ( !$wgDebugToolbar && $oldid === 0 && $this->mPage->checkTouched() ) {
482  # Try to stream the output from file cache
483  if ( $wgUseFileCache && $this->tryFileCache() ) {
484  wfDebug( __METHOD__ . ": done file cache\n" );
485  # tell wgOut that output is taken care of
486  $outputPage->disable();
487  $this->mPage->doViewUpdates( $user, $oldid );
488 
489  return;
490  }
491  }
492 
493  # Should the parser cache be used?
494  $useParserCache = $this->mPage->shouldCheckParserCache( $parserOptions, $oldid );
495  wfDebug( 'Article::view using parser cache: ' . ( $useParserCache ? 'yes' : 'no' ) . "\n" );
496  if ( $user->getStubThreshold() ) {
497  $this->getContext()->getStats()->increment( 'pcache_miss_stub' );
498  }
499 
500  $this->showRedirectedFromHeader();
501  $this->showNamespaceHeader();
502 
503  # Iterate through the possible ways of constructing the output text.
504  # Keep going until $outputDone is set, or we run out of things to do.
505  $pass = 0;
506  $outputDone = false;
507  $this->mParserOutput = false;
508 
509  while ( !$outputDone && ++$pass ) {
510  switch ( $pass ) {
511  case 1:
512  // Avoid PHP 7.1 warning of passing $this by reference
513  $articlePage = $this;
514  Hooks::run( 'ArticleViewHeader', [ &$articlePage, &$outputDone, &$useParserCache ] );
515  break;
516  case 2:
517  # Early abort if the page doesn't exist
518  if ( !$this->mPage->exists() ) {
519  wfDebug( __METHOD__ . ": showing missing article\n" );
520  $this->showMissingArticle();
521  $this->mPage->doViewUpdates( $user );
522  return;
523  }
524 
525  # Try the parser cache
526  if ( $useParserCache ) {
527  $this->mParserOutput = $parserCache->get( $this->mPage, $parserOptions );
528 
529  if ( $this->mParserOutput !== false ) {
530  if ( $oldid ) {
531  wfDebug( __METHOD__ . ": showing parser cache contents for current rev permalink\n" );
532  $this->setOldSubtitle( $oldid );
533  } else {
534  wfDebug( __METHOD__ . ": showing parser cache contents\n" );
535  }
536  $outputPage->addParserOutput( $this->mParserOutput );
537  # Ensure that UI elements requiring revision ID have
538  # the correct version information.
539  $outputPage->setRevisionId( $this->mPage->getLatest() );
540  # Preload timestamp to avoid a DB hit
541  $cachedTimestamp = $this->mParserOutput->getTimestamp();
542  if ( $cachedTimestamp !== null ) {
543  $outputPage->setRevisionTimestamp( $cachedTimestamp );
544  $this->mPage->setTimestamp( $cachedTimestamp );
545  }
546  $outputDone = true;
547  }
548  }
549  break;
550  case 3:
551  # This will set $this->mRevision if needed
552  $this->fetchContentObject();
553 
554  # Are we looking at an old revision
555  if ( $oldid && $this->mRevision ) {
556  $this->setOldSubtitle( $oldid );
557 
558  if ( !$this->showDeletedRevisionHeader() ) {
559  wfDebug( __METHOD__ . ": cannot view deleted revision\n" );
560  return;
561  }
562  }
563 
564  # Ensure that UI elements requiring revision ID have
565  # the correct version information.
566  $outputPage->setRevisionId( $this->getRevIdFetched() );
567  # Preload timestamp to avoid a DB hit
568  $outputPage->setRevisionTimestamp( $this->mPage->getTimestamp() );
569 
570  if ( !Hooks::run( 'ArticleContentViewCustom',
571  [ $this->fetchContentObject(), $this->getTitle(), $outputPage ] ) ) {
572 
573  # Allow extensions do their own custom view for certain pages
574  $outputDone = true;
575  }
576  break;
577  case 4:
578  # Run the parse, protected by a pool counter
579  wfDebug( __METHOD__ . ": doing uncached parse\n" );
580 
581  $content = $this->getContentObject();
582  $poolArticleView = new PoolWorkArticleView( $this->getPage(), $parserOptions,
583  $this->getRevIdFetched(), $useParserCache, $content );
584 
585  if ( !$poolArticleView->execute() ) {
586  $error = $poolArticleView->getError();
587  if ( $error ) {
588  $outputPage->clearHTML(); // for release() errors
589  $outputPage->enableClientCache( false );
590  $outputPage->setRobotPolicy( 'noindex,nofollow' );
591 
592  $errortext = $error->getWikiText( false, 'view-pool-error' );
593  $outputPage->addWikiText( '<div class="errorbox">' . $errortext . '</div>' );
594  }
595  # Connection or timeout error
596  return;
597  }
598 
599  $this->mParserOutput = $poolArticleView->getParserOutput();
600  $outputPage->addParserOutput( $this->mParserOutput );
601  if ( $content->getRedirectTarget() ) {
602  $outputPage->addSubtitle( "<span id=\"redirectsub\">" .
603  $this->getContext()->msg( 'redirectpagesub' )->parse() . "</span>" );
604  }
605 
606  # Don't cache a dirty ParserOutput object
607  if ( $poolArticleView->getIsDirty() ) {
608  $outputPage->setCdnMaxage( 0 );
609  $outputPage->addHTML( "<!-- parser cache is expired, " .
610  "sending anyway due to pool overload-->\n" );
611  }
612 
613  $outputDone = true;
614  break;
615  # Should be unreachable, but just in case...
616  default:
617  break 2;
618  }
619  }
620 
621  # Get the ParserOutput actually *displayed* here.
622  # Note that $this->mParserOutput is the *current*/oldid version output.
623  $pOutput = ( $outputDone instanceof ParserOutput )
624  ? $outputDone // object fetched by hook
625  : $this->mParserOutput;
626 
627  # Adjust title for main page & pages with displaytitle
628  if ( $pOutput ) {
629  $this->adjustDisplayTitle( $pOutput );
630  }
631 
632  # For the main page, overwrite the <title> element with the con-
633  # tents of 'pagetitle-view-mainpage' instead of the default (if
634  # that's not empty).
635  # This message always exists because it is in the i18n files
636  if ( $this->getTitle()->isMainPage() ) {
637  $msg = wfMessage( 'pagetitle-view-mainpage' )->inContentLanguage();
638  if ( !$msg->isDisabled() ) {
639  $outputPage->setHTMLTitle( $msg->title( $this->getTitle() )->text() );
640  }
641  }
642 
643  # Use adaptive TTLs for CDN so delayed/failed purges are noticed less often.
644  # This could use getTouched(), but that could be scary for major template edits.
645  $outputPage->adaptCdnTTL( $this->mPage->getTimestamp(), IExpiringStore::TTL_DAY );
646 
647  # Check for any __NOINDEX__ tags on the page using $pOutput
648  $policy = $this->getRobotPolicy( 'view', $pOutput );
649  $outputPage->setIndexPolicy( $policy['index'] );
650  $outputPage->setFollowPolicy( $policy['follow'] );
651 
652  $this->showViewFooter();
653  $this->mPage->doViewUpdates( $user, $oldid );
654 
655  $outputPage->addModules( 'mediawiki.action.view.postEdit' );
656  }
657 
662  public function adjustDisplayTitle( ParserOutput $pOutput ) {
663  # Adjust the title if it was set by displaytitle, -{T|}- or language conversion
664  $titleText = $pOutput->getTitleText();
665  if ( strval( $titleText ) !== '' ) {
666  $this->getContext()->getOutput()->setPageTitle( $titleText );
667  }
668  }
669 
674  protected function showDiffPage() {
675  $request = $this->getContext()->getRequest();
676  $user = $this->getContext()->getUser();
677  $diff = $request->getVal( 'diff' );
678  $rcid = $request->getVal( 'rcid' );
679  $diffOnly = $request->getBool( 'diffonly', $user->getOption( 'diffonly' ) );
680  $purge = $request->getVal( 'action' ) == 'purge';
681  $unhide = $request->getInt( 'unhide' ) == 1;
682  $oldid = $this->getOldID();
683 
684  $rev = $this->getRevisionFetched();
685 
686  if ( !$rev ) {
687  $this->getContext()->getOutput()->setPageTitle( wfMessage( 'errorpagetitle' ) );
688  $msg = $this->getContext()->msg( 'difference-missing-revision' )
689  ->params( $oldid )
690  ->numParams( 1 )
691  ->parseAsBlock();
692  $this->getContext()->getOutput()->addHTML( $msg );
693  return;
694  }
695 
696  $contentHandler = $rev->getContentHandler();
697  $de = $contentHandler->createDifferenceEngine(
698  $this->getContext(),
699  $oldid,
700  $diff,
701  $rcid,
702  $purge,
703  $unhide
704  );
705 
706  // DifferenceEngine directly fetched the revision:
707  $this->mRevIdFetched = $de->mNewid;
708  $de->showDiffPage( $diffOnly );
709 
710  // Run view updates for the newer revision being diffed (and shown
711  // below the diff if not $diffOnly).
712  list( $old, $new ) = $de->mapDiffPrevNext( $oldid, $diff );
713  // New can be false, convert it to 0 - this conveniently means the latest revision
714  $this->mPage->doViewUpdates( $user, (int)$new );
715  }
716 
724  public function getRobotPolicy( $action, $pOutput = null ) {
725  global $wgArticleRobotPolicies, $wgNamespaceRobotPolicies, $wgDefaultRobotPolicy;
726 
727  $ns = $this->getTitle()->getNamespace();
728 
729  # Don't index user and user talk pages for blocked users (bug 11443)
730  if ( ( $ns == NS_USER || $ns == NS_USER_TALK ) && !$this->getTitle()->isSubpage() ) {
731  $specificTarget = null;
732  $vagueTarget = null;
733  $titleText = $this->getTitle()->getText();
734  if ( IP::isValid( $titleText ) ) {
735  $vagueTarget = $titleText;
736  } else {
737  $specificTarget = $titleText;
738  }
739  if ( Block::newFromTarget( $specificTarget, $vagueTarget ) instanceof Block ) {
740  return [
741  'index' => 'noindex',
742  'follow' => 'nofollow'
743  ];
744  }
745  }
746 
747  if ( $this->mPage->getId() === 0 || $this->getOldID() ) {
748  # Non-articles (special pages etc), and old revisions
749  return [
750  'index' => 'noindex',
751  'follow' => 'nofollow'
752  ];
753  } elseif ( $this->getContext()->getOutput()->isPrintable() ) {
754  # Discourage indexing of printable versions, but encourage following
755  return [
756  'index' => 'noindex',
757  'follow' => 'follow'
758  ];
759  } elseif ( $this->getContext()->getRequest()->getInt( 'curid' ) ) {
760  # For ?curid=x urls, disallow indexing
761  return [
762  'index' => 'noindex',
763  'follow' => 'follow'
764  ];
765  }
766 
767  # Otherwise, construct the policy based on the various config variables.
768  $policy = self::formatRobotPolicy( $wgDefaultRobotPolicy );
769 
770  if ( isset( $wgNamespaceRobotPolicies[$ns] ) ) {
771  # Honour customised robot policies for this namespace
772  $policy = array_merge(
773  $policy,
774  self::formatRobotPolicy( $wgNamespaceRobotPolicies[$ns] )
775  );
776  }
777  if ( $this->getTitle()->canUseNoindex() && is_object( $pOutput ) && $pOutput->getIndexPolicy() ) {
778  # __INDEX__ and __NOINDEX__ magic words, if allowed. Incorporates
779  # a final sanity check that we have really got the parser output.
780  $policy = array_merge(
781  $policy,
782  [ 'index' => $pOutput->getIndexPolicy() ]
783  );
784  }
785 
786  if ( isset( $wgArticleRobotPolicies[$this->getTitle()->getPrefixedText()] ) ) {
787  # (bug 14900) site config can override user-defined __INDEX__ or __NOINDEX__
788  $policy = array_merge(
789  $policy,
790  self::formatRobotPolicy( $wgArticleRobotPolicies[$this->getTitle()->getPrefixedText()] )
791  );
792  }
793 
794  return $policy;
795  }
796 
804  public static function formatRobotPolicy( $policy ) {
805  if ( is_array( $policy ) ) {
806  return $policy;
807  } elseif ( !$policy ) {
808  return [];
809  }
810 
811  $policy = explode( ',', $policy );
812  $policy = array_map( 'trim', $policy );
813 
814  $arr = [];
815  foreach ( $policy as $var ) {
816  if ( in_array( $var, [ 'index', 'noindex' ] ) ) {
817  $arr['index'] = $var;
818  } elseif ( in_array( $var, [ 'follow', 'nofollow' ] ) ) {
819  $arr['follow'] = $var;
820  }
821  }
822 
823  return $arr;
824  }
825 
833  public function showRedirectedFromHeader() {
835 
836  $context = $this->getContext();
837  $outputPage = $context->getOutput();
838  $request = $context->getRequest();
839  $rdfrom = $request->getVal( 'rdfrom' );
840 
841  // Construct a URL for the current page view, but with the target title
842  $query = $request->getValues();
843  unset( $query['rdfrom'] );
844  unset( $query['title'] );
845  if ( $this->getTitle()->isRedirect() ) {
846  // Prevent double redirects
847  $query['redirect'] = 'no';
848  }
849  $redirectTargetUrl = $this->getTitle()->getLinkURL( $query );
850 
851  if ( isset( $this->mRedirectedFrom ) ) {
852  // Avoid PHP 7.1 warning of passing $this by reference
853  $articlePage = $this;
854 
855  // This is an internally redirected page view.
856  // We'll need a backlink to the source page for navigation.
857  if ( Hooks::run( 'ArticleViewRedirect', [ &$articlePage ] ) ) {
858  $redir = Linker::linkKnown(
859  $this->mRedirectedFrom,
860  null,
861  [],
862  [ 'redirect' => 'no' ]
863  );
864 
865  $outputPage->addSubtitle( "<span class=\"mw-redirectedfrom\">" .
866  $context->msg( 'redirectedfrom' )->rawParams( $redir )->parse()
867  . "</span>" );
868 
869  // Add the script to update the displayed URL and
870  // set the fragment if one was specified in the redirect
871  $outputPage->addJsConfigVars( [
872  'wgInternalRedirectTargetUrl' => $redirectTargetUrl,
873  ] );
874  $outputPage->addModules( 'mediawiki.action.view.redirect' );
875 
876  // Add a <link rel="canonical"> tag
877  $outputPage->setCanonicalUrl( $this->getTitle()->getCanonicalURL() );
878 
879  // Tell the output object that the user arrived at this article through a redirect
880  $outputPage->setRedirectedFrom( $this->mRedirectedFrom );
881 
882  return true;
883  }
884  } elseif ( $rdfrom ) {
885  // This is an externally redirected view, from some other wiki.
886  // If it was reported from a trusted site, supply a backlink.
887  if ( $wgRedirectSources && preg_match( $wgRedirectSources, $rdfrom ) ) {
888  $redir = Linker::makeExternalLink( $rdfrom, $rdfrom );
889  $outputPage->addSubtitle( "<span class=\"mw-redirectedfrom\">" .
890  $context->msg( 'redirectedfrom' )->rawParams( $redir )->parse()
891  . "</span>" );
892 
893  // Add the script to update the displayed URL
894  $outputPage->addJsConfigVars( [
895  'wgInternalRedirectTargetUrl' => $redirectTargetUrl,
896  ] );
897  $outputPage->addModules( 'mediawiki.action.view.redirect' );
898 
899  return true;
900  }
901  }
902 
903  return false;
904  }
905 
910  public function showNamespaceHeader() {
911  if ( $this->getTitle()->isTalkPage() ) {
912  if ( !wfMessage( 'talkpageheader' )->isDisabled() ) {
913  $this->getContext()->getOutput()->wrapWikiMsg(
914  "<div class=\"mw-talkpageheader\">\n$1\n</div>",
915  [ 'talkpageheader' ]
916  );
917  }
918  }
919  }
920 
924  public function showViewFooter() {
925  # check if we're displaying a [[User talk:x.x.x.x]] anonymous talk page
926  if ( $this->getTitle()->getNamespace() == NS_USER_TALK
927  && IP::isValid( $this->getTitle()->getText() )
928  ) {
929  $this->getContext()->getOutput()->addWikiMsg( 'anontalkpagetext' );
930  }
931 
932  // Show a footer allowing the user to patrol the shown revision or page if possible
933  $patrolFooterShown = $this->showPatrolFooter();
934 
935  Hooks::run( 'ArticleViewFooter', [ $this, $patrolFooterShown ] );
936  }
937 
947  public function showPatrolFooter() {
948  global $wgUseNPPatrol, $wgUseRCPatrol, $wgUseFilePatrol, $wgEnableAPI, $wgEnableWriteAPI;
949 
950  $outputPage = $this->getContext()->getOutput();
951  $user = $this->getContext()->getUser();
952  $title = $this->getTitle();
953  $rc = false;
954 
955  if ( !$title->quickUserCan( 'patrol', $user )
956  || !( $wgUseRCPatrol || $wgUseNPPatrol
957  || ( $wgUseFilePatrol && $title->inNamespace( NS_FILE ) ) )
958  ) {
959  // Patrolling is disabled or the user isn't allowed to
960  return false;
961  }
962 
963  if ( $this->mRevision
964  && !RecentChange::isInRCLifespan( $this->mRevision->getTimestamp(), 21600 )
965  ) {
966  // The current revision is already older than what could be in the RC table
967  // 6h tolerance because the RC might not be cleaned out regularly
968  return false;
969  }
970 
971  // Check for cached results
972  $key = wfMemcKey( 'unpatrollable-page', $title->getArticleID() );
974  if ( $cache->get( $key ) ) {
975  return false;
976  }
977 
978  $dbr = wfGetDB( DB_REPLICA );
979  $oldestRevisionTimestamp = $dbr->selectField(
980  'revision',
981  'MIN( rev_timestamp )',
982  [ 'rev_page' => $title->getArticleID() ],
983  __METHOD__
984  );
985 
986  // New page patrol: Get the timestamp of the oldest revison which
987  // the revision table holds for the given page. Then we look
988  // whether it's within the RC lifespan and if it is, we try
989  // to get the recentchanges row belonging to that entry
990  // (with rc_new = 1).
991  $recentPageCreation = false;
992  if ( $oldestRevisionTimestamp
993  && RecentChange::isInRCLifespan( $oldestRevisionTimestamp, 21600 )
994  ) {
995  // 6h tolerance because the RC might not be cleaned out regularly
996  $recentPageCreation = true;
998  [
999  'rc_new' => 1,
1000  'rc_timestamp' => $oldestRevisionTimestamp,
1001  'rc_namespace' => $title->getNamespace(),
1002  'rc_cur_id' => $title->getArticleID()
1003  ],
1004  __METHOD__
1005  );
1006  if ( $rc ) {
1007  // Use generic patrol message for new pages
1008  $markPatrolledMsg = wfMessage( 'markaspatrolledtext' );
1009  }
1010  }
1011 
1012  // File patrol: Get the timestamp of the latest upload for this page,
1013  // check whether it is within the RC lifespan and if it is, we try
1014  // to get the recentchanges row belonging to that entry
1015  // (with rc_type = RC_LOG, rc_log_type = upload).
1016  $recentFileUpload = false;
1017  if ( ( !$rc || $rc->getAttribute( 'rc_patrolled' ) ) && $wgUseFilePatrol
1018  && $title->getNamespace() === NS_FILE ) {
1019  // Retrieve timestamp of most recent upload
1020  $newestUploadTimestamp = $dbr->selectField(
1021  'image',
1022  'MAX( img_timestamp )',
1023  [ 'img_name' => $title->getDBkey() ],
1024  __METHOD__
1025  );
1026  if ( $newestUploadTimestamp
1027  && RecentChange::isInRCLifespan( $newestUploadTimestamp, 21600 )
1028  ) {
1029  // 6h tolerance because the RC might not be cleaned out regularly
1030  $recentFileUpload = true;
1032  [
1033  'rc_type' => RC_LOG,
1034  'rc_log_type' => 'upload',
1035  'rc_timestamp' => $newestUploadTimestamp,
1036  'rc_namespace' => NS_FILE,
1037  'rc_cur_id' => $title->getArticleID()
1038  ],
1039  __METHOD__,
1040  [ 'USE INDEX' => 'rc_timestamp' ]
1041  );
1042  if ( $rc ) {
1043  // Use patrol message specific to files
1044  $markPatrolledMsg = wfMessage( 'markaspatrolledtext-file' );
1045  }
1046  }
1047  }
1048 
1049  if ( !$recentPageCreation && !$recentFileUpload ) {
1050  // Page creation and latest upload (for files) is too old to be in RC
1051 
1052  // We definitely can't patrol so cache the information
1053  // When a new file version is uploaded, the cache is cleared
1054  $cache->set( $key, '1' );
1055 
1056  return false;
1057  }
1058 
1059  if ( !$rc ) {
1060  // Don't cache: This can be hit if the page gets accessed very fast after
1061  // its creation / latest upload or in case we have high replica DB lag. In case
1062  // the revision is too old, we will already return above.
1063  return false;
1064  }
1065 
1066  if ( $rc->getAttribute( 'rc_patrolled' ) ) {
1067  // Patrolled RC entry around
1068 
1069  // Cache the information we gathered above in case we can't patrol
1070  // Don't cache in case we can patrol as this could change
1071  $cache->set( $key, '1' );
1072 
1073  return false;
1074  }
1075 
1076  if ( $rc->getPerformer()->equals( $user ) ) {
1077  // Don't show a patrol link for own creations/uploads. If the user could
1078  // patrol them, they already would be patrolled
1079  return false;
1080  }
1081 
1082  $outputPage->preventClickjacking();
1083  if ( $wgEnableAPI && $wgEnableWriteAPI && $user->isAllowed( 'writeapi' ) ) {
1084  $outputPage->addModules( 'mediawiki.page.patrol.ajax' );
1085  }
1086 
1088  $title,
1089  $markPatrolledMsg->escaped(),
1090  [],
1091  [
1092  'action' => 'markpatrolled',
1093  'rcid' => $rc->getAttribute( 'rc_id' ),
1094  ]
1095  );
1096 
1097  $outputPage->addHTML(
1098  "<div class='patrollink' data-mw='interface'>" .
1099  wfMessage( 'markaspatrolledlink' )->rawParams( $link )->escaped() .
1100  '</div>'
1101  );
1102 
1103  return true;
1104  }
1105 
1112  public static function purgePatrolFooterCache( $articleID ) {
1114  $cache->delete( wfMemcKey( 'unpatrollable-page', $articleID ) );
1115  }
1116 
1121  public function showMissingArticle() {
1123 
1124  $outputPage = $this->getContext()->getOutput();
1125  // Whether the page is a root user page of an existing user (but not a subpage)
1126  $validUserPage = false;
1127 
1128  $title = $this->getTitle();
1129 
1130  # Show info in user (talk) namespace. Does the user exist? Is he blocked?
1131  if ( $title->getNamespace() == NS_USER
1132  || $title->getNamespace() == NS_USER_TALK
1133  ) {
1134  $rootPart = explode( '/', $title->getText() )[0];
1135  $user = User::newFromName( $rootPart, false /* allow IP users*/ );
1136  $ip = User::isIP( $rootPart );
1137  $block = Block::newFromTarget( $user, $user );
1138 
1139  if ( !( $user && $user->isLoggedIn() ) && !$ip ) { # User does not exist
1140  $outputPage->wrapWikiMsg( "<div class=\"mw-userpage-userdoesnotexist error\">\n\$1\n</div>",
1141  [ 'userpage-userdoesnotexist-view', wfEscapeWikiText( $rootPart ) ] );
1142  } elseif ( !is_null( $block ) && $block->getType() != Block::TYPE_AUTO ) {
1143  # Show log extract if the user is currently blocked
1145  $outputPage,
1146  'block',
1147  MWNamespace::getCanonicalName( NS_USER ) . ':' . $block->getTarget(),
1148  '',
1149  [
1150  'lim' => 1,
1151  'showIfEmpty' => false,
1152  'msgKey' => [
1153  'blocked-notice-logextract',
1154  $user->getName() # Support GENDER in notice
1155  ]
1156  ]
1157  );
1158  $validUserPage = !$title->isSubpage();
1159  } else {
1160  $validUserPage = !$title->isSubpage();
1161  }
1162  }
1163 
1164  Hooks::run( 'ShowMissingArticle', [ $this ] );
1165 
1166  # Show delete and move logs if there were any such events.
1167  # The logging query can DOS the site when bots/crawlers cause 404 floods,
1168  # so be careful showing this. 404 pages must be cheap as they are hard to cache.
1170  $key = wfMemcKey( 'page-recent-delete', md5( $title->getPrefixedText() ) );
1171  $loggedIn = $this->getContext()->getUser()->isLoggedIn();
1172  if ( $loggedIn || $cache->get( $key ) ) {
1173  $logTypes = [ 'delete', 'move' ];
1174 
1175  $dbr = wfGetDB( DB_REPLICA );
1176 
1177  $conds = [ 'log_action != ' . $dbr->addQuotes( 'revision' ) ];
1178  // Give extensions a chance to hide their (unrelated) log entries
1179  Hooks::run( 'Article::MissingArticleConditions', [ &$conds, $logTypes ] );
1181  $outputPage,
1182  $logTypes,
1183  $title,
1184  '',
1185  [
1186  'lim' => 10,
1187  'conds' => $conds,
1188  'showIfEmpty' => false,
1189  'msgKey' => [ $loggedIn
1190  ? 'moveddeleted-notice'
1191  : 'moveddeleted-notice-recent'
1192  ]
1193  ]
1194  );
1195  }
1196 
1197  if ( !$this->mPage->hasViewableContent() && $wgSend404Code && !$validUserPage ) {
1198  // If there's no backing content, send a 404 Not Found
1199  // for better machine handling of broken links.
1200  $this->getContext()->getRequest()->response()->statusHeader( 404 );
1201  }
1202 
1203  // Also apply the robot policy for nonexisting pages (even if a 404 was used for sanity)
1204  $policy = $this->getRobotPolicy( 'view' );
1205  $outputPage->setIndexPolicy( $policy['index'] );
1206  $outputPage->setFollowPolicy( $policy['follow'] );
1207 
1208  $hookResult = Hooks::run( 'BeforeDisplayNoArticleText', [ $this ] );
1209 
1210  if ( !$hookResult ) {
1211  return;
1212  }
1213 
1214  # Show error message
1215  $oldid = $this->getOldID();
1216  if ( !$oldid && $title->getNamespace() === NS_MEDIAWIKI && $title->hasSourceText() ) {
1217  $outputPage->addParserOutput( $this->getContentObject()->getParserOutput( $title ) );
1218  } else {
1219  if ( $oldid ) {
1220  $text = wfMessage( 'missing-revision', $oldid )->plain();
1221  } elseif ( $title->quickUserCan( 'create', $this->getContext()->getUser() )
1222  && $title->quickUserCan( 'edit', $this->getContext()->getUser() )
1223  ) {
1224  $message = $this->getContext()->getUser()->isLoggedIn() ? 'noarticletext' : 'noarticletextanon';
1225  $text = wfMessage( $message )->plain();
1226  } else {
1227  $text = wfMessage( 'noarticletext-nopermission' )->plain();
1228  }
1229 
1230  $dir = $this->getContext()->getLanguage()->getDir();
1231  $lang = $this->getContext()->getLanguage()->getCode();
1232  $outputPage->addWikiText( Xml::openElement( 'div', [
1233  'class' => "noarticletext mw-content-$dir",
1234  'dir' => $dir,
1235  'lang' => $lang,
1236  ] ) . "\n$text\n</div>" );
1237  }
1238  }
1239 
1246  public function showDeletedRevisionHeader() {
1247  if ( !$this->mRevision->isDeleted( Revision::DELETED_TEXT ) ) {
1248  // Not deleted
1249  return true;
1250  }
1251 
1252  $outputPage = $this->getContext()->getOutput();
1253  $user = $this->getContext()->getUser();
1254  // If the user is not allowed to see it...
1255  if ( !$this->mRevision->userCan( Revision::DELETED_TEXT, $user ) ) {
1256  $outputPage->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n",
1257  'rev-deleted-text-permission' );
1258 
1259  return false;
1260  // If the user needs to confirm that they want to see it...
1261  } elseif ( $this->getContext()->getRequest()->getInt( 'unhide' ) != 1 ) {
1262  # Give explanation and add a link to view the revision...
1263  $oldid = intval( $this->getOldID() );
1264  $link = $this->getTitle()->getFullURL( "oldid={$oldid}&unhide=1" );
1265  $msg = $this->mRevision->isDeleted( Revision::DELETED_RESTRICTED ) ?
1266  'rev-suppressed-text-unhide' : 'rev-deleted-text-unhide';
1267  $outputPage->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n",
1268  [ $msg, $link ] );
1269 
1270  return false;
1271  // We are allowed to see...
1272  } else {
1273  $msg = $this->mRevision->isDeleted( Revision::DELETED_RESTRICTED ) ?
1274  'rev-suppressed-text-view' : 'rev-deleted-text-view';
1275  $outputPage->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n", $msg );
1276 
1277  return true;
1278  }
1279  }
1280 
1289  public function setOldSubtitle( $oldid = 0 ) {
1290  // Avoid PHP 7.1 warning of passing $this by reference
1291  $articlePage = $this;
1292 
1293  if ( !Hooks::run( 'DisplayOldSubtitle', [ &$articlePage, &$oldid ] ) ) {
1294  return;
1295  }
1296 
1297  $context = $this->getContext();
1298  $unhide = $context->getRequest()->getInt( 'unhide' ) == 1;
1299 
1300  # Cascade unhide param in links for easy deletion browsing
1301  $extraParams = [];
1302  if ( $unhide ) {
1303  $extraParams['unhide'] = 1;
1304  }
1305 
1306  if ( $this->mRevision && $this->mRevision->getId() === $oldid ) {
1307  $revision = $this->mRevision;
1308  } else {
1309  $revision = Revision::newFromId( $oldid );
1310  }
1311 
1312  $timestamp = $revision->getTimestamp();
1313 
1314  $current = ( $oldid == $this->mPage->getLatest() );
1315  $language = $context->getLanguage();
1316  $user = $context->getUser();
1317 
1318  $td = $language->userTimeAndDate( $timestamp, $user );
1319  $tddate = $language->userDate( $timestamp, $user );
1320  $tdtime = $language->userTime( $timestamp, $user );
1321 
1322  # Show user links if allowed to see them. If hidden, then show them only if requested...
1323  $userlinks = Linker::revUserTools( $revision, !$unhide );
1324 
1325  $infomsg = $current && !$context->msg( 'revision-info-current' )->isDisabled()
1326  ? 'revision-info-current'
1327  : 'revision-info';
1328 
1329  $outputPage = $context->getOutput();
1330  $revisionInfo = "<div id=\"mw-{$infomsg}\">" .
1331  $context->msg( $infomsg, $td )
1332  ->rawParams( $userlinks )
1333  ->params( $revision->getId(), $tddate, $tdtime, $revision->getUserText() )
1334  ->rawParams( Linker::revComment( $revision, true, true ) )
1335  ->parse() .
1336  "</div>";
1337 
1338  $lnk = $current
1339  ? $context->msg( 'currentrevisionlink' )->escaped()
1341  $this->getTitle(),
1342  $context->msg( 'currentrevisionlink' )->escaped(),
1343  [],
1344  $extraParams
1345  );
1346  $curdiff = $current
1347  ? $context->msg( 'diff' )->escaped()
1349  $this->getTitle(),
1350  $context->msg( 'diff' )->escaped(),
1351  [],
1352  [
1353  'diff' => 'cur',
1354  'oldid' => $oldid
1355  ] + $extraParams
1356  );
1357  $prev = $this->getTitle()->getPreviousRevisionID( $oldid );
1358  $prevlink = $prev
1360  $this->getTitle(),
1361  $context->msg( 'previousrevision' )->escaped(),
1362  [],
1363  [
1364  'direction' => 'prev',
1365  'oldid' => $oldid
1366  ] + $extraParams
1367  )
1368  : $context->msg( 'previousrevision' )->escaped();
1369  $prevdiff = $prev
1371  $this->getTitle(),
1372  $context->msg( 'diff' )->escaped(),
1373  [],
1374  [
1375  'diff' => 'prev',
1376  'oldid' => $oldid
1377  ] + $extraParams
1378  )
1379  : $context->msg( 'diff' )->escaped();
1380  $nextlink = $current
1381  ? $context->msg( 'nextrevision' )->escaped()
1383  $this->getTitle(),
1384  $context->msg( 'nextrevision' )->escaped(),
1385  [],
1386  [
1387  'direction' => 'next',
1388  'oldid' => $oldid
1389  ] + $extraParams
1390  );
1391  $nextdiff = $current
1392  ? $context->msg( 'diff' )->escaped()
1394  $this->getTitle(),
1395  $context->msg( 'diff' )->escaped(),
1396  [],
1397  [
1398  'diff' => 'next',
1399  'oldid' => $oldid
1400  ] + $extraParams
1401  );
1402 
1403  $cdel = Linker::getRevDeleteLink( $user, $revision, $this->getTitle() );
1404  if ( $cdel !== '' ) {
1405  $cdel .= ' ';
1406  }
1407 
1408  // the outer div is need for styling the revision info and nav in MobileFrontend
1409  $outputPage->addSubtitle( "<div class=\"mw-revision\">" . $revisionInfo .
1410  "<div id=\"mw-revision-nav\">" . $cdel .
1411  $context->msg( 'revision-nav' )->rawParams(
1412  $prevdiff, $prevlink, $lnk, $curdiff, $nextlink, $nextdiff
1413  )->escaped() . "</div></div>" );
1414  }
1415 
1427  public function viewRedirect( $target, $appendSubtitle = true, $forceKnown = false ) {
1428  $lang = $this->getTitle()->getPageLanguage();
1429  $out = $this->getContext()->getOutput();
1430  if ( $appendSubtitle ) {
1431  $out->addSubtitle( wfMessage( 'redirectpagesub' ) );
1432  }
1433  $out->addModuleStyles( 'mediawiki.action.view.redirectPage' );
1434  return static::getRedirectHeaderHtml( $lang, $target, $forceKnown );
1435  }
1436 
1449  public static function getRedirectHeaderHtml( Language $lang, $target, $forceKnown = false ) {
1450  if ( !is_array( $target ) ) {
1451  $target = [ $target ];
1452  }
1453 
1454  $html = '<ul class="redirectText">';
1456  foreach ( $target as $title ) {
1457  $html .= '<li>' . Linker::link(
1458  $title,
1459  htmlspecialchars( $title->getFullText() ),
1460  [],
1461  // Make sure wiki page redirects are not followed
1462  $title->isRedirect() ? [ 'redirect' => 'no' ] : [],
1463  ( $forceKnown ? [ 'known', 'noclasses' ] : [] )
1464  ) . '</li>';
1465  }
1466  $html .= '</ul>';
1467 
1468  $redirectToText = wfMessage( 'redirectto' )->inLanguage( $lang )->escaped();
1469 
1470  return '<div class="redirectMsg">' .
1471  '<p>' . $redirectToText . '</p>' .
1472  $html .
1473  '</div>';
1474  }
1475 
1484  public function addHelpLink( $to, $overrideBaseUrl = false ) {
1485  $msg = wfMessage(
1486  'namespace-' . $this->getTitle()->getNamespace() . '-helppage'
1487  );
1488 
1489  $out = $this->getContext()->getOutput();
1490  if ( !$msg->isDisabled() ) {
1491  $helpUrl = Skin::makeUrl( $msg->plain() );
1492  $out->addHelpLink( $helpUrl, true );
1493  } else {
1494  $out->addHelpLink( $to, $overrideBaseUrl );
1495  }
1496  }
1497 
1501  public function render() {
1502  $this->getContext()->getRequest()->response()->header( 'X-Robots-Tag: noindex' );
1503  $this->getContext()->getOutput()->setArticleBodyOnly( true );
1504  $this->getContext()->getOutput()->enableSectionEditLinks( false );
1505  $this->view();
1506  }
1507 
1511  public function protect() {
1512  $form = new ProtectionForm( $this );
1513  $form->execute();
1514  }
1515 
1519  public function unprotect() {
1520  $this->protect();
1521  }
1522 
1526  public function delete() {
1527  # This code desperately needs to be totally rewritten
1528 
1529  $title = $this->getTitle();
1530  $context = $this->getContext();
1531  $user = $context->getUser();
1532  $request = $context->getRequest();
1533 
1534  # Check permissions
1535  $permissionErrors = $title->getUserPermissionsErrors( 'delete', $user );
1536  if ( count( $permissionErrors ) ) {
1537  throw new PermissionsError( 'delete', $permissionErrors );
1538  }
1539 
1540  # Read-only check...
1541  if ( wfReadOnly() ) {
1542  throw new ReadOnlyError;
1543  }
1544 
1545  # Better double-check that it hasn't been deleted yet!
1546  $this->mPage->loadPageData(
1547  $request->wasPosted() ? WikiPage::READ_LATEST : WikiPage::READ_NORMAL
1548  );
1549  if ( !$this->mPage->exists() ) {
1550  $deleteLogPage = new LogPage( 'delete' );
1551  $outputPage = $context->getOutput();
1552  $outputPage->setPageTitle( $context->msg( 'cannotdelete-title', $title->getPrefixedText() ) );
1553  $outputPage->wrapWikiMsg( "<div class=\"error mw-error-cannotdelete\">\n$1\n</div>",
1554  [ 'cannotdelete', wfEscapeWikiText( $title->getPrefixedText() ) ]
1555  );
1556  $outputPage->addHTML(
1557  Xml::element( 'h2', null, $deleteLogPage->getName()->text() )
1558  );
1560  $outputPage,
1561  'delete',
1562  $title
1563  );
1564 
1565  return;
1566  }
1567 
1568  $deleteReasonList = $request->getText( 'wpDeleteReasonList', 'other' );
1569  $deleteReason = $request->getText( 'wpReason' );
1570 
1571  if ( $deleteReasonList == 'other' ) {
1572  $reason = $deleteReason;
1573  } elseif ( $deleteReason != '' ) {
1574  // Entry from drop down menu + additional comment
1575  $colonseparator = wfMessage( 'colon-separator' )->inContentLanguage()->text();
1576  $reason = $deleteReasonList . $colonseparator . $deleteReason;
1577  } else {
1578  $reason = $deleteReasonList;
1579  }
1580 
1581  if ( $request->wasPosted() && $user->matchEditToken( $request->getVal( 'wpEditToken' ),
1582  [ 'delete', $this->getTitle()->getPrefixedText() ] )
1583  ) {
1584  # Flag to hide all contents of the archived revisions
1585  $suppress = $request->getVal( 'wpSuppress' ) && $user->isAllowed( 'suppressrevision' );
1586 
1587  $this->doDelete( $reason, $suppress );
1588 
1589  WatchAction::doWatchOrUnwatch( $request->getCheck( 'wpWatch' ), $title, $user );
1590 
1591  return;
1592  }
1593 
1594  // Generate deletion reason
1595  $hasHistory = false;
1596  if ( !$reason ) {
1597  try {
1598  $reason = $this->generateReason( $hasHistory );
1599  } catch ( Exception $e ) {
1600  # if a page is horribly broken, we still want to be able to
1601  # delete it. So be lenient about errors here.
1602  wfDebug( "Error while building auto delete summary: $e" );
1603  $reason = '';
1604  }
1605  }
1606 
1607  // If the page has a history, insert a warning
1608  if ( $hasHistory ) {
1609  $title = $this->getTitle();
1610 
1611  // The following can use the real revision count as this is only being shown for users
1612  // that can delete this page.
1613  // This, as a side-effect, also makes sure that the following query isn't being run for
1614  // pages with a larger history, unless the user has the 'bigdelete' right
1615  // (and is about to delete this page).
1616  $dbr = wfGetDB( DB_REPLICA );
1617  $revisions = $edits = (int)$dbr->selectField(
1618  'revision',
1619  'COUNT(rev_page)',
1620  [ 'rev_page' => $title->getArticleID() ],
1621  __METHOD__
1622  );
1623 
1624  // @todo FIXME: i18n issue/patchwork message
1625  $context->getOutput()->addHTML(
1626  '<strong class="mw-delete-warning-revisions">' .
1627  $context->msg( 'historywarning' )->numParams( $revisions )->parse() .
1628  $context->msg( 'word-separator' )->escaped() . Linker::linkKnown( $title,
1629  $context->msg( 'history' )->escaped(),
1630  [],
1631  [ 'action' => 'history' ] ) .
1632  '</strong>'
1633  );
1634 
1635  if ( $title->isBigDeletion() ) {
1636  global $wgDeleteRevisionsLimit;
1637  $context->getOutput()->wrapWikiMsg( "<div class='error'>\n$1\n</div>\n",
1638  [
1639  'delete-warning-toobig',
1640  $context->getLanguage()->formatNum( $wgDeleteRevisionsLimit )
1641  ]
1642  );
1643  }
1644  }
1645 
1646  $this->confirmDelete( $reason );
1647  }
1648 
1654  public function confirmDelete( $reason ) {
1655  wfDebug( "Article::confirmDelete\n" );
1656 
1657  $title = $this->getTitle();
1658  $ctx = $this->getContext();
1659  $outputPage = $ctx->getOutput();
1660  $useMediaWikiUIEverywhere = $ctx->getConfig()->get( 'UseMediaWikiUIEverywhere' );
1661  $outputPage->setPageTitle( wfMessage( 'delete-confirm', $title->getPrefixedText() ) );
1662  $outputPage->addBacklinkSubtitle( $title );
1663  $outputPage->setRobotPolicy( 'noindex,nofollow' );
1664  $backlinkCache = $title->getBacklinkCache();
1665  if ( $backlinkCache->hasLinks( 'pagelinks' ) || $backlinkCache->hasLinks( 'templatelinks' ) ) {
1666  $outputPage->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n",
1667  'deleting-backlinks-warning' );
1668  }
1669  $outputPage->addWikiMsg( 'confirmdeletetext' );
1670 
1671  Hooks::run( 'ArticleConfirmDelete', [ $this, $outputPage, &$reason ] );
1672 
1673  $user = $this->getContext()->getUser();
1674  if ( $user->isAllowed( 'suppressrevision' ) ) {
1675  $suppress = Html::openElement( 'div', [ 'id' => 'wpDeleteSuppressRow' ] ) .
1676  Xml::checkLabel( wfMessage( 'revdelete-suppress' )->text(),
1677  'wpSuppress', 'wpSuppress', false, [ 'tabindex' => '4' ] ) .
1678  Html::closeElement( 'div' );
1679  } else {
1680  $suppress = '';
1681  }
1682  $checkWatch = $user->getBoolOption( 'watchdeletion' ) || $user->isWatched( $title );
1683  $form = Html::openElement( 'form', [ 'method' => 'post',
1684  'action' => $title->getLocalURL( 'action=delete' ), 'id' => 'deleteconfirm' ] ) .
1685  Html::openElement( 'fieldset', [ 'id' => 'mw-delete-table' ] ) .
1686  Html::element( 'legend', null, wfMessage( 'delete-legend' )->text() ) .
1687  Html::openElement( 'div', [ 'id' => 'mw-deleteconfirm-table' ] ) .
1688  Html::openElement( 'div', [ 'id' => 'wpDeleteReasonListRow' ] ) .
1689  Html::label( wfMessage( 'deletecomment' )->text(), 'wpDeleteReasonList' ) .
1690  '&nbsp;' .
1692  'wpDeleteReasonList',
1693  wfMessage( 'deletereason-dropdown' )->inContentLanguage()->text(),
1694  wfMessage( 'deletereasonotherlist' )->inContentLanguage()->text(),
1695  '',
1696  'wpReasonDropDown',
1697  1
1698  ) .
1699  Html::closeElement( 'div' ) .
1700  Html::openElement( 'div', [ 'id' => 'wpDeleteReasonRow' ] ) .
1701  Html::label( wfMessage( 'deleteotherreason' )->text(), 'wpReason' ) .
1702  '&nbsp;' .
1703  Html::input( 'wpReason', $reason, 'text', [
1704  'size' => '60',
1705  'maxlength' => '255',
1706  'tabindex' => '2',
1707  'id' => 'wpReason',
1708  'class' => 'mw-ui-input-inline',
1709  'autofocus'
1710  ] ) .
1711  Html::closeElement( 'div' );
1712 
1713  # Disallow watching if user is not logged in
1714  if ( $user->isLoggedIn() ) {
1715  $form .=
1716  Xml::checkLabel( wfMessage( 'watchthis' )->text(),
1717  'wpWatch', 'wpWatch', $checkWatch, [ 'tabindex' => '3' ] );
1718  }
1719 
1720  $form .=
1721  Html::openElement( 'div' ) .
1722  $suppress .
1723  Xml::submitButton( wfMessage( 'deletepage' )->text(),
1724  [
1725  'name' => 'wpConfirmB',
1726  'id' => 'wpConfirmB',
1727  'tabindex' => '5',
1728  'class' => $useMediaWikiUIEverywhere ? 'mw-ui-button mw-ui-destructive' : '',
1729  ]
1730  ) .
1731  Html::closeElement( 'div' ) .
1732  Html::closeElement( 'div' ) .
1733  Xml::closeElement( 'fieldset' ) .
1734  Html::hidden(
1735  'wpEditToken',
1736  $user->getEditToken( [ 'delete', $title->getPrefixedText() ] )
1737  ) .
1738  Xml::closeElement( 'form' );
1739 
1740  if ( $user->isAllowed( 'editinterface' ) ) {
1742  $ctx->msg( 'deletereason-dropdown' )->inContentLanguage()->getTitle(),
1743  wfMessage( 'delete-edit-reasonlist' )->escaped(),
1744  [],
1745  [ 'action' => 'edit' ]
1746  );
1747  $form .= '<p class="mw-delete-editreasons">' . $link . '</p>';
1748  }
1749 
1750  $outputPage->addHTML( $form );
1751 
1752  $deleteLogPage = new LogPage( 'delete' );
1753  $outputPage->addHTML( Xml::element( 'h2', null, $deleteLogPage->getName()->text() ) );
1754  LogEventsList::showLogExtract( $outputPage, 'delete', $title );
1755  }
1756 
1762  public function doDelete( $reason, $suppress = false ) {
1763  $error = '';
1764  $context = $this->getContext();
1765  $outputPage = $context->getOutput();
1766  $user = $context->getUser();
1767  $status = $this->mPage->doDeleteArticleReal( $reason, $suppress, 0, true, $error, $user );
1768 
1769  if ( $status->isGood() ) {
1770  $deleted = $this->getTitle()->getPrefixedText();
1771 
1772  $outputPage->setPageTitle( wfMessage( 'actioncomplete' ) );
1773  $outputPage->setRobotPolicy( 'noindex,nofollow' );
1774 
1775  $loglink = '[[Special:Log/delete|' . wfMessage( 'deletionlog' )->text() . ']]';
1776 
1777  $outputPage->addWikiMsg( 'deletedtext', wfEscapeWikiText( $deleted ), $loglink );
1778 
1779  Hooks::run( 'ArticleDeleteAfterSuccess', [ $this->getTitle(), $outputPage ] );
1780 
1781  $outputPage->returnToMain( false );
1782  } else {
1783  $outputPage->setPageTitle(
1784  wfMessage( 'cannotdelete-title',
1785  $this->getTitle()->getPrefixedText() )
1786  );
1787 
1788  if ( $error == '' ) {
1789  $outputPage->addWikiText(
1790  "<div class=\"error mw-error-cannotdelete\">\n" . $status->getWikiText() . "\n</div>"
1791  );
1792  $deleteLogPage = new LogPage( 'delete' );
1793  $outputPage->addHTML( Xml::element( 'h2', null, $deleteLogPage->getName()->text() ) );
1794 
1796  $outputPage,
1797  'delete',
1798  $this->getTitle()
1799  );
1800  } else {
1801  $outputPage->addHTML( $error );
1802  }
1803  }
1804  }
1805 
1806  /* Caching functions */
1807 
1815  protected function tryFileCache() {
1816  static $called = false;
1817 
1818  if ( $called ) {
1819  wfDebug( "Article::tryFileCache(): called twice!?\n" );
1820  return false;
1821  }
1822 
1823  $called = true;
1824  if ( $this->isFileCacheable() ) {
1825  $cache = new HTMLFileCache( $this->getTitle(), 'view' );
1826  if ( $cache->isCacheGood( $this->mPage->getTouched() ) ) {
1827  wfDebug( "Article::tryFileCache(): about to load file\n" );
1828  $cache->loadFromFileCache( $this->getContext() );
1829  return true;
1830  } else {
1831  wfDebug( "Article::tryFileCache(): starting buffer\n" );
1832  ob_start( [ &$cache, 'saveToFileCache' ] );
1833  }
1834  } else {
1835  wfDebug( "Article::tryFileCache(): not cacheable\n" );
1836  }
1837 
1838  return false;
1839  }
1840 
1846  public function isFileCacheable( $mode = HTMLFileCache::MODE_NORMAL ) {
1847  $cacheable = false;
1848 
1849  if ( HTMLFileCache::useFileCache( $this->getContext(), $mode ) ) {
1850  $cacheable = $this->mPage->getId()
1851  && !$this->mRedirectedFrom && !$this->getTitle()->isRedirect();
1852  // Extension may have reason to disable file caching on some pages.
1853  if ( $cacheable ) {
1854  // Avoid PHP 7.1 warning of passing $this by reference
1855  $articlePage = $this;
1856  $cacheable = Hooks::run( 'IsFileCacheable', [ &$articlePage ] );
1857  }
1858  }
1859 
1860  return $cacheable;
1861  }
1862 
1876  public function getParserOutput( $oldid = null, User $user = null ) {
1877  // XXX: bypasses mParserOptions and thus setParserOptions()
1878 
1879  if ( $user === null ) {
1880  $parserOptions = $this->getParserOptions();
1881  } else {
1882  $parserOptions = $this->mPage->makeParserOptions( $user );
1883  }
1884 
1885  return $this->mPage->getParserOutput( $parserOptions, $oldid );
1886  }
1887 
1895  if ( $this->mParserOptions ) {
1896  throw new MWException( "can't change parser options after they have already been set" );
1897  }
1898 
1899  // clone, so if $options is modified later, it doesn't confuse the parser cache.
1900  $this->mParserOptions = clone $options;
1901  }
1902 
1907  public function getParserOptions() {
1908  if ( !$this->mParserOptions ) {
1909  $this->mParserOptions = $this->mPage->makeParserOptions( $this->getContext() );
1910  }
1911  // Clone to allow modifications of the return value without affecting cache
1912  return clone $this->mParserOptions;
1913  }
1914 
1921  public function setContext( $context ) {
1922  $this->mContext = $context;
1923  }
1924 
1931  public function getContext() {
1932  if ( $this->mContext instanceof IContextSource ) {
1933  return $this->mContext;
1934  } else {
1935  wfDebug( __METHOD__ . " called and \$mContext is null. " .
1936  "Return RequestContext::getMain(); for sanity\n" );
1937  return RequestContext::getMain();
1938  }
1939  }
1940 
1948  public function __get( $fname ) {
1949  if ( property_exists( $this->mPage, $fname ) ) {
1950  # wfWarn( "Access to raw $fname field " . __CLASS__ );
1951  return $this->mPage->$fname;
1952  }
1953  trigger_error( 'Inaccessible property via __get(): ' . $fname, E_USER_NOTICE );
1954  }
1955 
1963  public function __set( $fname, $fvalue ) {
1964  if ( property_exists( $this->mPage, $fname ) ) {
1965  # wfWarn( "Access to raw $fname field of " . __CLASS__ );
1966  $this->mPage->$fname = $fvalue;
1967  // Note: extensions may want to toss on new fields
1968  } elseif ( !in_array( $fname, [ 'mContext', 'mPage' ] ) ) {
1969  $this->mPage->$fname = $fvalue;
1970  } else {
1971  trigger_error( 'Inaccessible property via __set(): ' . $fname, E_USER_NOTICE );
1972  }
1973  }
1974 
1979  public function checkFlags( $flags ) {
1980  return $this->mPage->checkFlags( $flags );
1981  }
1982 
1987  public function checkTouched() {
1988  return $this->mPage->checkTouched();
1989  }
1990 
1995  public function clearPreparedEdit() {
1996  $this->mPage->clearPreparedEdit();
1997  }
1998 
2003  public function doDeleteArticleReal(
2004  $reason, $suppress = false, $u1 = null, $u2 = null, &$error = '', User $user = null,
2005  $tags = []
2006  ) {
2007  return $this->mPage->doDeleteArticleReal(
2008  $reason, $suppress, $u1, $u2, $error, $user, $tags
2009  );
2010  }
2011 
2016  public function doDeleteUpdates( $id, Content $content = null ) {
2017  return $this->mPage->doDeleteUpdates( $id, $content );
2018  }
2019 
2025  public function doEditContent( Content $content, $summary, $flags = 0, $baseRevId = false,
2026  User $user = null, $serialFormat = null
2027  ) {
2028  wfDeprecated( __METHOD__, '1.29' );
2029  return $this->mPage->doEditContent( $content, $summary, $flags, $baseRevId,
2030  $user, $serialFormat
2031  );
2032  }
2033 
2038  public function doEditUpdates( Revision $revision, User $user, array $options = [] ) {
2039  return $this->mPage->doEditUpdates( $revision, $user, $options );
2040  }
2041 
2046  public function doPurge( $flags = WikiPage::PURGE_ALL ) {
2047  return $this->mPage->doPurge( $flags );
2048  }
2049 
2054  public function getLastPurgeTimestamp() {
2055  return $this->mPage->getLastPurgeTimestamp();
2056  }
2057 
2062  public function doViewUpdates( User $user, $oldid = 0 ) {
2063  $this->mPage->doViewUpdates( $user, $oldid );
2064  }
2065 
2070  public function exists() {
2071  return $this->mPage->exists();
2072  }
2073 
2078  public function followRedirect() {
2079  return $this->mPage->followRedirect();
2080  }
2081 
2086  public function getActionOverrides() {
2087  return $this->mPage->getActionOverrides();
2088  }
2089 
2094  public function getAutoDeleteReason( &$hasHistory ) {
2095  return $this->mPage->getAutoDeleteReason( $hasHistory );
2096  }
2097 
2102  public function getCategories() {
2103  return $this->mPage->getCategories();
2104  }
2105 
2110  public function getComment( $audience = Revision::FOR_PUBLIC, User $user = null ) {
2111  return $this->mPage->getComment( $audience, $user );
2112  }
2113 
2118  public function getContentHandler() {
2119  return $this->mPage->getContentHandler();
2120  }
2121 
2126  public function getContentModel() {
2127  return $this->mPage->getContentModel();
2128  }
2129 
2134  public function getContributors() {
2135  return $this->mPage->getContributors();
2136  }
2137 
2142  public function getCreator( $audience = Revision::FOR_PUBLIC, User $user = null ) {
2143  return $this->mPage->getCreator( $audience, $user );
2144  }
2145 
2150  public function getDeletionUpdates( Content $content = null ) {
2151  return $this->mPage->getDeletionUpdates( $content );
2152  }
2153 
2158  public function getHiddenCategories() {
2159  return $this->mPage->getHiddenCategories();
2160  }
2161 
2166  public function getId() {
2167  return $this->mPage->getId();
2168  }
2169 
2174  public function getLatest() {
2175  return $this->mPage->getLatest();
2176  }
2177 
2182  public function getLinksTimestamp() {
2183  return $this->mPage->getLinksTimestamp();
2184  }
2185 
2190  public function getMinorEdit() {
2191  return $this->mPage->getMinorEdit();
2192  }
2193 
2198  public function getOldestRevision() {
2199  return $this->mPage->getOldestRevision();
2200  }
2201 
2206  public function getRedirectTarget() {
2207  return $this->mPage->getRedirectTarget();
2208  }
2209 
2214  public function getRedirectURL( $rt ) {
2215  return $this->mPage->getRedirectURL( $rt );
2216  }
2217 
2222  public function getRevision() {
2223  return $this->mPage->getRevision();
2224  }
2225 
2230  public function getTimestamp() {
2231  return $this->mPage->getTimestamp();
2232  }
2233 
2238  public function getTouched() {
2239  return $this->mPage->getTouched();
2240  }
2241 
2246  public function getUndoContent( Revision $undo, Revision $undoafter = null ) {
2247  return $this->mPage->getUndoContent( $undo, $undoafter );
2248  }
2249 
2254  public function getUser( $audience = Revision::FOR_PUBLIC, User $user = null ) {
2255  return $this->mPage->getUser( $audience, $user );
2256  }
2257 
2262  public function getUserText( $audience = Revision::FOR_PUBLIC, User $user = null ) {
2263  return $this->mPage->getUserText( $audience, $user );
2264  }
2265 
2270  public function hasViewableContent() {
2271  return $this->mPage->hasViewableContent();
2272  }
2273 
2278  public function insertOn( $dbw, $pageId = null ) {
2279  return $this->mPage->insertOn( $dbw, $pageId );
2280  }
2281 
2286  public function insertProtectNullRevision( $revCommentMsg, array $limit,
2287  array $expiry, $cascade, $reason, $user = null
2288  ) {
2289  return $this->mPage->insertProtectNullRevision( $revCommentMsg, $limit,
2290  $expiry, $cascade, $reason, $user
2291  );
2292  }
2293 
2298  public function insertRedirect() {
2299  return $this->mPage->insertRedirect();
2300  }
2301 
2306  public function insertRedirectEntry( Title $rt, $oldLatest = null ) {
2307  return $this->mPage->insertRedirectEntry( $rt, $oldLatest );
2308  }
2309 
2314  public function isCountable( $editInfo = false ) {
2315  return $this->mPage->isCountable( $editInfo );
2316  }
2317 
2322  public function isRedirect() {
2323  return $this->mPage->isRedirect();
2324  }
2325 
2330  public function loadFromRow( $data, $from ) {
2331  return $this->mPage->loadFromRow( $data, $from );
2332  }
2333 
2338  public function loadPageData( $from = 'fromdb' ) {
2339  $this->mPage->loadPageData( $from );
2340  }
2341 
2346  public function lockAndGetLatest() {
2347  return $this->mPage->lockAndGetLatest();
2348  }
2349 
2354  public function makeParserOptions( $context ) {
2355  return $this->mPage->makeParserOptions( $context );
2356  }
2357 
2362  public function pageDataFromId( $dbr, $id, $options = [] ) {
2363  return $this->mPage->pageDataFromId( $dbr, $id, $options );
2364  }
2365 
2370  public function pageDataFromTitle( $dbr, $title, $options = [] ) {
2371  return $this->mPage->pageDataFromTitle( $dbr, $title, $options );
2372  }
2373 
2378  public function prepareContentForEdit(
2379  Content $content, $revision = null, User $user = null,
2380  $serialFormat = null, $useCache = true
2381  ) {
2382  return $this->mPage->prepareContentForEdit(
2383  $content, $revision, $user,
2384  $serialFormat, $useCache
2385  );
2386  }
2387 
2392  public function protectDescription( array $limit, array $expiry ) {
2393  return $this->mPage->protectDescription( $limit, $expiry );
2394  }
2395 
2400  public function protectDescriptionLog( array $limit, array $expiry ) {
2401  return $this->mPage->protectDescriptionLog( $limit, $expiry );
2402  }
2403 
2408  public function replaceSectionAtRev( $sectionId, Content $sectionContent,
2409  $sectionTitle = '', $baseRevId = null
2410  ) {
2411  return $this->mPage->replaceSectionAtRev( $sectionId, $sectionContent,
2412  $sectionTitle, $baseRevId
2413  );
2414  }
2415 
2420  public function replaceSectionContent(
2421  $sectionId, Content $sectionContent, $sectionTitle = '', $edittime = null
2422  ) {
2423  return $this->mPage->replaceSectionContent(
2424  $sectionId, $sectionContent, $sectionTitle, $edittime
2425  );
2426  }
2427 
2432  public function setTimestamp( $ts ) {
2433  return $this->mPage->setTimestamp( $ts );
2434  }
2435 
2440  public function shouldCheckParserCache( ParserOptions $parserOptions, $oldId ) {
2441  return $this->mPage->shouldCheckParserCache( $parserOptions, $oldId );
2442  }
2443 
2448  public function supportsSections() {
2449  return $this->mPage->supportsSections();
2450  }
2451 
2457  return $this->mPage->triggerOpportunisticLinksUpdate( $parserOutput );
2458  }
2459 
2464  public function updateCategoryCounts( array $added, array $deleted, $id = 0 ) {
2465  return $this->mPage->updateCategoryCounts( $added, $deleted, $id );
2466  }
2467 
2472  public function updateIfNewerOn( $dbw, $revision ) {
2473  return $this->mPage->updateIfNewerOn( $dbw, $revision );
2474  }
2475 
2480  public function updateRedirectOn( $dbw, $redirectTitle, $lastRevIsRedirect = null ) {
2481  return $this->mPage->updateRedirectOn( $dbw, $redirectTitle, $lastRevIsRedirect = null );
2482  }
2483 
2488  public function updateRevisionOn( $dbw, $revision, $lastRevision = null,
2489  $lastRevIsRedirect = null
2490  ) {
2491  return $this->mPage->updateRevisionOn( $dbw, $revision, $lastRevision,
2492  $lastRevIsRedirect
2493  );
2494  }
2495 
2504  public function doUpdateRestrictions( array $limit, array $expiry, &$cascade,
2505  $reason, User $user
2506  ) {
2507  return $this->mPage->doUpdateRestrictions( $limit, $expiry, $cascade, $reason, $user );
2508  }
2509 
2517  public function updateRestrictions( $limit = [], $reason = '',
2518  &$cascade = 0, $expiry = []
2519  ) {
2520  return $this->mPage->doUpdateRestrictions(
2521  $limit,
2522  $expiry,
2523  $cascade,
2524  $reason,
2525  $this->getContext()->getUser()
2526  );
2527  }
2528 
2537  public function doDeleteArticle(
2538  $reason, $suppress = false, $u1 = null, $u2 = null, &$error = ''
2539  ) {
2540  return $this->mPage->doDeleteArticle( $reason, $suppress, $u1, $u2, $error );
2541  }
2542 
2552  public function doRollback( $fromP, $summary, $token, $bot, &$resultDetails, User $user = null ) {
2553  $user = is_null( $user ) ? $this->getContext()->getUser() : $user;
2554  return $this->mPage->doRollback( $fromP, $summary, $token, $bot, $resultDetails, $user );
2555  }
2556 
2565  public function commitRollback( $fromP, $summary, $bot, &$resultDetails, User $guser = null ) {
2566  $guser = is_null( $guser ) ? $this->getContext()->getUser() : $guser;
2567  return $this->mPage->commitRollback( $fromP, $summary, $bot, $resultDetails, $guser );
2568  }
2569 
2574  public function generateReason( &$hasHistory ) {
2575  $title = $this->mPage->getTitle();
2577  return $handler->getAutoDeleteReason( $title, $hasHistory );
2578  }
2579 
2585  public static function selectFields() {
2586  wfDeprecated( __METHOD__, '1.24' );
2587  return WikiPage::selectFields();
2588  }
2589 
2595  public static function onArticleCreate( $title ) {
2596  wfDeprecated( __METHOD__, '1.24' );
2598  }
2599 
2605  public static function onArticleDelete( $title ) {
2606  wfDeprecated( __METHOD__, '1.24' );
2608  }
2609 
2615  public static function onArticleEdit( $title ) {
2616  wfDeprecated( __METHOD__, '1.24' );
2618  }
2619 
2620  // ******
2621 }
pageDataFromId($dbr, $id, $options=[])
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2362
__set($fname, $fvalue)
Use PHP's magic __set handler to handle setting of raw WikiPage fields for backwards compatibility...
Definition: Article.php:1963
static newFromName($name, $validate= 'valid')
Static factory method for creation from username.
Definition: User.php:544
getRedirectTarget()
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2206
static purgePatrolFooterCache($articleID)
Purge the cache used to check if it is worth showing the patrol footer For example, it is done during re-uploads when file patrol is used.
Definition: Article.php:1112
const FOR_THIS_USER
Definition: Revision.php:94
viewRedirect($target, $appendSubtitle=true, $forceKnown=false)
Return the HTML for the top of a redirect page.
Definition: Article.php:1427
static newFromID($id, $flags=0)
Create a new Title from an article ID.
Definition: Title.php:402
static closeElement($element)
Returns "".
Definition: Html.php:305
const PURGE_ALL
Definition: WikiPage.php:89
lockAndGetLatest()
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2346
static onArticleCreate(Title $title)
The onArticle*() functions are supposed to be a kind of hooks which should be called whenever any of ...
Definition: WikiPage.php:3275
static onArticleCreate($title)
Definition: Article.php:2595
getUndoContent(Revision $undo, Revision $undoafter=null)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2246
static getMainWANInstance()
Get the main WAN cache object.
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses & $html
Definition: hooks.txt:1923
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
Interface for objects which can provide a MediaWiki context on request.
static isInRCLifespan($timestamp, $tolerance=0)
Check whether the given timestamp is new enough to have a RC row with a given tolerance as the recent...
static revComment(Revision $rev, $local=false, $isPublic=false)
Wrap and format the given revision's comment block, if the current user is allowed to view it...
Definition: Linker.php:1464
WikiPage $mPage
The WikiPage object of this instance.
Definition: Article.php:39
wfGetDB($db, $groups=[], $wiki=false)
Get a Database object.
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:781
getRobotPolicy($action, $pOutput=null)
Get the robot policy to be used for the current view.
Definition: Article.php:724
the array() calling protocol came about after MediaWiki 1.4rc1.
getRedirectedFrom()
Get the page this view was redirected from.
Definition: Article.php:155
null for the local wiki Added should default to null in handler for backwards compatibility add a value to it if you want to add a cookie that have to vary cache options can modify $query
Definition: hooks.txt:1539
updateRestrictions($limit=[], $reason= '', &$cascade=0, $expiry=[])
Definition: Article.php:2517
doEditContent(Content $content, $summary, $flags=0, $baseRevId=false, User $user=null, $serialFormat=null)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2025
getLatest()
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2174
setParserOptions(ParserOptions $options)
Override the ParserOptions used to render the primary article wikitext.
Definition: Article.php:1894
magic word the default is to use $key to get the and $key value or $key value text $key value html to format the value $key
Definition: hooks.txt:2482
doEditUpdates(Revision $revision, User $user, array $options=[])
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2038
$context
Definition: load.php:50
static getRevDeleteLink(User $user, Revision $rev, Title $title)
Get a revision-deletion link, or disabled link, or nothing, depending on user permissions & the setti...
Definition: Linker.php:2015
static element($element, $attribs=null, $contents= '', $allowShortTag=true)
Format an XML element with given attributes and, optionally, text content.
Definition: Xml.php:39
exists()
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2070
supportsSections()
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2448
static makeUrl($name, $urlaction= '')
Definition: Skin.php:1105
doRollback($fromP, $summary, $token, $bot, &$resultDetails, User $user=null)
Definition: Article.php:2552
Show an error when the wiki is locked/read-only and the user tries to do something that requires writ...
doDeleteArticle($reason, $suppress=false, $u1=null, $u2=null, &$error= '')
Definition: Article.php:2537
protect()
action=protect handler
Definition: Article.php:1511
div flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException'returning false will NOT prevent logging $e
Definition: hooks.txt:2089
IContextSource $mContext
The context this Article is executed in.
Definition: Article.php:36
Set options of the Parser.
isCountable($editInfo=false)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2314
Wrapper allowing us to handle a system message as a Content object.
getPage()
Get the WikiPage object of this instance.
Definition: Article.php:183
getParserOutput($oldid=null, User $user=null)
#@-
Definition: Article.php:1876
static useFileCache(IContextSource $context, $mode=self::MODE_NORMAL)
Check if pages can be cached for this request/user.
updateCategoryCounts(array $added, array $deleted, $id=0)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2464
string bool $mRedirectUrl
URL to redirect to or false if none.
Definition: Article.php:66
loadPageData($from= 'fromdb')
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2338
if(!isset($args[0])) $lang
ParserOptions $mParserOptions
ParserOptions object for $wgUser articles.
Definition: Article.php:42
Content $mContentObject
Content of the revision we are working on.
Definition: Article.php:54
Special handling for category description pages, showing pages, subcategories and file that belong to...
isFileCacheable($mode=HTMLFileCache::MODE_NORMAL)
Check if the page can be cached.
Definition: Article.php:1846
doDeleteUpdates($id, Content $content=null)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2016
static newFromConds($conds, $fname=__METHOD__, $dbType=DB_REPLICA)
Find the first recent change matching some specific conditions.
adjustDisplayTitle(ParserOutput $pOutput)
Adjust title for pages with displaytitle, -{T|}- or language conversion.
Definition: Article.php:662
static hidden($name, $value, array $attribs=[])
Convenience function to produce an input element with type=hidden.
Definition: Html.php:742
shouldCheckParserCache(ParserOptions $parserOptions, $oldId)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2440
doUpdateRestrictions(array $limit, array $expiry, &$cascade, $reason, User $user)
Definition: Article.php:2504
Class for viewing MediaWiki article and history.
Definition: Article.php:34
null for the local wiki Added in
Definition: hooks.txt:1539
Using a hook running we can avoid having all this option specific stuff in our mainline code Using the function array $article
Definition: hooks.txt:78
Page view caching in the file system.
followRedirect()
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2078
confirmDelete($reason)
Output deletion confirmation dialog.
Definition: Article.php:1654
Class for viewing MediaWiki file description pages.
Definition: ImagePage.php:28
doPurge($flags=WikiPage::PURGE_ALL)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2046
triggerOpportunisticLinksUpdate(ParserOutput $parserOutput)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2456
getOldIDFromRequest()
Sets $this->mRedirectUrl to a correct URL if the query parameters are incorrect.
Definition: Article.php:255
__get($fname)
Use PHP's magic __get handler to handle accessing of raw WikiPage fields for backwards compatibility...
Definition: Article.php:1948
it s the revision text itself In either if gzip is the revision text is gzipped $flags
Definition: hooks.txt:2705
getDeletionUpdates(Content $content=null)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2150
updateIfNewerOn($dbw, $revision)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2472
clearPreparedEdit()
Call to WikiPage function for backwards compatibility.
Definition: Article.php:1995
static getMainStashInstance()
Get the cache object for the main stash.
when a variable name is used in a it is silently declared as a new local masking the global
Definition: design.txt:93
getContributors()
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2134
static submitButton($value, $attribs=[])
Convenience function to build an HTML submit button When $wgUseMediaWikiUIEverywhere is true it will ...
Definition: Xml.php:459
commitRollback($fromP, $summary, $bot, &$resultDetails, User $guser=null)
Definition: Article.php:2565
showMissingArticle()
Show the error text for a missing article.
Definition: Article.php:1121
wfDebug($text, $dest= 'all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
static showLogExtract(&$out, $types=[], $page= '', $user= '', $param=[])
Show log extract.
protectDescription(array $limit, array $expiry)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2392
Class to simplify the use of log pages.
Definition: LogPage.php:31
usually copyright or history_copyright This message must be in HTML not wikitext & $link
Definition: hooks.txt:2885
getContext()
Gets the context this Article is executed in.
Definition: Article.php:1931
static closeElement($element)
Shortcut to close an XML element.
Definition: Xml.php:118
isRedirect()
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2322
__construct(Title $title, $oldId=null)
Constructor and clear the article.
Definition: Article.php:82
setTimestamp($ts)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2432
protectDescriptionLog(array $limit, array $expiry)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2400
static onArticleDelete($title)
Definition: Article.php:2605
static openElement($element, $attribs=[])
Identical to rawElement(), but has no third parameter and omits the end tag (and the self-closing '/'...
Definition: Html.php:247
Interface for type hinting (accepts WikiPage, Article, ImagePage, CategoryPage)
Definition: Page.php:24
makeParserOptions($context)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2354
wfEscapeWikiText($text)
Escapes the given text so that it may be output using addWikiText() without any linking, formatting, etc.
wfReadOnly()
Check whether the wiki is in read-only mode.
static getMain()
Static methods.
prepareContentForEdit(Content $content, $revision=null, User $user=null, $serialFormat=null, $useCache=true)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2378
const FOR_PUBLIC
Definition: Revision.php:93
static getCanonicalName($index)
Returns the canonical (English) name for a given index.
$wgUseFileCache
This will cache static pages for non-logged-in users to reduce database traffic on public sites...
either a unescaped string or a HtmlArmor object after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock()-offset Set to overwrite offset parameter in $wgRequest set to ''to unsetoffset-wrap String Wrap the message in html(usually something like"&lt
showViewFooter()
Show the footer section of an ordinary page view.
Definition: Article.php:924
static newFromTarget($specificTarget, $vagueTarget=null, $fromMaster=false)
Given a target and the target's type, get an existing Block object if possible.
Definition: Block.php:1111
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist 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 $parserOutput
Definition: hooks.txt:1025
getRevisionFetched()
Get the fetched Revision object depending on request parameters or null on failure.
Definition: Article.php:405
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist 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:1025
insertProtectNullRevision($revCommentMsg, array $limit, array $expiry, $cascade, $reason, $user=null)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2286
const NS_MEDIA
Definition: Defines.php:49
static isValid($ip)
Validate an IP address.
Definition: IP.php:113
showRedirectedFromHeader()
If this request is a redirect view, send "redirected from" subtitle to the output.
Definition: Article.php:833
ParserOutput $mParserOutput
Definition: Article.php:75
getRevision()
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2222
it s the revision text itself In either if gzip is set
Definition: hooks.txt:2705
generateReason(&$hasHistory)
Definition: Article.php:2574
static getRedirectHeaderHtml(Language $lang, $target, $forceKnown=false)
Return the HTML for the top of a redirect page.
Definition: Article.php:1449
insertRedirect()
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2298
int null $mOldId
The oldid of the article that is to be shown, 0 for the current revision.
Definition: Article.php:60
static openElement($element, $attribs=null)
This opens an XML element.
Definition: Xml.php:109
hasViewableContent()
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2270
getComment($audience=Revision::FOR_PUBLIC, User $user=null)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2110
Base interface for content objects.
Definition: Content.php:34
getTitle()
Get the title object of the article.
Definition: Article.php:173
loadFromRow($data, $from)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2330
$cache
Definition: mcc.php:33
getActionOverrides()
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2086
doViewUpdates(User $user, $oldid=0)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2062
getTitle()
Get the title object of the article.
Definition: WikiPage.php:232
const NS_CATEGORY
Definition: Defines.php:75
doDeleteArticleReal($reason, $suppress=false, $u1=null, $u2=null, &$error= '', User $user=null, $tags=[])
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2003
static newFromTitle($title, IContextSource $context)
Create an Article object of the appropriate class for the given page.
Definition: Article.php:112
wfDeprecated($function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
render()
Handle action=render.
Definition: Article.php:1501
static isIP($name)
Does the string match an anonymous IP address?
Definition: User.php:807
const DELETED_RESTRICTED
Definition: Revision.php:88
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 & $sectionContent
Definition: hooks.txt:2499
getCategories()
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2102
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:932
static linkKnown($target, $html=null, $customAttribs=[], $query=[], $options=[ 'known'])
Identical to link(), except $options defaults to 'known'.
Definition: Linker.php:159
replaceSectionAtRev($sectionId, Content $sectionContent, $sectionTitle= '', $baseRevId=null)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2408
static run($event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:131
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
checkFlags($flags)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:1979
const NS_FILE
Definition: Defines.php:67
static makeContent($text, Title $title=null, $modelId=null, $format=null)
Convenience function for creating a Content object from a given textual representation.
$wgRedirectSources
If local interwikis are set up which allow redirects, set this regexp to restrict URLs which will be ...
const TYPE_AUTO
Definition: Block.php:84
presenting them properly to the user as errors is done by the caller return true use this to change the list i e etc $rev
Definition: hooks.txt:1708
static getForTitle(Title $title)
Returns the appropriate ContentHandler singleton for the given title.
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
getContentHandler()
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2118
const NS_MEDIAWIKI
Definition: Defines.php:69
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 local account $user
Definition: hooks.txt:246
static link($target, $html=null, $customAttribs=[], $query=[], $options=[])
This function returns an HTML link to the given target.
Definition: Linker.php:107
static onArticleEdit(Title $title, Revision $revision=null)
Purge caches on page update etc.
Definition: WikiPage.php:3344
Title $mRedirectedFrom
Title from which we were redirected here.
Definition: Article.php:63
const DELETED_TEXT
Definition: Revision.php:85
getCreator($audience=Revision::FOR_PUBLIC, User $user=null)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2142
static singleton()
Get an instance of this object.
Definition: ParserCache.php:36
addHelpLink($to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
Definition: Article.php:1484
newPage(Title $title)
Definition: Article.php:91
Class representing a MediaWiki article and history.
Definition: WikiPage.php:32
static newFromId($id, $flags=0)
Load a page revision from a given revision ID number.
Definition: Revision.php:111
getOldestRevision()
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2198
string $mContent
Text of the revision we are working on.
Definition: Article.php:48
static makeExternalLink($url, $text, $escape=true, $linktype= '', $attribs=[], $title=null)
Make an external link.
Definition: Linker.php:838
null for the local wiki Added should default to null in handler for backwards compatibility add a value to it if you want to add a cookie that have to vary cache options can modify as strings Extensions should add to this list prev or next refreshes the diff cache $unhide
Definition: hooks.txt:1539
clear()
Clear the object.
Definition: Article.php:190
bool $mContentLoaded
Is the content ($mContent) already loaded?
Definition: Article.php:57
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
getLastPurgeTimestamp()
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2054
getAutoDeleteReason(&$hasHistory)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2094
checkTouched()
Call to WikiPage function for backwards compatibility.
Definition: Article.php:1987
updateRevisionOn($dbw, $revision, $lastRevision=null, $lastRevIsRedirect=null)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2488
static selectFields()
Definition: Article.php:2585
error also a ContextSource you ll probably need to make sure the header is varied on $request
Definition: hooks.txt:2575
static newFromID($id)
Constructor from a page id.
Definition: Article.php:100
if(!defined( 'MEDIAWIKI')) $fname
This file is not a valid entry point, perform no further processing unless MEDIAWIKI is defined...
Definition: Setup.php:36
getId()
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2166
getTimestamp()
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2230
static input($name, $value= '', $type= 'text', array $attribs=[])
Convenience function to produce an "" element.
Definition: Html.php:659
pageDataFromTitle($dbr, $title, $options=[])
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2370
getMinorEdit()
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2190
view()
This is the default action of the index.php entry point: just view the page of the given title...
Definition: Article.php:428
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist 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 $content
Definition: hooks.txt:1025
static onArticleDelete(Title $title)
Clears caches when article is deleted.
Definition: WikiPage.php:3301
getContentObject()
Returns a Content object representing the pages effective display content, not necessarily the revisi...
Definition: Article.php:215
getOldID()
Definition: Article.php:242
doDelete($reason, $suppress=false)
Perform a deletion and output success or failure messages.
Definition: Article.php:1762
showNamespaceHeader()
Show a header specific to the namespace currently being viewed, like [[MediaWiki:Talkpagetext]].
Definition: Article.php:910
Show an error when a user tries to do something they do not have the necessary permissions for...
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist 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 to manipulate or replace but no entry for that model exists in $wgContentHandlers please use GetContentModels hook to make them known to core if desired whether it is OK to use $contentModel on $title Handler functions that modify $ok should generally return false to prevent further hooks from further modifying $ok inclusive $limit
Definition: hooks.txt:1025
updateRedirectOn($dbw, $redirectTitle, $lastRevIsRedirect=null)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2480
tryFileCache()
checkLastModified returns true if it has taken care of all output to the client that is necessary for...
Definition: Article.php:1815
insertRedirectEntry(Title $rt, $oldLatest=null)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2306
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist 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 $status
Definition: hooks.txt:1025
static checkLabel($label, $name, $id, $checked=false, $attribs=[])
Convenience function to build an HTML checkbox with a label.
Definition: Xml.php:419
int $mRevIdFetched
Revision ID of revision we are working on.
Definition: Article.php:69
wfMemcKey()
Make a cache key for the local wiki.
fetchContentObject()
Get text content object Does NOT follow redirects.
Definition: Article.php:313
const DB_REPLICA
Definition: defines.php:24
setOldSubtitle($oldid=0)
Generate the navigation links when browsing through an article revisions It shows the information as:...
Definition: Article.php:1289
isCurrent()
Returns true if the currently-referenced revision is the current edit to this page (and it exists)...
Definition: Article.php:389
unprotect()
action=unprotect handler (alias)
Definition: Article.php:1519
Handles the page protection UI and backend.
getTouched()
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2238
static onArticleEdit($title)
Definition: Article.php:2615
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 modifiable modifiable after all normalizations have been except for the $wgMaxImageArea check set to true or false to override the $wgMaxImageArea check result gives extension the possibility to transform it themselves $handler
Definition: hooks.txt:781
getUser($audience=Revision::FOR_PUBLIC, User $user=null)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2254
static newFromWikiPage(WikiPage $page, IContextSource $context)
Create an Article object of the appropriate class for the given page.
Definition: Article.php:144
static selectFields()
Return the list of revision fields that should be selected to create a new page.
Definition: WikiPage.php:281
static doWatchOrUnwatch($watch, Title $title, User $user)
Watch or unwatch a page.
Definition: WatchAction.php:84
$wgSend404Code
Some web hosts attempt to rewrite all responses with a 404 (not found) status code, mangling or hiding MediaWiki's output.
replaceSectionContent($sectionId, Content $sectionContent, $sectionTitle= '', $edittime=null)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2420
setContext($context)
Sets the context this Article is executed in.
Definition: Article.php:1921
static listDropDown($name= '', $list= '', $other= '', $selected= '', $class= '', $tabindex=null)
Build a drop-down box from a textual list.
Definition: Xml.php:507
getRevIdFetched()
Use this to fetch the rev ID used on page views.
Definition: Article.php:416
const NS_USER_TALK
Definition: Defines.php:64
static revUserTools($rev, $isPublic=false)
Generate a user tool link cluster if the current user is allowed to view it.
Definition: Linker.php:1055
showDiffPage()
Show a diff page according to current request variables.
Definition: Article.php:674
static element($element, $attribs=[], $contents= '')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition: Html.php:229
getRedirectURL($rt)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2214
Definition: Block.php:25
showDeletedRevisionHeader()
If the revision requested for view is deleted, check permissions.
Definition: Article.php:1246
static makeTitle($ns, $title, $fragment= '', $interwiki= '')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:511
setRedirectedFrom(Title $from)
Tell the page view functions that this view was redirected from another page on the wiki...
Definition: Article.php:164
getContentModel()
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2126
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:2499
getLinksTimestamp()
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2182
insertOn($dbw, $pageId=null)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2278
getParserOptions()
Get parser options suitable for rendering the primary article wikitext.
Definition: Article.php:1907
const RC_LOG
Definition: Defines.php:141
Revision $mRevision
Revision we are working on.
Definition: Article.php:72
getUserText($audience=Revision::FOR_PUBLIC, User $user=null)
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2262
showPatrolFooter()
If patrol is possible, output a patrol UI box.
Definition: Article.php:947
static label($label, $id, array $attribs=[])
Convenience function for generating a label for inputs.
Definition: Html.php:726
static formatRobotPolicy($policy)
Converts a String robot policy into an associative array, to allow merging of several policies using ...
Definition: Article.php:804
getHiddenCategories()
Call to WikiPage function for backwards compatibility.
Definition: Article.php:2158