MediaWiki REL1_28
Article.php
Go to the documentation of this file.
1<?php
34class 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
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() {
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
212 public function getContent() {
213 wfDeprecated( __METHOD__, '1.21' );
214 $content = $this->getContentObject();
216 }
217
233 protected function getContentObject() {
234
235 if ( $this->mPage->getId() === 0 ) {
236 # If this is a MediaWiki:x message, then load the messages
237 # and return the message value for x.
238 if ( $this->getTitle()->getNamespace() == NS_MEDIAWIKI ) {
239 $text = $this->getTitle()->getDefaultMessageText();
240 if ( $text === false ) {
241 $text = '';
242 }
243
244 $content = ContentHandler::makeContent( $text, $this->getTitle() );
245 } else {
246 $message = $this->getContext()->getUser()->isLoggedIn() ? 'noarticletext' : 'noarticletextanon';
247 $content = new MessageContent( $message, null, 'parsemag' );
248 }
249 } else {
250 $this->fetchContentObject();
252 }
253
254 return $content;
255 }
256
260 public function getOldID() {
261 if ( is_null( $this->mOldId ) ) {
262 $this->mOldId = $this->getOldIDFromRequest();
263 }
264
265 return $this->mOldId;
266 }
267
273 public function getOldIDFromRequest() {
274 $this->mRedirectUrl = false;
275
276 $request = $this->getContext()->getRequest();
277 $oldid = $request->getIntOrNull( 'oldid' );
278
279 if ( $oldid === null ) {
280 return 0;
281 }
282
283 if ( $oldid !== 0 ) {
284 # Load the given revision and check whether the page is another one.
285 # In that case, update this instance to reflect the change.
286 if ( $oldid === $this->mPage->getLatest() ) {
287 $this->mRevision = $this->mPage->getRevision();
288 } else {
289 $this->mRevision = Revision::newFromId( $oldid );
290 if ( $this->mRevision !== null ) {
291 // Revision title doesn't match the page title given?
292 if ( $this->mPage->getId() != $this->mRevision->getPage() ) {
293 $function = [ get_class( $this->mPage ), 'newFromID' ];
294 $this->mPage = call_user_func( $function, $this->mRevision->getPage() );
295 }
296 }
297 }
298 }
299
300 if ( $request->getVal( 'direction' ) == 'next' ) {
301 $nextid = $this->getTitle()->getNextRevisionID( $oldid );
302 if ( $nextid ) {
303 $oldid = $nextid;
304 $this->mRevision = null;
305 } else {
306 $this->mRedirectUrl = $this->getTitle()->getFullURL( 'redirect=no' );
307 }
308 } elseif ( $request->getVal( 'direction' ) == 'prev' ) {
309 $previd = $this->getTitle()->getPreviousRevisionID( $oldid );
310 if ( $previd ) {
311 $oldid = $previd;
312 $this->mRevision = null;
313 }
314 }
315
316 return $oldid;
317 }
318
333 function fetchContent() {
334 // BC cruft!
335
336 wfDeprecated( __METHOD__, '1.21' );
337
338 if ( $this->mContentLoaded && $this->mContent ) {
339 return $this->mContent;
340 }
341
342 $content = $this->fetchContentObject();
343
344 if ( !$content ) {
345 return false;
346 }
347
348 // @todo Get rid of mContent everywhere!
349 $this->mContent = ContentHandler::getContentText( $content );
351 'ArticleAfterFetchContent',
352 [ &$this, &$this->mContent ],
353 '1.21'
354 );
355
356 return $this->mContent;
357 }
358
371 protected function fetchContentObject() {
372 if ( $this->mContentLoaded ) {
374 }
375
376 $this->mContentLoaded = true;
377 $this->mContent = null;
378
379 $oldid = $this->getOldID();
380
381 # Pre-fill content with error message so that if something
382 # fails we'll have something telling us what we intended.
383 // XXX: this isn't page content but a UI message. horrible.
384 $this->mContentObject = new MessageContent( 'missing-revision', [ $oldid ] );
385
386 if ( $oldid ) {
387 # $this->mRevision might already be fetched by getOldIDFromRequest()
388 if ( !$this->mRevision ) {
389 $this->mRevision = Revision::newFromId( $oldid );
390 if ( !$this->mRevision ) {
391 wfDebug( __METHOD__ . " failed to retrieve specified revision, id $oldid\n" );
392 return false;
393 }
394 }
395 } else {
396 $oldid = $this->mPage->getLatest();
397 if ( !$oldid ) {
398 wfDebug( __METHOD__ . " failed to find page data for title " .
399 $this->getTitle()->getPrefixedText() . "\n" );
400 return false;
401 }
402
403 # Update error message with correct oldid
404 $this->mContentObject = new MessageContent( 'missing-revision', [ $oldid ] );
405
406 $this->mRevision = $this->mPage->getRevision();
407
408 if ( !$this->mRevision ) {
409 wfDebug( __METHOD__ . " failed to retrieve current page, rev_id $oldid\n" );
410 return false;
411 }
412 }
413
414 // @todo FIXME: Horrible, horrible! This content-loading interface just plain sucks.
415 // We should instead work with the Revision object when we need it...
416 // Loads if user is allowed
417 $content = $this->mRevision->getContent(
419 $this->getContext()->getUser()
420 );
421
422 if ( !$content ) {
423 wfDebug( __METHOD__ . " failed to retrieve content of revision " .
424 $this->mRevision->getId() . "\n" );
425 return false;
426 }
427
428 $this->mContentObject = $content;
429 $this->mRevIdFetched = $this->mRevision->getId();
430
431 Hooks::run(
432 'ArticleAfterFetchContentObject',
433 [ &$this, &$this->mContentObject ]
434 );
435
437 }
438
444 public function isCurrent() {
445 # If no oldid, this is the current version.
446 if ( $this->getOldID() == 0 ) {
447 return true;
448 }
449
450 return $this->mPage->exists() && $this->mRevision && $this->mRevision->isCurrent();
451 }
452
460 public function getRevisionFetched() {
461 $this->fetchContentObject();
462
463 return $this->mRevision;
464 }
465
471 public function getRevIdFetched() {
472 if ( $this->mRevIdFetched ) {
474 } else {
475 return $this->mPage->getLatest();
476 }
477 }
478
483 public function view() {
485
486 # Get variables from query string
487 # As side effect this will load the revision and update the title
488 # in a revision ID is passed in the request, so this should remain
489 # the first call of this method even if $oldid is used way below.
490 $oldid = $this->getOldID();
491
492 $user = $this->getContext()->getUser();
493 # Another whitelist check in case getOldID() is altering the title
494 $permErrors = $this->getTitle()->getUserPermissionsErrors( 'read', $user );
495 if ( count( $permErrors ) ) {
496 wfDebug( __METHOD__ . ": denied on secondary read check\n" );
497 throw new PermissionsError( 'read', $permErrors );
498 }
499
500 $outputPage = $this->getContext()->getOutput();
501 # getOldID() may as well want us to redirect somewhere else
502 if ( $this->mRedirectUrl ) {
503 $outputPage->redirect( $this->mRedirectUrl );
504 wfDebug( __METHOD__ . ": redirecting due to oldid\n" );
505
506 return;
507 }
508
509 # If we got diff in the query, we want to see a diff page instead of the article.
510 if ( $this->getContext()->getRequest()->getCheck( 'diff' ) ) {
511 wfDebug( __METHOD__ . ": showing diff page\n" );
512 $this->showDiffPage();
513
514 return;
515 }
516
517 # Set page title (may be overridden by DISPLAYTITLE)
518 $outputPage->setPageTitle( $this->getTitle()->getPrefixedText() );
519
520 $outputPage->setArticleFlag( true );
521 # Allow frames by default
522 $outputPage->allowClickjacking();
523
524 $parserCache = ParserCache::singleton();
525
526 $parserOptions = $this->getParserOptions();
527 # Render printable version, use printable version cache
528 if ( $outputPage->isPrintable() ) {
529 $parserOptions->setIsPrintable( true );
530 $parserOptions->setEditSection( false );
531 } elseif ( !$this->isCurrent() || !$this->getTitle()->quickUserCan( 'edit', $user ) ) {
532 $parserOptions->setEditSection( false );
533 }
534
535 # Try client and file cache
536 if ( !$wgDebugToolbar && $oldid === 0 && $this->mPage->checkTouched() ) {
537 # Try to stream the output from file cache
538 if ( $wgUseFileCache && $this->tryFileCache() ) {
539 wfDebug( __METHOD__ . ": done file cache\n" );
540 # tell wgOut that output is taken care of
541 $outputPage->disable();
542 $this->mPage->doViewUpdates( $user, $oldid );
543
544 return;
545 }
546 }
547
548 # Should the parser cache be used?
549 $useParserCache = $this->mPage->shouldCheckParserCache( $parserOptions, $oldid );
550 wfDebug( 'Article::view using parser cache: ' . ( $useParserCache ? 'yes' : 'no' ) . "\n" );
551 if ( $user->getStubThreshold() ) {
552 $this->getContext()->getStats()->increment( 'pcache_miss_stub' );
553 }
554
556 $this->showNamespaceHeader();
557
558 # Iterate through the possible ways of constructing the output text.
559 # Keep going until $outputDone is set, or we run out of things to do.
560 $pass = 0;
561 $outputDone = false;
562 $this->mParserOutput = false;
563
564 while ( !$outputDone && ++$pass ) {
565 switch ( $pass ) {
566 case 1:
567 Hooks::run( 'ArticleViewHeader', [ &$this, &$outputDone, &$useParserCache ] );
568 break;
569 case 2:
570 # Early abort if the page doesn't exist
571 if ( !$this->mPage->exists() ) {
572 wfDebug( __METHOD__ . ": showing missing article\n" );
573 $this->showMissingArticle();
574 $this->mPage->doViewUpdates( $user );
575 return;
576 }
577
578 # Try the parser cache
579 if ( $useParserCache ) {
580 $this->mParserOutput = $parserCache->get( $this->mPage, $parserOptions );
581
582 if ( $this->mParserOutput !== false ) {
583 if ( $oldid ) {
584 wfDebug( __METHOD__ . ": showing parser cache contents for current rev permalink\n" );
585 $this->setOldSubtitle( $oldid );
586 } else {
587 wfDebug( __METHOD__ . ": showing parser cache contents\n" );
588 }
589 $outputPage->addParserOutput( $this->mParserOutput );
590 # Ensure that UI elements requiring revision ID have
591 # the correct version information.
592 $outputPage->setRevisionId( $this->mPage->getLatest() );
593 # Preload timestamp to avoid a DB hit
594 $cachedTimestamp = $this->mParserOutput->getTimestamp();
595 if ( $cachedTimestamp !== null ) {
596 $outputPage->setRevisionTimestamp( $cachedTimestamp );
597 $this->mPage->setTimestamp( $cachedTimestamp );
598 }
599 $outputDone = true;
600 }
601 }
602 break;
603 case 3:
604 # This will set $this->mRevision if needed
605 $this->fetchContentObject();
606
607 # Are we looking at an old revision
608 if ( $oldid && $this->mRevision ) {
609 $this->setOldSubtitle( $oldid );
610
611 if ( !$this->showDeletedRevisionHeader() ) {
612 wfDebug( __METHOD__ . ": cannot view deleted revision\n" );
613 return;
614 }
615 }
616
617 # Ensure that UI elements requiring revision ID have
618 # the correct version information.
619 $outputPage->setRevisionId( $this->getRevIdFetched() );
620 # Preload timestamp to avoid a DB hit
621 $outputPage->setRevisionTimestamp( $this->mPage->getTimestamp() );
622
623 # Pages containing custom CSS or JavaScript get special treatment
624 if ( $this->getTitle()->isCssOrJsPage() || $this->getTitle()->isCssJsSubpage() ) {
625 wfDebug( __METHOD__ . ": showing CSS/JS source\n" );
626 $this->showCssOrJsPage();
627 $outputDone = true;
628 } elseif ( !Hooks::run( 'ArticleContentViewCustom',
629 [ $this->fetchContentObject(), $this->getTitle(), $outputPage ] ) ) {
630
631 # Allow extensions do their own custom view for certain pages
632 $outputDone = true;
634 'ArticleViewCustom',
635 [ $this->fetchContentObject(), $this->getTitle(), $outputPage ],
636 '1.21'
637 ) ) {
638 # Allow extensions do their own custom view for certain pages
639 $outputDone = true;
640 }
641 break;
642 case 4:
643 # Run the parse, protected by a pool counter
644 wfDebug( __METHOD__ . ": doing uncached parse\n" );
645
646 $content = $this->getContentObject();
647 $poolArticleView = new PoolWorkArticleView( $this->getPage(), $parserOptions,
648 $this->getRevIdFetched(), $useParserCache, $content );
649
650 if ( !$poolArticleView->execute() ) {
651 $error = $poolArticleView->getError();
652 if ( $error ) {
653 $outputPage->clearHTML(); // for release() errors
654 $outputPage->enableClientCache( false );
655 $outputPage->setRobotPolicy( 'noindex,nofollow' );
656
657 $errortext = $error->getWikiText( false, 'view-pool-error' );
658 $outputPage->addWikiText( '<div class="errorbox">' . $errortext . '</div>' );
659 }
660 # Connection or timeout error
661 return;
662 }
663
664 $this->mParserOutput = $poolArticleView->getParserOutput();
665 $outputPage->addParserOutput( $this->mParserOutput );
666 if ( $content->getRedirectTarget() ) {
667 $outputPage->addSubtitle( "<span id=\"redirectsub\">" .
668 $this->getContext()->msg( 'redirectpagesub' )->parse() . "</span>" );
669 }
670
671 # Don't cache a dirty ParserOutput object
672 if ( $poolArticleView->getIsDirty() ) {
673 $outputPage->setCdnMaxage( 0 );
674 $outputPage->addHTML( "<!-- parser cache is expired, " .
675 "sending anyway due to pool overload-->\n" );
676 }
677
678 $outputDone = true;
679 break;
680 # Should be unreachable, but just in case...
681 default:
682 break 2;
683 }
684 }
685
686 # Get the ParserOutput actually *displayed* here.
687 # Note that $this->mParserOutput is the *current*/oldid version output.
688 $pOutput = ( $outputDone instanceof ParserOutput )
689 ? $outputDone // object fetched by hook
691
692 # Adjust title for main page & pages with displaytitle
693 if ( $pOutput ) {
694 $this->adjustDisplayTitle( $pOutput );
695 }
696
697 # For the main page, overwrite the <title> element with the con-
698 # tents of 'pagetitle-view-mainpage' instead of the default (if
699 # that's not empty).
700 # This message always exists because it is in the i18n files
701 if ( $this->getTitle()->isMainPage() ) {
702 $msg = wfMessage( 'pagetitle-view-mainpage' )->inContentLanguage();
703 if ( !$msg->isDisabled() ) {
704 $outputPage->setHTMLTitle( $msg->title( $this->getTitle() )->text() );
705 }
706 }
707
708 # Use adaptive TTLs for CDN so delayed/failed purges are noticed less often.
709 # This could use getTouched(), but that could be scary for major template edits.
710 $outputPage->adaptCdnTTL( $this->mPage->getTimestamp(), IExpiringStore::TTL_DAY );
711
712 # Check for any __NOINDEX__ tags on the page using $pOutput
713 $policy = $this->getRobotPolicy( 'view', $pOutput );
714 $outputPage->setIndexPolicy( $policy['index'] );
715 $outputPage->setFollowPolicy( $policy['follow'] );
716
717 $this->showViewFooter();
718 $this->mPage->doViewUpdates( $user, $oldid );
719
720 $outputPage->addModules( 'mediawiki.action.view.postEdit' );
721 }
722
727 public function adjustDisplayTitle( ParserOutput $pOutput ) {
728 # Adjust the title if it was set by displaytitle, -{T|}- or language conversion
729 $titleText = $pOutput->getTitleText();
730 if ( strval( $titleText ) !== '' ) {
731 $this->getContext()->getOutput()->setPageTitle( $titleText );
732 }
733 }
734
740 protected function showDiffPage() {
741 $request = $this->getContext()->getRequest();
742 $user = $this->getContext()->getUser();
743 $diff = $request->getVal( 'diff' );
744 $rcid = $request->getVal( 'rcid' );
745 $diffOnly = $request->getBool( 'diffonly', $user->getOption( 'diffonly' ) );
746 $purge = $request->getVal( 'action' ) == 'purge';
747 $unhide = $request->getInt( 'unhide' ) == 1;
748 $oldid = $this->getOldID();
749
750 $rev = $this->getRevisionFetched();
751
752 if ( !$rev ) {
753 $this->getContext()->getOutput()->setPageTitle( wfMessage( 'errorpagetitle' ) );
754 $msg = $this->getContext()->msg( 'difference-missing-revision' )
755 ->params( $oldid )
756 ->numParams( 1 )
757 ->parseAsBlock();
758 $this->getContext()->getOutput()->addHTML( $msg );
759 return;
760 }
761
762 $contentHandler = $rev->getContentHandler();
763 $de = $contentHandler->createDifferenceEngine(
764 $this->getContext(),
765 $oldid,
766 $diff,
767 $rcid,
768 $purge,
769 $unhide
770 );
771
772 // DifferenceEngine directly fetched the revision:
773 $this->mRevIdFetched = $de->mNewid;
774 $de->showDiffPage( $diffOnly );
775
776 // Run view updates for the newer revision being diffed (and shown
777 // below the diff if not $diffOnly).
778 list( $old, $new ) = $de->mapDiffPrevNext( $oldid, $diff );
779 // New can be false, convert it to 0 - this conveniently means the latest revision
780 $this->mPage->doViewUpdates( $user, (int)$new );
781 }
782
794 protected function showCssOrJsPage( $showCacheHint = true ) {
795 $outputPage = $this->getContext()->getOutput();
796
797 if ( $showCacheHint ) {
798 $dir = $this->getContext()->getLanguage()->getDir();
799 $lang = $this->getContext()->getLanguage()->getHtmlCode();
800
801 $outputPage->wrapWikiMsg(
802 "<div id='mw-clearyourcache' lang='$lang' dir='$dir' class='mw-content-$dir'>\n$1\n</div>",
803 'clearyourcache'
804 );
805 }
806
807 $this->fetchContentObject();
808
809 if ( $this->mContentObject ) {
810 // Give hooks a chance to customise the output
812 'ShowRawCssJs',
813 [ $this->mContentObject, $this->getTitle(), $outputPage ],
814 '1.24'
815 ) ) {
816 // If no legacy hooks ran, display the content of the parser output, including RL modules,
817 // but excluding metadata like categories and language links
818 $po = $this->mContentObject->getParserOutput( $this->getTitle() );
819 $outputPage->addParserOutputContent( $po );
820 }
821 }
822 }
823
831 public function getRobotPolicy( $action, $pOutput = null ) {
833
834 $ns = $this->getTitle()->getNamespace();
835
836 # Don't index user and user talk pages for blocked users (bug 11443)
837 if ( ( $ns == NS_USER || $ns == NS_USER_TALK ) && !$this->getTitle()->isSubpage() ) {
838 $specificTarget = null;
839 $vagueTarget = null;
840 $titleText = $this->getTitle()->getText();
841 if ( IP::isValid( $titleText ) ) {
842 $vagueTarget = $titleText;
843 } else {
844 $specificTarget = $titleText;
845 }
846 if ( Block::newFromTarget( $specificTarget, $vagueTarget ) instanceof Block ) {
847 return [
848 'index' => 'noindex',
849 'follow' => 'nofollow'
850 ];
851 }
852 }
853
854 if ( $this->mPage->getId() === 0 || $this->getOldID() ) {
855 # Non-articles (special pages etc), and old revisions
856 return [
857 'index' => 'noindex',
858 'follow' => 'nofollow'
859 ];
860 } elseif ( $this->getContext()->getOutput()->isPrintable() ) {
861 # Discourage indexing of printable versions, but encourage following
862 return [
863 'index' => 'noindex',
864 'follow' => 'follow'
865 ];
866 } elseif ( $this->getContext()->getRequest()->getInt( 'curid' ) ) {
867 # For ?curid=x urls, disallow indexing
868 return [
869 'index' => 'noindex',
870 'follow' => 'follow'
871 ];
872 }
873
874 # Otherwise, construct the policy based on the various config variables.
876
877 if ( isset( $wgNamespaceRobotPolicies[$ns] ) ) {
878 # Honour customised robot policies for this namespace
879 $policy = array_merge(
880 $policy,
881 self::formatRobotPolicy( $wgNamespaceRobotPolicies[$ns] )
882 );
883 }
884 if ( $this->getTitle()->canUseNoindex() && is_object( $pOutput ) && $pOutput->getIndexPolicy() ) {
885 # __INDEX__ and __NOINDEX__ magic words, if allowed. Incorporates
886 # a final sanity check that we have really got the parser output.
887 $policy = array_merge(
888 $policy,
889 [ 'index' => $pOutput->getIndexPolicy() ]
890 );
891 }
892
893 if ( isset( $wgArticleRobotPolicies[$this->getTitle()->getPrefixedText()] ) ) {
894 # (bug 14900) site config can override user-defined __INDEX__ or __NOINDEX__
895 $policy = array_merge(
896 $policy,
897 self::formatRobotPolicy( $wgArticleRobotPolicies[$this->getTitle()->getPrefixedText()] )
898 );
899 }
900
901 return $policy;
902 }
903
911 public static function formatRobotPolicy( $policy ) {
912 if ( is_array( $policy ) ) {
913 return $policy;
914 } elseif ( !$policy ) {
915 return [];
916 }
917
918 $policy = explode( ',', $policy );
919 $policy = array_map( 'trim', $policy );
920
921 $arr = [];
922 foreach ( $policy as $var ) {
923 if ( in_array( $var, [ 'index', 'noindex' ] ) ) {
924 $arr['index'] = $var;
925 } elseif ( in_array( $var, [ 'follow', 'nofollow' ] ) ) {
926 $arr['follow'] = $var;
927 }
928 }
929
930 return $arr;
931 }
932
940 public function showRedirectedFromHeader() {
942
943 $context = $this->getContext();
944 $outputPage = $context->getOutput();
946 $rdfrom = $request->getVal( 'rdfrom' );
947
948 // Construct a URL for the current page view, but with the target title
949 $query = $request->getValues();
950 unset( $query['rdfrom'] );
951 unset( $query['title'] );
952 if ( $this->getTitle()->isRedirect() ) {
953 // Prevent double redirects
954 $query['redirect'] = 'no';
955 }
956 $redirectTargetUrl = $this->getTitle()->getLinkURL( $query );
957
958 if ( isset( $this->mRedirectedFrom ) ) {
959 // This is an internally redirected page view.
960 // We'll need a backlink to the source page for navigation.
961 if ( Hooks::run( 'ArticleViewRedirect', [ &$this ] ) ) {
962 $redir = Linker::linkKnown(
963 $this->mRedirectedFrom,
964 null,
965 [],
966 [ 'redirect' => 'no' ]
967 );
968
969 $outputPage->addSubtitle( "<span class=\"mw-redirectedfrom\">" .
970 $context->msg( 'redirectedfrom' )->rawParams( $redir )->parse()
971 . "</span>" );
972
973 // Add the script to update the displayed URL and
974 // set the fragment if one was specified in the redirect
975 $outputPage->addJsConfigVars( [
976 'wgInternalRedirectTargetUrl' => $redirectTargetUrl,
977 ] );
978 $outputPage->addModules( 'mediawiki.action.view.redirect' );
979
980 // Add a <link rel="canonical"> tag
981 $outputPage->setCanonicalUrl( $this->getTitle()->getCanonicalURL() );
982
983 // Tell the output object that the user arrived at this article through a redirect
984 $outputPage->setRedirectedFrom( $this->mRedirectedFrom );
985
986 return true;
987 }
988 } elseif ( $rdfrom ) {
989 // This is an externally redirected view, from some other wiki.
990 // If it was reported from a trusted site, supply a backlink.
991 if ( $wgRedirectSources && preg_match( $wgRedirectSources, $rdfrom ) ) {
992 $redir = Linker::makeExternalLink( $rdfrom, $rdfrom );
993 $outputPage->addSubtitle( "<span class=\"mw-redirectedfrom\">" .
994 $context->msg( 'redirectedfrom' )->rawParams( $redir )->parse()
995 . "</span>" );
996
997 // Add the script to update the displayed URL
998 $outputPage->addJsConfigVars( [
999 'wgInternalRedirectTargetUrl' => $redirectTargetUrl,
1000 ] );
1001 $outputPage->addModules( 'mediawiki.action.view.redirect' );
1002
1003 return true;
1004 }
1005 }
1006
1007 return false;
1008 }
1009
1014 public function showNamespaceHeader() {
1015 if ( $this->getTitle()->isTalkPage() ) {
1016 if ( !wfMessage( 'talkpageheader' )->isDisabled() ) {
1017 $this->getContext()->getOutput()->wrapWikiMsg(
1018 "<div class=\"mw-talkpageheader\">\n$1\n</div>",
1019 [ 'talkpageheader' ]
1020 );
1021 }
1022 }
1023 }
1024
1028 public function showViewFooter() {
1029 # check if we're displaying a [[User talk:x.x.x.x]] anonymous talk page
1030 if ( $this->getTitle()->getNamespace() == NS_USER_TALK
1031 && IP::isValid( $this->getTitle()->getText() )
1032 ) {
1033 $this->getContext()->getOutput()->addWikiMsg( 'anontalkpagetext' );
1034 }
1035
1036 // Show a footer allowing the user to patrol the shown revision or page if possible
1037 $patrolFooterShown = $this->showPatrolFooter();
1038
1039 Hooks::run( 'ArticleViewFooter', [ $this, $patrolFooterShown ] );
1040 }
1041
1051 public function showPatrolFooter() {
1053
1054 $outputPage = $this->getContext()->getOutput();
1055 $user = $this->getContext()->getUser();
1056 $title = $this->getTitle();
1057 $rc = false;
1058
1059 if ( !$title->quickUserCan( 'patrol', $user )
1061 || ( $wgUseFilePatrol && $title->inNamespace( NS_FILE ) ) )
1062 ) {
1063 // Patrolling is disabled or the user isn't allowed to
1064 return false;
1065 }
1066
1067 if ( $this->mRevision
1068 && !RecentChange::isInRCLifespan( $this->mRevision->getTimestamp(), 21600 )
1069 ) {
1070 // The current revision is already older than what could be in the RC table
1071 // 6h tolerance because the RC might not be cleaned out regularly
1072 return false;
1073 }
1074
1075 // Check for cached results
1076 $key = wfMemcKey( 'unpatrollable-page', $title->getArticleID() );
1077 $cache = ObjectCache::getMainWANInstance();
1078 if ( $cache->get( $key ) ) {
1079 return false;
1080 }
1081
1082 $dbr = wfGetDB( DB_REPLICA );
1083 $oldestRevisionTimestamp = $dbr->selectField(
1084 'revision',
1085 'MIN( rev_timestamp )',
1086 [ 'rev_page' => $title->getArticleID() ],
1087 __METHOD__
1088 );
1089
1090 // New page patrol: Get the timestamp of the oldest revison which
1091 // the revision table holds for the given page. Then we look
1092 // whether it's within the RC lifespan and if it is, we try
1093 // to get the recentchanges row belonging to that entry
1094 // (with rc_new = 1).
1095 $recentPageCreation = false;
1096 if ( $oldestRevisionTimestamp
1097 && RecentChange::isInRCLifespan( $oldestRevisionTimestamp, 21600 )
1098 ) {
1099 // 6h tolerance because the RC might not be cleaned out regularly
1100 $recentPageCreation = true;
1102 [
1103 'rc_new' => 1,
1104 'rc_timestamp' => $oldestRevisionTimestamp,
1105 'rc_namespace' => $title->getNamespace(),
1106 'rc_cur_id' => $title->getArticleID()
1107 ],
1108 __METHOD__
1109 );
1110 if ( $rc ) {
1111 // Use generic patrol message for new pages
1112 $markPatrolledMsg = wfMessage( 'markaspatrolledtext' );
1113 }
1114 }
1115
1116 // File patrol: Get the timestamp of the latest upload for this page,
1117 // check whether it is within the RC lifespan and if it is, we try
1118 // to get the recentchanges row belonging to that entry
1119 // (with rc_type = RC_LOG, rc_log_type = upload).
1120 $recentFileUpload = false;
1121 if ( ( !$rc || $rc->getAttribute( 'rc_patrolled' ) ) && $wgUseFilePatrol
1122 && $title->getNamespace() === NS_FILE ) {
1123 // Retrieve timestamp of most recent upload
1124 $newestUploadTimestamp = $dbr->selectField(
1125 'image',
1126 'MAX( img_timestamp )',
1127 [ 'img_name' => $title->getDBkey() ],
1128 __METHOD__
1129 );
1130 if ( $newestUploadTimestamp
1131 && RecentChange::isInRCLifespan( $newestUploadTimestamp, 21600 )
1132 ) {
1133 // 6h tolerance because the RC might not be cleaned out regularly
1134 $recentFileUpload = true;
1136 [
1137 'rc_type' => RC_LOG,
1138 'rc_log_type' => 'upload',
1139 'rc_timestamp' => $newestUploadTimestamp,
1140 'rc_namespace' => NS_FILE,
1141 'rc_cur_id' => $title->getArticleID()
1142 ],
1143 __METHOD__,
1144 [ 'USE INDEX' => 'rc_timestamp' ]
1145 );
1146 if ( $rc ) {
1147 // Use patrol message specific to files
1148 $markPatrolledMsg = wfMessage( 'markaspatrolledtext-file' );
1149 }
1150 }
1151 }
1152
1153 if ( !$recentPageCreation && !$recentFileUpload ) {
1154 // Page creation and latest upload (for files) is too old to be in RC
1155
1156 // We definitely can't patrol so cache the information
1157 // When a new file version is uploaded, the cache is cleared
1158 $cache->set( $key, '1' );
1159
1160 return false;
1161 }
1162
1163 if ( !$rc ) {
1164 // Don't cache: This can be hit if the page gets accessed very fast after
1165 // its creation / latest upload or in case we have high replica DB lag. In case
1166 // the revision is too old, we will already return above.
1167 return false;
1168 }
1169
1170 if ( $rc->getAttribute( 'rc_patrolled' ) ) {
1171 // Patrolled RC entry around
1172
1173 // Cache the information we gathered above in case we can't patrol
1174 // Don't cache in case we can patrol as this could change
1175 $cache->set( $key, '1' );
1176
1177 return false;
1178 }
1179
1180 if ( $rc->getPerformer()->equals( $user ) ) {
1181 // Don't show a patrol link for own creations/uploads. If the user could
1182 // patrol them, they already would be patrolled
1183 return false;
1184 }
1185
1186 $rcid = $rc->getAttribute( 'rc_id' );
1187
1188 $token = $user->getEditToken( $rcid );
1189
1190 $outputPage->preventClickjacking();
1191 if ( $wgEnableAPI && $wgEnableWriteAPI && $user->isAllowed( 'writeapi' ) ) {
1192 $outputPage->addModules( 'mediawiki.page.patrol.ajax' );
1193 }
1194
1196 $title,
1197 $markPatrolledMsg->escaped(),
1198 [],
1199 [
1200 'action' => 'markpatrolled',
1201 'rcid' => $rcid,
1202 'token' => $token,
1203 ]
1204 );
1205
1206 $outputPage->addHTML(
1207 "<div class='patrollink' data-mw='interface'>" .
1208 wfMessage( 'markaspatrolledlink' )->rawParams( $link )->escaped() .
1209 '</div>'
1210 );
1211
1212 return true;
1213 }
1214
1221 public static function purgePatrolFooterCache( $articleID ) {
1222 $cache = ObjectCache::getMainWANInstance();
1223 $cache->delete( wfMemcKey( 'unpatrollable-page', $articleID ) );
1224 }
1225
1230 public function showMissingArticle() {
1232
1233 $outputPage = $this->getContext()->getOutput();
1234 // Whether the page is a root user page of an existing user (but not a subpage)
1235 $validUserPage = false;
1236
1237 $title = $this->getTitle();
1238
1239 # Show info in user (talk) namespace. Does the user exist? Is he blocked?
1240 if ( $title->getNamespace() == NS_USER
1241 || $title->getNamespace() == NS_USER_TALK
1242 ) {
1243 $rootPart = explode( '/', $title->getText() )[0];
1244 $user = User::newFromName( $rootPart, false /* allow IP users*/ );
1245 $ip = User::isIP( $rootPart );
1246 $block = Block::newFromTarget( $user, $user );
1247
1248 if ( !( $user && $user->isLoggedIn() ) && !$ip ) { # User does not exist
1249 $outputPage->wrapWikiMsg( "<div class=\"mw-userpage-userdoesnotexist error\">\n\$1\n</div>",
1250 [ 'userpage-userdoesnotexist-view', wfEscapeWikiText( $rootPart ) ] );
1251 } elseif ( !is_null( $block ) && $block->getType() != Block::TYPE_AUTO ) {
1252 # Show log extract if the user is currently blocked
1254 $outputPage,
1255 'block',
1256 MWNamespace::getCanonicalName( NS_USER ) . ':' . $block->getTarget(),
1257 '',
1258 [
1259 'lim' => 1,
1260 'showIfEmpty' => false,
1261 'msgKey' => [
1262 'blocked-notice-logextract',
1263 $user->getName() # Support GENDER in notice
1264 ]
1265 ]
1266 );
1267 $validUserPage = !$title->isSubpage();
1268 } else {
1269 $validUserPage = !$title->isSubpage();
1270 }
1271 }
1272
1273 Hooks::run( 'ShowMissingArticle', [ $this ] );
1274
1275 # Show delete and move logs if there were any such events.
1276 # The logging query can DOS the site when bots/crawlers cause 404 floods,
1277 # so be careful showing this. 404 pages must be cheap as they are hard to cache.
1278 $cache = ObjectCache::getMainStashInstance();
1279 $key = wfMemcKey( 'page-recent-delete', md5( $title->getPrefixedText() ) );
1280 $loggedIn = $this->getContext()->getUser()->isLoggedIn();
1281 if ( $loggedIn || $cache->get( $key ) ) {
1282 $logTypes = [ 'delete', 'move' ];
1283 $conds = [ "log_action != 'revision'" ];
1284 // Give extensions a chance to hide their (unrelated) log entries
1285 Hooks::run( 'Article::MissingArticleConditions', [ &$conds, $logTypes ] );
1287 $outputPage,
1288 $logTypes,
1289 $title,
1290 '',
1291 [
1292 'lim' => 10,
1293 'conds' => $conds,
1294 'showIfEmpty' => false,
1295 'msgKey' => [ $loggedIn
1296 ? 'moveddeleted-notice'
1297 : 'moveddeleted-notice-recent'
1298 ]
1299 ]
1300 );
1301 }
1302
1303 if ( !$this->mPage->hasViewableContent() && $wgSend404Code && !$validUserPage ) {
1304 // If there's no backing content, send a 404 Not Found
1305 // for better machine handling of broken links.
1306 $this->getContext()->getRequest()->response()->statusHeader( 404 );
1307 }
1308
1309 // Also apply the robot policy for nonexisting pages (even if a 404 was used for sanity)
1310 $policy = $this->getRobotPolicy( 'view' );
1311 $outputPage->setIndexPolicy( $policy['index'] );
1312 $outputPage->setFollowPolicy( $policy['follow'] );
1313
1314 $hookResult = Hooks::run( 'BeforeDisplayNoArticleText', [ $this ] );
1315
1316 if ( !$hookResult ) {
1317 return;
1318 }
1319
1320 # Show error message
1321 $oldid = $this->getOldID();
1322 if ( !$oldid && $title->getNamespace() === NS_MEDIAWIKI && $title->hasSourceText() ) {
1323 $outputPage->addParserOutput( $this->getContentObject()->getParserOutput( $title ) );
1324 } else {
1325 if ( $oldid ) {
1326 $text = wfMessage( 'missing-revision', $oldid )->plain();
1327 } elseif ( $title->quickUserCan( 'create', $this->getContext()->getUser() )
1328 && $title->quickUserCan( 'edit', $this->getContext()->getUser() )
1329 ) {
1330 $message = $this->getContext()->getUser()->isLoggedIn() ? 'noarticletext' : 'noarticletextanon';
1331 $text = wfMessage( $message )->plain();
1332 } else {
1333 $text = wfMessage( 'noarticletext-nopermission' )->plain();
1334 }
1335
1336 $dir = $this->getContext()->getLanguage()->getDir();
1337 $lang = $this->getContext()->getLanguage()->getCode();
1338 $outputPage->addWikiText( Xml::openElement( 'div', [
1339 'class' => "noarticletext mw-content-$dir",
1340 'dir' => $dir,
1341 'lang' => $lang,
1342 ] ) . "\n$text\n</div>" );
1343 }
1344 }
1345
1352 public function showDeletedRevisionHeader() {
1353 if ( !$this->mRevision->isDeleted( Revision::DELETED_TEXT ) ) {
1354 // Not deleted
1355 return true;
1356 }
1357
1358 $outputPage = $this->getContext()->getOutput();
1359 $user = $this->getContext()->getUser();
1360 // If the user is not allowed to see it...
1361 if ( !$this->mRevision->userCan( Revision::DELETED_TEXT, $user ) ) {
1362 $outputPage->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n",
1363 'rev-deleted-text-permission' );
1364
1365 return false;
1366 // If the user needs to confirm that they want to see it...
1367 } elseif ( $this->getContext()->getRequest()->getInt( 'unhide' ) != 1 ) {
1368 # Give explanation and add a link to view the revision...
1369 $oldid = intval( $this->getOldID() );
1370 $link = $this->getTitle()->getFullURL( "oldid={$oldid}&unhide=1" );
1371 $msg = $this->mRevision->isDeleted( Revision::DELETED_RESTRICTED ) ?
1372 'rev-suppressed-text-unhide' : 'rev-deleted-text-unhide';
1373 $outputPage->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n",
1374 [ $msg, $link ] );
1375
1376 return false;
1377 // We are allowed to see...
1378 } else {
1379 $msg = $this->mRevision->isDeleted( Revision::DELETED_RESTRICTED ) ?
1380 'rev-suppressed-text-view' : 'rev-deleted-text-view';
1381 $outputPage->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n", $msg );
1382
1383 return true;
1384 }
1385 }
1386
1395 public function setOldSubtitle( $oldid = 0 ) {
1396 if ( !Hooks::run( 'DisplayOldSubtitle', [ &$this, &$oldid ] ) ) {
1397 return;
1398 }
1399
1400 $context = $this->getContext();
1401 $unhide = $context->getRequest()->getInt( 'unhide' ) == 1;
1402
1403 # Cascade unhide param in links for easy deletion browsing
1404 $extraParams = [];
1405 if ( $unhide ) {
1406 $extraParams['unhide'] = 1;
1407 }
1408
1409 if ( $this->mRevision && $this->mRevision->getId() === $oldid ) {
1410 $revision = $this->mRevision;
1411 } else {
1412 $revision = Revision::newFromId( $oldid );
1413 }
1414
1415 $timestamp = $revision->getTimestamp();
1416
1417 $current = ( $oldid == $this->mPage->getLatest() );
1418 $language = $context->getLanguage();
1419 $user = $context->getUser();
1420
1421 $td = $language->userTimeAndDate( $timestamp, $user );
1422 $tddate = $language->userDate( $timestamp, $user );
1423 $tdtime = $language->userTime( $timestamp, $user );
1424
1425 # Show user links if allowed to see them. If hidden, then show them only if requested...
1426 $userlinks = Linker::revUserTools( $revision, !$unhide );
1427
1428 $infomsg = $current && !$context->msg( 'revision-info-current' )->isDisabled()
1429 ? 'revision-info-current'
1430 : 'revision-info';
1431
1432 $outputPage = $context->getOutput();
1433 $revisionInfo = "<div id=\"mw-{$infomsg}\">" .
1434 $context->msg( $infomsg, $td )
1435 ->rawParams( $userlinks )
1436 ->params( $revision->getId(), $tddate, $tdtime, $revision->getUserText() )
1437 ->rawParams( Linker::revComment( $revision, true, true ) )
1438 ->parse() .
1439 "</div>";
1440
1441 $lnk = $current
1442 ? $context->msg( 'currentrevisionlink' )->escaped()
1444 $this->getTitle(),
1445 $context->msg( 'currentrevisionlink' )->escaped(),
1446 [],
1447 $extraParams
1448 );
1449 $curdiff = $current
1450 ? $context->msg( 'diff' )->escaped()
1452 $this->getTitle(),
1453 $context->msg( 'diff' )->escaped(),
1454 [],
1455 [
1456 'diff' => 'cur',
1457 'oldid' => $oldid
1458 ] + $extraParams
1459 );
1460 $prev = $this->getTitle()->getPreviousRevisionID( $oldid );
1461 $prevlink = $prev
1463 $this->getTitle(),
1464 $context->msg( 'previousrevision' )->escaped(),
1465 [],
1466 [
1467 'direction' => 'prev',
1468 'oldid' => $oldid
1469 ] + $extraParams
1470 )
1471 : $context->msg( 'previousrevision' )->escaped();
1472 $prevdiff = $prev
1474 $this->getTitle(),
1475 $context->msg( 'diff' )->escaped(),
1476 [],
1477 [
1478 'diff' => 'prev',
1479 'oldid' => $oldid
1480 ] + $extraParams
1481 )
1482 : $context->msg( 'diff' )->escaped();
1483 $nextlink = $current
1484 ? $context->msg( 'nextrevision' )->escaped()
1486 $this->getTitle(),
1487 $context->msg( 'nextrevision' )->escaped(),
1488 [],
1489 [
1490 'direction' => 'next',
1491 'oldid' => $oldid
1492 ] + $extraParams
1493 );
1494 $nextdiff = $current
1495 ? $context->msg( 'diff' )->escaped()
1497 $this->getTitle(),
1498 $context->msg( 'diff' )->escaped(),
1499 [],
1500 [
1501 'diff' => 'next',
1502 'oldid' => $oldid
1503 ] + $extraParams
1504 );
1505
1506 $cdel = Linker::getRevDeleteLink( $user, $revision, $this->getTitle() );
1507 if ( $cdel !== '' ) {
1508 $cdel .= ' ';
1509 }
1510
1511 // the outer div is need for styling the revision info and nav in MobileFrontend
1512 $outputPage->addSubtitle( "<div class=\"mw-revision\">" . $revisionInfo .
1513 "<div id=\"mw-revision-nav\">" . $cdel .
1514 $context->msg( 'revision-nav' )->rawParams(
1515 $prevdiff, $prevlink, $lnk, $curdiff, $nextlink, $nextdiff
1516 )->escaped() . "</div></div>" );
1517 }
1518
1530 public function viewRedirect( $target, $appendSubtitle = true, $forceKnown = false ) {
1531 $lang = $this->getTitle()->getPageLanguage();
1532 $out = $this->getContext()->getOutput();
1533 if ( $appendSubtitle ) {
1534 $out->addSubtitle( wfMessage( 'redirectpagesub' ) );
1535 }
1536 $out->addModuleStyles( 'mediawiki.action.view.redirectPage' );
1537 return static::getRedirectHeaderHtml( $lang, $target, $forceKnown );
1538 }
1539
1552 public static function getRedirectHeaderHtml( Language $lang, $target, $forceKnown = false ) {
1553 if ( !is_array( $target ) ) {
1554 $target = [ $target ];
1555 }
1556
1557 $html = '<ul class="redirectText">';
1559 foreach ( $target as $title ) {
1560 $html .= '<li>' . Linker::link(
1561 $title,
1562 htmlspecialchars( $title->getFullText() ),
1563 [],
1564 // Make sure wiki page redirects are not followed
1565 $title->isRedirect() ? [ 'redirect' => 'no' ] : [],
1566 ( $forceKnown ? [ 'known', 'noclasses' ] : [] )
1567 ) . '</li>';
1568 }
1569 $html .= '</ul>';
1570
1571 $redirectToText = wfMessage( 'redirectto' )->inLanguage( $lang )->escaped();
1572
1573 return '<div class="redirectMsg">' .
1574 '<p>' . $redirectToText . '</p>' .
1575 $html .
1576 '</div>';
1577 }
1578
1587 public function addHelpLink( $to, $overrideBaseUrl = false ) {
1588 $msg = wfMessage(
1589 'namespace-' . $this->getTitle()->getNamespace() . '-helppage'
1590 );
1591
1592 $out = $this->getContext()->getOutput();
1593 if ( !$msg->isDisabled() ) {
1594 $helpUrl = Skin::makeUrl( $msg->plain() );
1595 $out->addHelpLink( $helpUrl, true );
1596 } else {
1597 $out->addHelpLink( $to, $overrideBaseUrl );
1598 }
1599 }
1600
1604 public function render() {
1605 $this->getContext()->getRequest()->response()->header( 'X-Robots-Tag: noindex' );
1606 $this->getContext()->getOutput()->setArticleBodyOnly( true );
1607 $this->getContext()->getOutput()->enableSectionEditLinks( false );
1608 $this->view();
1609 }
1610
1614 public function protect() {
1615 $form = new ProtectionForm( $this );
1616 $form->execute();
1617 }
1618
1622 public function unprotect() {
1623 $this->protect();
1624 }
1625
1629 public function delete() {
1630 # This code desperately needs to be totally rewritten
1631
1632 $title = $this->getTitle();
1633 $context = $this->getContext();
1634 $user = $context->getUser();
1636
1637 # Check permissions
1638 $permissionErrors = $title->getUserPermissionsErrors( 'delete', $user );
1639 if ( count( $permissionErrors ) ) {
1640 throw new PermissionsError( 'delete', $permissionErrors );
1641 }
1642
1643 # Read-only check...
1644 if ( wfReadOnly() ) {
1645 throw new ReadOnlyError;
1646 }
1647
1648 # Better double-check that it hasn't been deleted yet!
1649 $this->mPage->loadPageData(
1650 $request->wasPosted() ? WikiPage::READ_LATEST : WikiPage::READ_NORMAL
1651 );
1652 if ( !$this->mPage->exists() ) {
1653 $deleteLogPage = new LogPage( 'delete' );
1654 $outputPage = $context->getOutput();
1655 $outputPage->setPageTitle( $context->msg( 'cannotdelete-title', $title->getPrefixedText() ) );
1656 $outputPage->wrapWikiMsg( "<div class=\"error mw-error-cannotdelete\">\n$1\n</div>",
1657 [ 'cannotdelete', wfEscapeWikiText( $title->getPrefixedText() ) ]
1658 );
1659 $outputPage->addHTML(
1660 Xml::element( 'h2', null, $deleteLogPage->getName()->text() )
1661 );
1663 $outputPage,
1664 'delete',
1665 $title
1666 );
1667
1668 return;
1669 }
1670
1671 $deleteReasonList = $request->getText( 'wpDeleteReasonList', 'other' );
1672 $deleteReason = $request->getText( 'wpReason' );
1673
1674 if ( $deleteReasonList == 'other' ) {
1675 $reason = $deleteReason;
1676 } elseif ( $deleteReason != '' ) {
1677 // Entry from drop down menu + additional comment
1678 $colonseparator = wfMessage( 'colon-separator' )->inContentLanguage()->text();
1679 $reason = $deleteReasonList . $colonseparator . $deleteReason;
1680 } else {
1681 $reason = $deleteReasonList;
1682 }
1683
1684 if ( $request->wasPosted() && $user->matchEditToken( $request->getVal( 'wpEditToken' ),
1685 [ 'delete', $this->getTitle()->getPrefixedText() ] )
1686 ) {
1687 # Flag to hide all contents of the archived revisions
1688 $suppress = $request->getVal( 'wpSuppress' ) && $user->isAllowed( 'suppressrevision' );
1689
1690 $this->doDelete( $reason, $suppress );
1691
1692 WatchAction::doWatchOrUnwatch( $request->getCheck( 'wpWatch' ), $title, $user );
1693
1694 return;
1695 }
1696
1697 // Generate deletion reason
1698 $hasHistory = false;
1699 if ( !$reason ) {
1700 try {
1701 $reason = $this->generateReason( $hasHistory );
1702 } catch ( Exception $e ) {
1703 # if a page is horribly broken, we still want to be able to
1704 # delete it. So be lenient about errors here.
1705 wfDebug( "Error while building auto delete summary: $e" );
1706 $reason = '';
1707 }
1708 }
1709
1710 // If the page has a history, insert a warning
1711 if ( $hasHistory ) {
1712 $title = $this->getTitle();
1713
1714 // The following can use the real revision count as this is only being shown for users
1715 // that can delete this page.
1716 // This, as a side-effect, also makes sure that the following query isn't being run for
1717 // pages with a larger history, unless the user has the 'bigdelete' right
1718 // (and is about to delete this page).
1719 $dbr = wfGetDB( DB_REPLICA );
1720 $revisions = $edits = (int)$dbr->selectField(
1721 'revision',
1722 'COUNT(rev_page)',
1723 [ 'rev_page' => $title->getArticleID() ],
1724 __METHOD__
1725 );
1726
1727 // @todo FIXME: i18n issue/patchwork message
1728 $context->getOutput()->addHTML(
1729 '<strong class="mw-delete-warning-revisions">' .
1730 $context->msg( 'historywarning' )->numParams( $revisions )->parse() .
1731 $context->msg( 'word-separator' )->escaped() . Linker::linkKnown( $title,
1732 $context->msg( 'history' )->escaped(),
1733 [],
1734 [ 'action' => 'history' ] ) .
1735 '</strong>'
1736 );
1737
1738 if ( $title->isBigDeletion() ) {
1740 $context->getOutput()->wrapWikiMsg( "<div class='error'>\n$1\n</div>\n",
1741 [
1742 'delete-warning-toobig',
1743 $context->getLanguage()->formatNum( $wgDeleteRevisionsLimit )
1744 ]
1745 );
1746 }
1747 }
1748
1749 $this->confirmDelete( $reason );
1750 }
1751
1757 public function confirmDelete( $reason ) {
1758 wfDebug( "Article::confirmDelete\n" );
1759
1760 $title = $this->getTitle();
1761 $ctx = $this->getContext();
1762 $outputPage = $ctx->getOutput();
1763 $useMediaWikiUIEverywhere = $ctx->getConfig()->get( 'UseMediaWikiUIEverywhere' );
1764 $outputPage->setPageTitle( wfMessage( 'delete-confirm', $title->getPrefixedText() ) );
1765 $outputPage->addBacklinkSubtitle( $title );
1766 $outputPage->setRobotPolicy( 'noindex,nofollow' );
1767 $backlinkCache = $title->getBacklinkCache();
1768 if ( $backlinkCache->hasLinks( 'pagelinks' ) || $backlinkCache->hasLinks( 'templatelinks' ) ) {
1769 $outputPage->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n",
1770 'deleting-backlinks-warning' );
1771 }
1772 $outputPage->addWikiMsg( 'confirmdeletetext' );
1773
1774 Hooks::run( 'ArticleConfirmDelete', [ $this, $outputPage, &$reason ] );
1775
1776 $user = $this->getContext()->getUser();
1777
1778 if ( $user->isAllowed( 'suppressrevision' ) ) {
1779 $suppress = Html::openElement( 'div', [ 'id' => 'wpDeleteSuppressRow' ] ) .
1780 Xml::checkLabel( wfMessage( 'revdelete-suppress' )->text(),
1781 'wpSuppress', 'wpSuppress', false, [ 'tabindex' => '4' ] ) .
1782 Html::closeElement( 'div' );
1783 } else {
1784 $suppress = '';
1785 }
1786 $checkWatch = $user->getBoolOption( 'watchdeletion' ) || $user->isWatched( $title );
1787
1788 $form = Html::openElement( 'form', [ 'method' => 'post',
1789 'action' => $title->getLocalURL( 'action=delete' ), 'id' => 'deleteconfirm' ] ) .
1790 Html::openElement( 'fieldset', [ 'id' => 'mw-delete-table' ] ) .
1791 Html::element( 'legend', null, wfMessage( 'delete-legend' )->text() ) .
1792 Html::openElement( 'div', [ 'id' => 'mw-deleteconfirm-table' ] ) .
1793 Html::openElement( 'div', [ 'id' => 'wpDeleteReasonListRow' ] ) .
1794 Html::label( wfMessage( 'deletecomment' )->text(), 'wpDeleteReasonList' ) .
1795 '&nbsp;' .
1797 'wpDeleteReasonList',
1798 wfMessage( 'deletereason-dropdown' )->inContentLanguage()->text(),
1799 wfMessage( 'deletereasonotherlist' )->inContentLanguage()->text(),
1800 '',
1801 'wpReasonDropDown',
1802 1
1803 ) .
1804 Html::closeElement( 'div' ) .
1805 Html::openElement( 'div', [ 'id' => 'wpDeleteReasonRow' ] ) .
1806 Html::label( wfMessage( 'deleteotherreason' )->text(), 'wpReason' ) .
1807 '&nbsp;' .
1808 Html::input( 'wpReason', $reason, 'text', [
1809 'size' => '60',
1810 'maxlength' => '255',
1811 'tabindex' => '2',
1812 'id' => 'wpReason',
1813 'class' => 'mw-ui-input-inline',
1814 'autofocus'
1815 ] ) .
1816 Html::closeElement( 'div' );
1817
1818 # Disallow watching if user is not logged in
1819 if ( $user->isLoggedIn() ) {
1820 $form .=
1821 Xml::checkLabel( wfMessage( 'watchthis' )->text(),
1822 'wpWatch', 'wpWatch', $checkWatch, [ 'tabindex' => '3' ] );
1823 }
1824
1825 $form .=
1826 Html::openElement( 'div' ) .
1827 $suppress .
1828 Xml::submitButton( wfMessage( 'deletepage' )->text(),
1829 [
1830 'name' => 'wpConfirmB',
1831 'id' => 'wpConfirmB',
1832 'tabindex' => '5',
1833 'class' => $useMediaWikiUIEverywhere ? 'mw-ui-button mw-ui-destructive' : '',
1834 ]
1835 ) .
1836 Html::closeElement( 'div' ) .
1837 Html::closeElement( 'div' ) .
1838 Xml::closeElement( 'fieldset' ) .
1839 Html::hidden(
1840 'wpEditToken',
1841 $user->getEditToken( [ 'delete', $title->getPrefixedText() ] )
1842 ) .
1843 Xml::closeElement( 'form' );
1844
1845 if ( $user->isAllowed( 'editinterface' ) ) {
1847 $ctx->msg( 'deletereason-dropdown' )->inContentLanguage()->getTitle(),
1848 wfMessage( 'delete-edit-reasonlist' )->escaped(),
1849 [],
1850 [ 'action' => 'edit' ]
1851 );
1852 $form .= '<p class="mw-delete-editreasons">' . $link . '</p>';
1853 }
1854
1855 $outputPage->addHTML( $form );
1856
1857 $deleteLogPage = new LogPage( 'delete' );
1858 $outputPage->addHTML( Xml::element( 'h2', null, $deleteLogPage->getName()->text() ) );
1859 LogEventsList::showLogExtract( $outputPage, 'delete', $title );
1860 }
1861
1867 public function doDelete( $reason, $suppress = false ) {
1868 $error = '';
1869 $context = $this->getContext();
1870 $outputPage = $context->getOutput();
1871 $user = $context->getUser();
1872 $status = $this->mPage->doDeleteArticleReal( $reason, $suppress, 0, true, $error, $user );
1873
1874 if ( $status->isGood() ) {
1875 $deleted = $this->getTitle()->getPrefixedText();
1876
1877 $outputPage->setPageTitle( wfMessage( 'actioncomplete' ) );
1878 $outputPage->setRobotPolicy( 'noindex,nofollow' );
1879
1880 $loglink = '[[Special:Log/delete|' . wfMessage( 'deletionlog' )->text() . ']]';
1881
1882 $outputPage->addWikiMsg( 'deletedtext', wfEscapeWikiText( $deleted ), $loglink );
1883
1884 Hooks::run( 'ArticleDeleteAfterSuccess', [ $this->getTitle(), $outputPage ] );
1885
1886 $outputPage->returnToMain( false );
1887 } else {
1888 $outputPage->setPageTitle(
1889 wfMessage( 'cannotdelete-title',
1890 $this->getTitle()->getPrefixedText() )
1891 );
1892
1893 if ( $error == '' ) {
1894 $outputPage->addWikiText(
1895 "<div class=\"error mw-error-cannotdelete\">\n" . $status->getWikiText() . "\n</div>"
1896 );
1897 $deleteLogPage = new LogPage( 'delete' );
1898 $outputPage->addHTML( Xml::element( 'h2', null, $deleteLogPage->getName()->text() ) );
1899
1901 $outputPage,
1902 'delete',
1903 $this->getTitle()
1904 );
1905 } else {
1906 $outputPage->addHTML( $error );
1907 }
1908 }
1909 }
1910
1911 /* Caching functions */
1912
1920 protected function tryFileCache() {
1921 static $called = false;
1922
1923 if ( $called ) {
1924 wfDebug( "Article::tryFileCache(): called twice!?\n" );
1925 return false;
1926 }
1927
1928 $called = true;
1929 if ( $this->isFileCacheable() ) {
1930 $cache = new HTMLFileCache( $this->getTitle(), 'view' );
1931 if ( $cache->isCacheGood( $this->mPage->getTouched() ) ) {
1932 wfDebug( "Article::tryFileCache(): about to load file\n" );
1933 $cache->loadFromFileCache( $this->getContext() );
1934 return true;
1935 } else {
1936 wfDebug( "Article::tryFileCache(): starting buffer\n" );
1937 ob_start( [ &$cache, 'saveToFileCache' ] );
1938 }
1939 } else {
1940 wfDebug( "Article::tryFileCache(): not cacheable\n" );
1941 }
1942
1943 return false;
1944 }
1945
1951 public function isFileCacheable( $mode = HTMLFileCache::MODE_NORMAL ) {
1952 $cacheable = false;
1953
1954 if ( HTMLFileCache::useFileCache( $this->getContext(), $mode ) ) {
1955 $cacheable = $this->mPage->getId()
1956 && !$this->mRedirectedFrom && !$this->getTitle()->isRedirect();
1957 // Extension may have reason to disable file caching on some pages.
1958 if ( $cacheable ) {
1959 $cacheable = Hooks::run( 'IsFileCacheable', [ &$this ] );
1960 }
1961 }
1962
1963 return $cacheable;
1964 }
1965
1979 public function getParserOutput( $oldid = null, User $user = null ) {
1980 // XXX: bypasses mParserOptions and thus setParserOptions()
1981
1982 if ( $user === null ) {
1983 $parserOptions = $this->getParserOptions();
1984 } else {
1985 $parserOptions = $this->mPage->makeParserOptions( $user );
1986 }
1987
1988 return $this->mPage->getParserOutput( $parserOptions, $oldid );
1989 }
1990
1998 if ( $this->mParserOptions ) {
1999 throw new MWException( "can't change parser options after they have already been set" );
2000 }
2001
2002 // clone, so if $options is modified later, it doesn't confuse the parser cache.
2003 $this->mParserOptions = clone $options;
2004 }
2005
2010 public function getParserOptions() {
2011 if ( !$this->mParserOptions ) {
2012 $this->mParserOptions = $this->mPage->makeParserOptions( $this->getContext() );
2013 }
2014 // Clone to allow modifications of the return value without affecting cache
2015 return clone $this->mParserOptions;
2016 }
2017
2024 public function setContext( $context ) {
2025 $this->mContext = $context;
2026 }
2027
2034 public function getContext() {
2035 if ( $this->mContext instanceof IContextSource ) {
2036 return $this->mContext;
2037 } else {
2038 wfDebug( __METHOD__ . " called and \$mContext is null. " .
2039 "Return RequestContext::getMain(); for sanity\n" );
2040 return RequestContext::getMain();
2041 }
2042 }
2043
2051 public function __get( $fname ) {
2052 if ( property_exists( $this->mPage, $fname ) ) {
2053 # wfWarn( "Access to raw $fname field " . __CLASS__ );
2054 return $this->mPage->$fname;
2055 }
2056 trigger_error( 'Inaccessible property via __get(): ' . $fname, E_USER_NOTICE );
2057 }
2058
2066 public function __set( $fname, $fvalue ) {
2067 if ( property_exists( $this->mPage, $fname ) ) {
2068 # wfWarn( "Access to raw $fname field of " . __CLASS__ );
2069 $this->mPage->$fname = $fvalue;
2070 // Note: extensions may want to toss on new fields
2071 } elseif ( !in_array( $fname, [ 'mContext', 'mPage' ] ) ) {
2072 $this->mPage->$fname = $fvalue;
2073 } else {
2074 trigger_error( 'Inaccessible property via __set(): ' . $fname, E_USER_NOTICE );
2075 }
2076 }
2077
2082 public function checkFlags( $flags ) {
2083 return $this->mPage->checkFlags( $flags );
2084 }
2085
2090 public function checkTouched() {
2091 return $this->mPage->checkTouched();
2092 }
2093
2098 public function clearPreparedEdit() {
2099 $this->mPage->clearPreparedEdit();
2100 }
2101
2106 public function doDeleteArticleReal(
2107 $reason, $suppress = false, $u1 = null, $u2 = null, &$error = '', User $user = null,
2108 $tags = []
2109 ) {
2110 return $this->mPage->doDeleteArticleReal(
2111 $reason, $suppress, $u1, $u2, $error, $user, $tags
2112 );
2113 }
2114
2119 public function doDeleteUpdates( $id, Content $content = null ) {
2120 return $this->mPage->doDeleteUpdates( $id, $content );
2121 }
2122
2129 public function doEdit( $text, $summary, $flags = 0, $baseRevId = false, $user = null ) {
2130 wfDeprecated( __METHOD__, '1.21' );
2131 return $this->mPage->doEdit( $text, $summary, $flags, $baseRevId, $user );
2132 }
2133
2138 public function doEditContent( Content $content, $summary, $flags = 0, $baseRevId = false,
2139 User $user = null, $serialFormat = null
2140 ) {
2141 return $this->mPage->doEditContent( $content, $summary, $flags, $baseRevId,
2142 $user, $serialFormat
2143 );
2144 }
2145
2150 public function doEditUpdates( Revision $revision, User $user, array $options = [] ) {
2151 return $this->mPage->doEditUpdates( $revision, $user, $options );
2152 }
2153
2158 public function doPurge( $flags = WikiPage::PURGE_ALL ) {
2159 return $this->mPage->doPurge( $flags );
2160 }
2161
2166 public function getLastPurgeTimestamp() {
2167 return $this->mPage->getLastPurgeTimestamp();
2168 }
2169
2174 public function doViewUpdates( User $user, $oldid = 0 ) {
2175 $this->mPage->doViewUpdates( $user, $oldid );
2176 }
2177
2182 public function exists() {
2183 return $this->mPage->exists();
2184 }
2185
2190 public function followRedirect() {
2191 return $this->mPage->followRedirect();
2192 }
2193
2198 public function getActionOverrides() {
2199 return $this->mPage->getActionOverrides();
2200 }
2201
2206 public function getAutoDeleteReason( &$hasHistory ) {
2207 return $this->mPage->getAutoDeleteReason( $hasHistory );
2208 }
2209
2214 public function getCategories() {
2215 return $this->mPage->getCategories();
2216 }
2217
2222 public function getComment( $audience = Revision::FOR_PUBLIC, User $user = null ) {
2223 return $this->mPage->getComment( $audience, $user );
2224 }
2225
2230 public function getContentHandler() {
2231 return $this->mPage->getContentHandler();
2232 }
2233
2238 public function getContentModel() {
2239 return $this->mPage->getContentModel();
2240 }
2241
2246 public function getContributors() {
2247 return $this->mPage->getContributors();
2248 }
2249
2254 public function getCreator( $audience = Revision::FOR_PUBLIC, User $user = null ) {
2255 return $this->mPage->getCreator( $audience, $user );
2256 }
2257
2262 public function getDeletionUpdates( Content $content = null ) {
2263 return $this->mPage->getDeletionUpdates( $content );
2264 }
2265
2270 public function getHiddenCategories() {
2271 return $this->mPage->getHiddenCategories();
2272 }
2273
2278 public function getId() {
2279 return $this->mPage->getId();
2280 }
2281
2286 public function getLatest() {
2287 return $this->mPage->getLatest();
2288 }
2289
2294 public function getLinksTimestamp() {
2295 return $this->mPage->getLinksTimestamp();
2296 }
2297
2302 public function getMinorEdit() {
2303 return $this->mPage->getMinorEdit();
2304 }
2305
2310 public function getOldestRevision() {
2311 return $this->mPage->getOldestRevision();
2312 }
2313
2318 public function getRedirectTarget() {
2319 return $this->mPage->getRedirectTarget();
2320 }
2321
2326 public function getRedirectURL( $rt ) {
2327 return $this->mPage->getRedirectURL( $rt );
2328 }
2329
2334 public function getRevision() {
2335 return $this->mPage->getRevision();
2336 }
2337
2343 public function getText( $audience = Revision::FOR_PUBLIC, User $user = null ) {
2344 wfDeprecated( __METHOD__, '1.21' );
2345 return $this->mPage->getText( $audience, $user );
2346 }
2347
2352 public function getTimestamp() {
2353 return $this->mPage->getTimestamp();
2354 }
2355
2360 public function getTouched() {
2361 return $this->mPage->getTouched();
2362 }
2363
2368 public function getUndoContent( Revision $undo, Revision $undoafter = null ) {
2369 return $this->mPage->getUndoContent( $undo, $undoafter );
2370 }
2371
2376 public function getUser( $audience = Revision::FOR_PUBLIC, User $user = null ) {
2377 return $this->mPage->getUser( $audience, $user );
2378 }
2379
2384 public function getUserText( $audience = Revision::FOR_PUBLIC, User $user = null ) {
2385 return $this->mPage->getUserText( $audience, $user );
2386 }
2387
2392 public function hasViewableContent() {
2393 return $this->mPage->hasViewableContent();
2394 }
2395
2400 public function insertOn( $dbw, $pageId = null ) {
2401 return $this->mPage->insertOn( $dbw, $pageId );
2402 }
2403
2408 public function insertProtectNullRevision( $revCommentMsg, array $limit,
2409 array $expiry, $cascade, $reason, $user = null
2410 ) {
2411 return $this->mPage->insertProtectNullRevision( $revCommentMsg, $limit,
2412 $expiry, $cascade, $reason, $user
2413 );
2414 }
2415
2420 public function insertRedirect() {
2421 return $this->mPage->insertRedirect();
2422 }
2423
2428 public function insertRedirectEntry( Title $rt, $oldLatest = null ) {
2429 return $this->mPage->insertRedirectEntry( $rt, $oldLatest );
2430 }
2431
2436 public function isCountable( $editInfo = false ) {
2437 return $this->mPage->isCountable( $editInfo );
2438 }
2439
2444 public function isRedirect() {
2445 return $this->mPage->isRedirect();
2446 }
2447
2452 public function loadFromRow( $data, $from ) {
2453 return $this->mPage->loadFromRow( $data, $from );
2454 }
2455
2460 public function loadPageData( $from = 'fromdb' ) {
2461 $this->mPage->loadPageData( $from );
2462 }
2463
2468 public function lockAndGetLatest() {
2469 return $this->mPage->lockAndGetLatest();
2470 }
2471
2476 public function makeParserOptions( $context ) {
2477 return $this->mPage->makeParserOptions( $context );
2478 }
2479
2484 public function pageDataFromId( $dbr, $id, $options = [] ) {
2485 return $this->mPage->pageDataFromId( $dbr, $id, $options );
2486 }
2487
2492 public function pageDataFromTitle( $dbr, $title, $options = [] ) {
2493 return $this->mPage->pageDataFromTitle( $dbr, $title, $options );
2494 }
2495
2500 public function prepareContentForEdit(
2501 Content $content, $revision = null, User $user = null,
2502 $serialFormat = null, $useCache = true
2503 ) {
2504 return $this->mPage->prepareContentForEdit(
2505 $content, $revision, $user,
2506 $serialFormat, $useCache
2507 );
2508 }
2509
2515 public function prepareTextForEdit( $text, $revid = null, User $user = null ) {
2516 return $this->mPage->prepareTextForEdit( $text, $revid, $user );
2517 }
2518
2523 public function protectDescription( array $limit, array $expiry ) {
2524 return $this->mPage->protectDescription( $limit, $expiry );
2525 }
2526
2531 public function protectDescriptionLog( array $limit, array $expiry ) {
2532 return $this->mPage->protectDescriptionLog( $limit, $expiry );
2533 }
2534
2539 public function replaceSectionAtRev( $sectionId, Content $sectionContent,
2540 $sectionTitle = '', $baseRevId = null
2541 ) {
2542 return $this->mPage->replaceSectionAtRev( $sectionId, $sectionContent,
2543 $sectionTitle, $baseRevId
2544 );
2545 }
2546
2551 public function replaceSectionContent(
2552 $sectionId, Content $sectionContent, $sectionTitle = '', $edittime = null
2553 ) {
2554 return $this->mPage->replaceSectionContent(
2555 $sectionId, $sectionContent, $sectionTitle, $edittime
2556 );
2557 }
2558
2563 public function setTimestamp( $ts ) {
2564 return $this->mPage->setTimestamp( $ts );
2565 }
2566
2571 public function shouldCheckParserCache( ParserOptions $parserOptions, $oldId ) {
2572 return $this->mPage->shouldCheckParserCache( $parserOptions, $oldId );
2573 }
2574
2579 public function supportsSections() {
2580 return $this->mPage->supportsSections();
2581 }
2582
2588 return $this->mPage->triggerOpportunisticLinksUpdate( $parserOutput );
2589 }
2590
2595 public function updateCategoryCounts( array $added, array $deleted, $id = 0 ) {
2596 return $this->mPage->updateCategoryCounts( $added, $deleted, $id );
2597 }
2598
2603 public function updateIfNewerOn( $dbw, $revision ) {
2604 return $this->mPage->updateIfNewerOn( $dbw, $revision );
2605 }
2606
2611 public function updateRedirectOn( $dbw, $redirectTitle, $lastRevIsRedirect = null ) {
2612 return $this->mPage->updateRedirectOn( $dbw, $redirectTitle, $lastRevIsRedirect = null );
2613 }
2614
2619 public function updateRevisionOn( $dbw, $revision, $lastRevision = null,
2620 $lastRevIsRedirect = null
2621 ) {
2622 return $this->mPage->updateRevisionOn( $dbw, $revision, $lastRevision,
2623 $lastRevIsRedirect
2624 );
2625 }
2626
2635 public function doUpdateRestrictions( array $limit, array $expiry, &$cascade,
2636 $reason, User $user
2637 ) {
2638 return $this->mPage->doUpdateRestrictions( $limit, $expiry, $cascade, $reason, $user );
2639 }
2640
2648 public function updateRestrictions( $limit = [], $reason = '',
2649 &$cascade = 0, $expiry = []
2650 ) {
2651 return $this->mPage->doUpdateRestrictions(
2652 $limit,
2653 $expiry,
2654 $cascade,
2655 $reason,
2656 $this->getContext()->getUser()
2657 );
2658 }
2659
2668 public function doDeleteArticle(
2669 $reason, $suppress = false, $u1 = null, $u2 = null, &$error = ''
2670 ) {
2671 return $this->mPage->doDeleteArticle( $reason, $suppress, $u1, $u2, $error );
2672 }
2673
2683 public function doRollback( $fromP, $summary, $token, $bot, &$resultDetails, User $user = null ) {
2684 $user = is_null( $user ) ? $this->getContext()->getUser() : $user;
2685 return $this->mPage->doRollback( $fromP, $summary, $token, $bot, $resultDetails, $user );
2686 }
2687
2696 public function commitRollback( $fromP, $summary, $bot, &$resultDetails, User $guser = null ) {
2697 $guser = is_null( $guser ) ? $this->getContext()->getUser() : $guser;
2698 return $this->mPage->commitRollback( $fromP, $summary, $bot, $resultDetails, $guser );
2699 }
2700
2705 public function generateReason( &$hasHistory ) {
2706 $title = $this->mPage->getTitle();
2708 return $handler->getAutoDeleteReason( $title, $hasHistory );
2709 }
2710
2716 public static function selectFields() {
2717 wfDeprecated( __METHOD__, '1.24' );
2718 return WikiPage::selectFields();
2719 }
2720
2726 public static function onArticleCreate( $title ) {
2727 wfDeprecated( __METHOD__, '1.24' );
2729 }
2730
2736 public static function onArticleDelete( $title ) {
2737 wfDeprecated( __METHOD__, '1.24' );
2739 }
2740
2746 public static function onArticleEdit( $title ) {
2747 wfDeprecated( __METHOD__, '1.24' );
2749 }
2750
2758 public static function getAutosummary( $oldtext, $newtext, $flags ) {
2759 return WikiPage::getAutosummary( $oldtext, $newtext, $flags );
2760 }
2761 // ******
2762}
$wgArticleRobotPolicies
Robot policies per article.
$wgDefaultRobotPolicy
Default robot policy.
$wgSend404Code
Some web hosts attempt to rewrite all responses with a 404 (not found) status code,...
$wgRedirectSources
If local interwikis are set up which allow redirects, set this regexp to restrict URLs which will be ...
$wgUseFilePatrol
Use file patrolling to check new files on Special:Newfiles.
$wgUseRCPatrol
Use RC Patrolling to check for vandalism (from recent changes and watchlists) New pages and new files...
$wgEnableWriteAPI
Allow the API to be used to perform write operations (page edits, rollback, etc.) when an authorised ...
$wgNamespaceRobotPolicies
Robot policies per namespaces.
$wgUseNPPatrol
Use new page patrolling to check new pages on Special:Newpages.
$wgDeleteRevisionsLimit
Optional to restrict deletion of pages with higher revision counts to users with the 'bigdelete' perm...
$wgDebugToolbar
Display the new debugging toolbar.
$wgEnableAPI
Enable the MediaWiki API for convenient access to machine-readable data via api.php.
$wgUseFileCache
This will cache static pages for non-logged-in users to reduce database traffic on public sites.
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfReadOnly()
Check whether the wiki is in read-only mode.
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
wfMemcKey()
Make a cache key for the local wiki.
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
if(!defined( 'MEDIAWIKI')) $fname
This file is not a valid entry point, perform no further processing unless MEDIAWIKI is defined.
Definition Setup.php:36
Class for viewing MediaWiki article and history.
Definition Article.php:34
shouldCheckParserCache(ParserOptions $parserOptions, $oldId)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2571
getRevisionFetched()
Get the fetched Revision object depending on request parameters or null on failure.
Definition Article.php:460
ParserOutput $mParserOutput
Definition Article.php:75
Title $mRedirectedFrom
Title from which we were redirected here.
Definition Article.php:63
updateRedirectOn( $dbw, $redirectTitle, $lastRevIsRedirect=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2611
generateReason(&$hasHistory)
Definition Article.php:2705
checkFlags( $flags)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2082
doDeleteArticleReal( $reason, $suppress=false, $u1=null, $u2=null, &$error='', User $user=null, $tags=[])
Call to WikiPage function for backwards compatibility.
Definition Article.php:2106
checkTouched()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2090
doDelete( $reason, $suppress=false)
Perform a deletion and output success or failure messages.
Definition Article.php:1867
getHiddenCategories()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2270
static newFromWikiPage(WikiPage $page, IContextSource $context)
Create an Article object of the appropriate class for the given page.
Definition Article.php:144
doViewUpdates(User $user, $oldid=0)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2174
getContext()
Gets the context this Article is executed in.
Definition Article.php:2034
static getAutosummary( $oldtext, $newtext, $flags)
Definition Article.php:2758
getCategories()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2214
commitRollback( $fromP, $summary, $bot, &$resultDetails, User $guser=null)
Definition Article.php:2696
getOldIDFromRequest()
Sets $this->mRedirectUrl to a correct URL if the query parameters are incorrect.
Definition Article.php:273
doEditContent(Content $content, $summary, $flags=0, $baseRevId=false, User $user=null, $serialFormat=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2138
getParserOutput( $oldid=null, User $user=null)
#-
Definition Article.php:1979
doEdit( $text, $summary, $flags=0, $baseRevId=false, $user=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2129
insertProtectNullRevision( $revCommentMsg, array $limit, array $expiry, $cascade, $reason, $user=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2408
getRedirectedFrom()
Get the page this view was redirected from.
Definition Article.php:155
getUserText( $audience=Revision::FOR_PUBLIC, User $user=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2384
insertOn( $dbw, $pageId=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2400
updateRevisionOn( $dbw, $revision, $lastRevision=null, $lastRevIsRedirect=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2619
prepareTextForEdit( $text, $revid=null, User $user=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2515
IContextSource $mContext
The context this Article is executed in.
Definition Article.php:36
fetchContentObject()
Get text content object Does NOT follow redirects.
Definition Article.php:371
supportsSections()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2579
string $mContent
Text of the revision we are working on.
Definition Article.php:48
pageDataFromTitle( $dbr, $title, $options=[])
Call to WikiPage function for backwards compatibility.
Definition Article.php:2492
getContentHandler()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2230
updateCategoryCounts(array $added, array $deleted, $id=0)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2595
view()
This is the default action of the index.php entry point: just view the page of the given title.
Definition Article.php:483
loadPageData( $from='fromdb')
Call to WikiPage function for backwards compatibility.
Definition Article.php:2460
getRobotPolicy( $action, $pOutput=null)
Get the robot policy to be used for the current view.
Definition Article.php:831
doUpdateRestrictions(array $limit, array $expiry, &$cascade, $reason, User $user)
Definition Article.php:2635
protectDescriptionLog(array $limit, array $expiry)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2531
clearPreparedEdit()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2098
__construct(Title $title, $oldId=null)
Constructor and clear the article.
Definition Article.php:82
static purgePatrolFooterCache( $articleID)
Purge the cache used to check if it is worth showing the patrol footer For example,...
Definition Article.php:1221
followRedirect()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2190
prepareContentForEdit(Content $content, $revision=null, User $user=null, $serialFormat=null, $useCache=true)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2500
static selectFields()
Definition Article.php:2716
replaceSectionAtRev( $sectionId, Content $sectionContent, $sectionTitle='', $baseRevId=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2539
doPurge( $flags=WikiPage::PURGE_ALL)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2158
getAutoDeleteReason(&$hasHistory)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2206
getLinksTimestamp()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2294
getOldID()
Definition Article.php:260
protectDescription(array $limit, array $expiry)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2523
getOldestRevision()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2310
static onArticleEdit( $title)
Definition Article.php:2746
setTimestamp( $ts)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2563
getTitle()
Get the title object of the article.
Definition Article.php:173
getActionOverrides()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2198
doEditUpdates(Revision $revision, User $user, array $options=[])
Call to WikiPage function for backwards compatibility.
Definition Article.php:2150
getLastPurgeTimestamp()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2166
adjustDisplayTitle(ParserOutput $pOutput)
Adjust title for pages with displaytitle, -{T|}- or language conversion.
Definition Article.php:727
updateIfNewerOn( $dbw, $revision)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2603
getLatest()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2286
pageDataFromId( $dbr, $id, $options=[])
Call to WikiPage function for backwards compatibility.
Definition Article.php:2484
insertRedirect()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2420
doDeleteUpdates( $id, Content $content=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2119
getContributors()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2246
showDeletedRevisionHeader()
If the revision requested for view is deleted, check permissions.
Definition Article.php:1352
isCountable( $editInfo=false)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2436
getParserOptions()
Get parser options suitable for rendering the primary article wikitext.
Definition Article.php:2010
getCreator( $audience=Revision::FOR_PUBLIC, User $user=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2254
clear()
Clear the object.
Definition Article.php:190
getComment( $audience=Revision::FOR_PUBLIC, User $user=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2222
Content $mContentObject
Content of the revision we are working on.
Definition Article.php:54
getContentModel()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2238
static getRedirectHeaderHtml(Language $lang, $target, $forceKnown=false)
Return the HTML for the top of a redirect page.
Definition Article.php:1552
protect()
action=protect handler
Definition Article.php:1614
getText( $audience=Revision::FOR_PUBLIC, User $user=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2343
lockAndGetLatest()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2468
isCurrent()
Returns true if the currently-referenced revision is the current edit to this page (and it exists).
Definition Article.php:444
updateRestrictions( $limit=[], $reason='', &$cascade=0, $expiry=[])
Definition Article.php:2648
showMissingArticle()
Show the error text for a missing article.
Definition Article.php:1230
getUndoContent(Revision $undo, Revision $undoafter=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2368
__set( $fname, $fvalue)
Use PHP's magic __set handler to handle setting of raw WikiPage fields for backwards compatibility.
Definition Article.php:2066
doDeleteArticle( $reason, $suppress=false, $u1=null, $u2=null, &$error='')
Definition Article.php:2668
getId()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2278
unprotect()
action=unprotect handler (alias)
Definition Article.php:1622
int $mRevIdFetched
Revision ID of revision we are working on.
Definition Article.php:69
isRedirect()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2444
static onArticleCreate( $title)
Definition Article.php:2726
newPage(Title $title)
Definition Article.php:91
confirmDelete( $reason)
Output deletion confirmation dialog.
Definition Article.php:1757
getPage()
Get the WikiPage object of this instance.
Definition Article.php:183
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
Definition Article.php:1587
getTouched()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2360
getRevision()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2334
string bool $mRedirectUrl
URL to redirect to or false if none.
Definition Article.php:66
getTimestamp()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2352
static newFromID( $id)
Constructor from a page id.
Definition Article.php:100
getRedirectTarget()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2318
getUser( $audience=Revision::FOR_PUBLIC, User $user=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2376
int null $mOldId
The oldid of the article that is to be shown, 0 for the current revision.
Definition Article.php:60
static formatRobotPolicy( $policy)
Converts a String robot policy into an associative array, to allow merging of several policies using ...
Definition Article.php:911
Revision $mRevision
Revision we are working on.
Definition Article.php:72
viewRedirect( $target, $appendSubtitle=true, $forceKnown=false)
Return the HTML for the top of a redirect page.
Definition Article.php:1530
insertRedirectEntry(Title $rt, $oldLatest=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2428
triggerOpportunisticLinksUpdate(ParserOutput $parserOutput)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2587
static onArticleDelete( $title)
Definition Article.php:2736
makeParserOptions( $context)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2476
showPatrolFooter()
If patrol is possible, output a patrol UI box.
Definition Article.php:1051
setOldSubtitle( $oldid=0)
Generate the navigation links when browsing through an article revisions It shows the information as:...
Definition Article.php:1395
ParserOptions $mParserOptions
ParserOptions object for $wgUser articles.
Definition Article.php:42
showViewFooter()
Show the footer section of an ordinary page view.
Definition Article.php:1028
WikiPage $mPage
The WikiPage object of this instance.
Definition Article.php:39
loadFromRow( $data, $from)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2452
setRedirectedFrom(Title $from)
Tell the page view functions that this view was redirected from another page on the wiki.
Definition Article.php:164
isFileCacheable( $mode=HTMLFileCache::MODE_NORMAL)
Check if the page can be cached.
Definition Article.php:1951
getContent()
Note that getContent does not follow redirects anymore.
Definition Article.php:212
tryFileCache()
checkLastModified returns true if it has taken care of all output to the client that is necessary for...
Definition Article.php:1920
getRevIdFetched()
Use this to fetch the rev ID used on page views.
Definition Article.php:471
replaceSectionContent( $sectionId, Content $sectionContent, $sectionTitle='', $edittime=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2551
showNamespaceHeader()
Show a header specific to the namespace currently being viewed, like [[MediaWiki:Talkpagetext]].
Definition Article.php:1014
__get( $fname)
Use PHP's magic __get handler to handle accessing of raw WikiPage fields for backwards compatibility.
Definition Article.php:2051
static newFromTitle( $title, IContextSource $context)
Create an Article object of the appropriate class for the given page.
Definition Article.php:112
showCssOrJsPage( $showCacheHint=true)
Show a page view for a page formatted as CSS or JavaScript.
Definition Article.php:794
hasViewableContent()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2392
getContentObject()
Returns a Content object representing the pages effective display content, not necessarily the revisi...
Definition Article.php:233
showDiffPage()
Show a diff page according to current request variables.
Definition Article.php:740
getMinorEdit()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2302
setParserOptions(ParserOptions $options)
Override the ParserOptions used to render the primary article wikitext.
Definition Article.php:1997
render()
Handle action=render.
Definition Article.php:1604
showRedirectedFromHeader()
If this request is a redirect view, send "redirected from" subtitle to the output.
Definition Article.php:940
exists()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2182
setContext( $context)
Sets the context this Article is executed in.
Definition Article.php:2024
getRedirectURL( $rt)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2326
bool $mContentLoaded
Is the content ($mContent) already loaded?
Definition Article.php:57
getDeletionUpdates(Content $content=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2262
doRollback( $fromP, $summary, $token, $bot, &$resultDetails, User $user=null)
Definition Article.php:2683
fetchContent()
Get text of an article from database Does NOT follow redirects.
Definition Article.php:333
const TYPE_AUTO
Definition Block.php:81
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:1082
Special handling for category description pages, showing pages, subcategories and file that belong to...
static makeContent( $text, Title $title=null, $modelId=null, $format=null)
Convenience function for creating a Content object from a given textual representation.
static getForTitle(Title $title)
Returns the appropriate ContentHandler singleton for the given title.
static getContentText(Content $content=null)
Convenience function for getting flat text from a Content object.
static runLegacyHooks( $event, $args=[], $deprecatedVersion=null)
Call a legacy hook that uses text instead of Content objects.
getRequest()
Get the WebRequest object.
Page view caching in the file system.
static useFileCache(IContextSource $context, $mode=self::MODE_NORMAL)
Check if pages can be cached for this request/user.
static isValid( $ip)
Validate an IP address.
Definition IP.php:113
Class for viewing MediaWiki file description pages.
Definition ImagePage.php:28
Internationalisation code.
Definition Language.php:35
static link( $target, $html=null, $customAttribs=[], $query=[], $options=[])
This function returns an HTML link to the given target.
Definition Linker.php:203
static linkKnown( $target, $html=null, $customAttribs=[], $query=[], $options=[ 'known'])
Identical to link(), except $options defaults to 'known'.
Definition Linker.php:255
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:1550
static revUserTools( $rev, $isPublic=false)
Generate a user tool link cluster if the current user is allowed to view it.
Definition Linker.php:1141
static makeExternalLink( $url, $text, $escape=true, $linktype='', $attribs=[], $title=null)
Make an external link.
Definition Linker.php:934
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:2103
static showLogExtract(&$out, $types=[], $page='', $user='', $param=[])
Show log extract.
Class to simplify the use of log pages.
Definition LogPage.php:32
MediaWiki exception.
Wrapper allowing us to handle a system message as a Content object.
static singleton()
Get an instance of this object.
Set options of the Parser.
Show an error when a user tries to do something they do not have the necessary permissions for.
Handles the page protection UI and backend.
Show an error when the wiki is locked/read-only and the user tries to do something that requires writ...
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 newFromConds( $conds, $fname=__METHOD__, $dbType=DB_REPLICA)
Find the first recent change matching some specific conditions.
static getMain()
Static methods.
const DELETED_TEXT
Definition Revision.php:85
const DELETED_RESTRICTED
Definition Revision.php:88
const FOR_PUBLIC
Definition Revision.php:92
const FOR_THIS_USER
Definition Revision.php:93
static newFromId( $id, $flags=0)
Load a page revision from a given revision ID number.
Definition Revision.php:110
static makeUrl( $name, $urlaction='')
Definition Skin.php:1085
Represents a title within MediaWiki.
Definition Title.php:36
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition User.php:48
static doWatchOrUnwatch( $watch, Title $title, User $user)
Watch or unwatch a page.
Class representing a MediaWiki article and history.
Definition WikiPage.php:32
static onArticleEdit(Title $title, Revision $revision=null)
Purge caches on page update etc.
const PURGE_ALL
Definition WikiPage.php:89
static getAutosummary( $oldtext, $newtext, $flags)
Return an applicable autosummary if one exists for the given edit.
static onArticleDelete(Title $title)
Clears caches when article is deleted.
static selectFields()
Return the list of revision fields that should be selected to create a new page.
Definition WikiPage.php:281
static onArticleCreate(Title $title)
The onArticle*() functions are supposed to be a kind of hooks which should be called whenever any of ...
static closeElement( $element)
Shortcut to close an XML element.
Definition Xml.php:118
static openElement( $element, $attribs=null)
This opens an XML element.
Definition Xml.php:109
static submitButton( $value, $attribs=[])
Convenience function to build an HTML submit button When $wgUseMediaWikiUIEverywhere is true it will ...
Definition Xml.php:460
static checkLabel( $label, $name, $id, $checked=false, $attribs=[])
Convenience function to build an HTML checkbox with a label.
Definition Xml.php:420
static element( $element, $attribs=null, $contents='', $allowShortTag=true)
Format an XML element with given attributes and, optionally, text content.
Definition Xml.php:39
static listDropDown( $name='', $list='', $other='', $selected='', $class='', $tabindex=null)
Build a drop-down box from a textual list.
Definition Xml.php:508
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
when a variable name is used in a it is silently declared as a new local masking the global
Definition design.txt:95
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:18
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
const NS_USER
Definition Defines.php:58
const NS_FILE
Definition Defines.php:62
const NS_MEDIAWIKI
Definition Defines.php:64
const RC_LOG
Definition Defines.php:138
const NS_MEDIA
Definition Defines.php:44
const NS_USER_TALK
Definition Defines.php:59
const NS_CATEGORY
Definition Defines.php:70
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:1049
the array() calling protocol came about after MediaWiki 1.4rc1.
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:249
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:1090
namespace and then decline to actually register it file or subcat img or subcat $title
Definition hooks.txt:986
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:1096
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:1094
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 unset offset - wrap String Wrap the message in html(usually something like "&lt;div ...>$1&lt;/div>"). - flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException':Called before an exception(or PHP error) is logged. This is meant for integration with external error aggregation services
null for the local wiki Added in
Definition hooks.txt:1558
it s the revision text itself In either if gzip is the revision text is gzipped $flags
Definition hooks.txt:2710
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 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 false for true for descending in case the handler function wants to provide a converted Content object Note that $result getContentModel() must return $toModel. 'CustomEditor' $rcid is used in generating this variable which contains information about the new such as the revision s whether the revision was marked as a minor edit or etc which include things like revision author revision RevisionDelete link and more some of which may have been injected with the DiffRevisionTools hook $nextlink
Definition hooks.txt:1213
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 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 false for true for descending in case the handler function wants to provide a converted Content object Note that $result getContentModel() must return $toModel. 'CustomEditor' $rcid is used in generating this variable which contains information about the new such as the revision s whether the revision was marked as a minor edit or not
Definition hooks.txt:1207
error also a ContextSource you ll probably need to make sure the header is varied on $request
Definition hooks.txt:2685
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 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:1135
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:886
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:1957
usually copyright or history_copyright This message must be in HTML not wikitext & $link
Definition hooks.txt:2900
namespace are movable Hooks may change this value to override the return value of MWNamespace::isMovable(). 'NewDifferenceEngine' 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:2513
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 prev or next refreshes the diff cache $unhide
Definition hooks.txt:1597
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
namespace are movable Hooks may change this value to override the return value of MWNamespace::isMovable(). 'NewDifferenceEngine' 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:2534
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:925
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:1595
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:1734
returning false will NOT prevent logging $e
Definition hooks.txt:2110
$from
if(count( $args)==0) $dir
if( $limit) $timestamp
$summary
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:37
Base interface for content objects.
Definition Content.php:34
Interface for objects which can provide a MediaWiki context on request.
Interface for type hinting (accepts WikiPage, Article, ImagePage, CategoryPage)
Definition Page.php:24
$context
Definition load.php:50
$cache
Definition mcc.php:33
const DB_REPLICA
Definition defines.php:22
if(!isset( $args[0])) $lang