MediaWiki REL1_27
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 # @todo FIXME: Doesn't inherit right
103 return $t == null ? null : new self( $t );
104 # return $t == null ? null : new static( $t ); // PHP 5.3
105 }
106
114 public static function newFromTitle( $title, IContextSource $context ) {
115 if ( NS_MEDIA == $title->getNamespace() ) {
116 // FIXME: where should this go?
117 $title = Title::makeTitle( NS_FILE, $title->getDBkey() );
118 }
119
120 $page = null;
121 Hooks::run( 'ArticleFromTitle', [ &$title, &$page, $context ] );
122 if ( !$page ) {
123 switch ( $title->getNamespace() ) {
124 case NS_FILE:
125 $page = new ImagePage( $title );
126 break;
127 case NS_CATEGORY:
128 $page = new CategoryPage( $title );
129 break;
130 default:
131 $page = new Article( $title );
132 }
133 }
134 $page->setContext( $context );
135
136 return $page;
137 }
138
147 $article = self::newFromTitle( $page->getTitle(), $context );
148 $article->mPage = $page; // override to keep process cached vars
149 return $article;
150 }
151
157 public function setRedirectedFrom( Title $from ) {
158 $this->mRedirectedFrom = $from;
159 }
160
166 public function getTitle() {
167 return $this->mPage->getTitle();
168 }
169
176 public function getPage() {
177 return $this->mPage;
178 }
179
183 public function clear() {
184 $this->mContentLoaded = false;
185
186 $this->mRedirectedFrom = null; # Title object if set
187 $this->mRevIdFetched = 0;
188 $this->mRedirectUrl = false;
189
190 $this->mPage->clear();
191 }
192
205 public function getContent() {
206 ContentHandler::deprecated( __METHOD__, '1.21' );
207 $content = $this->getContentObject();
209 }
210
226 protected function getContentObject() {
227
228 if ( $this->mPage->getId() === 0 ) {
229 # If this is a MediaWiki:x message, then load the messages
230 # and return the message value for x.
231 if ( $this->getTitle()->getNamespace() == NS_MEDIAWIKI ) {
232 $text = $this->getTitle()->getDefaultMessageText();
233 if ( $text === false ) {
234 $text = '';
235 }
236
237 $content = ContentHandler::makeContent( $text, $this->getTitle() );
238 } else {
239 $message = $this->getContext()->getUser()->isLoggedIn() ? 'noarticletext' : 'noarticletextanon';
240 $content = new MessageContent( $message, null, 'parsemag' );
241 }
242 } else {
243 $this->fetchContentObject();
245 }
246
247 return $content;
248 }
249
253 public function getOldID() {
254 if ( is_null( $this->mOldId ) ) {
255 $this->mOldId = $this->getOldIDFromRequest();
256 }
257
258 return $this->mOldId;
259 }
260
266 public function getOldIDFromRequest() {
267 $this->mRedirectUrl = false;
268
269 $request = $this->getContext()->getRequest();
270 $oldid = $request->getIntOrNull( 'oldid' );
271
272 if ( $oldid === null ) {
273 return 0;
274 }
275
276 if ( $oldid !== 0 ) {
277 # Load the given revision and check whether the page is another one.
278 # In that case, update this instance to reflect the change.
279 if ( $oldid === $this->mPage->getLatest() ) {
280 $this->mRevision = $this->mPage->getRevision();
281 } else {
282 $this->mRevision = Revision::newFromId( $oldid );
283 if ( $this->mRevision !== null ) {
284 // Revision title doesn't match the page title given?
285 if ( $this->mPage->getId() != $this->mRevision->getPage() ) {
286 $function = [ get_class( $this->mPage ), 'newFromID' ];
287 $this->mPage = call_user_func( $function, $this->mRevision->getPage() );
288 }
289 }
290 }
291 }
292
293 if ( $request->getVal( 'direction' ) == 'next' ) {
294 $nextid = $this->getTitle()->getNextRevisionID( $oldid );
295 if ( $nextid ) {
296 $oldid = $nextid;
297 $this->mRevision = null;
298 } else {
299 $this->mRedirectUrl = $this->getTitle()->getFullURL( 'redirect=no' );
300 }
301 } elseif ( $request->getVal( 'direction' ) == 'prev' ) {
302 $previd = $this->getTitle()->getPreviousRevisionID( $oldid );
303 if ( $previd ) {
304 $oldid = $previd;
305 $this->mRevision = null;
306 }
307 }
308
309 return $oldid;
310 }
311
326 function fetchContent() {
327 // BC cruft!
328
329 ContentHandler::deprecated( __METHOD__, '1.21' );
330
331 if ( $this->mContentLoaded && $this->mContent ) {
332 return $this->mContent;
333 }
334
335 $content = $this->fetchContentObject();
336
337 if ( !$content ) {
338 return false;
339 }
340
341 // @todo Get rid of mContent everywhere!
342 $this->mContent = ContentHandler::getContentText( $content );
343
344 // Avoid PHP 7.1 warning of passing $this by reference
345 $articlePage = $this;
346 ContentHandler::runLegacyHooks( 'ArticleAfterFetchContent', [ &$articlePage, &$this->mContent ] );
347
348 return $this->mContent;
349 }
350
363 protected function fetchContentObject() {
364 if ( $this->mContentLoaded ) {
366 }
367
368 $this->mContentLoaded = true;
369 $this->mContent = null;
370
371 $oldid = $this->getOldID();
372
373 # Pre-fill content with error message so that if something
374 # fails we'll have something telling us what we intended.
375 // XXX: this isn't page content but a UI message. horrible.
376 $this->mContentObject = new MessageContent( 'missing-revision', [ $oldid ] );
377
378 if ( $oldid ) {
379 # $this->mRevision might already be fetched by getOldIDFromRequest()
380 if ( !$this->mRevision ) {
381 $this->mRevision = Revision::newFromId( $oldid );
382 if ( !$this->mRevision ) {
383 wfDebug( __METHOD__ . " failed to retrieve specified revision, id $oldid\n" );
384 return false;
385 }
386 }
387 } else {
388 $oldid = $this->mPage->getLatest();
389 if ( !$oldid ) {
390 wfDebug( __METHOD__ . " failed to find page data for title " .
391 $this->getTitle()->getPrefixedText() . "\n" );
392 return false;
393 }
394
395 # Update error message with correct oldid
396 $this->mContentObject = new MessageContent( 'missing-revision', [ $oldid ] );
397
398 $this->mRevision = $this->mPage->getRevision();
399
400 if ( !$this->mRevision ) {
401 wfDebug( __METHOD__ . " failed to retrieve current page, rev_id $oldid\n" );
402 return false;
403 }
404 }
405
406 // @todo FIXME: Horrible, horrible! This content-loading interface just plain sucks.
407 // We should instead work with the Revision object when we need it...
408 // Loads if user is allowed
409 $content = $this->mRevision->getContent(
411 $this->getContext()->getUser()
412 );
413
414 if ( !$content ) {
415 wfDebug( __METHOD__ . " failed to retrieve content of revision " .
416 $this->mRevision->getId() . "\n" );
417 return false;
418 }
419
420 $this->mContentObject = $content;
421 $this->mRevIdFetched = $this->mRevision->getId();
422
423 // Avoid PHP 7.1 warning of passing $this by reference
424 $articlePage = $this;
425 Hooks::run( 'ArticleAfterFetchContentObject', [ &$articlePage, &$this->mContentObject ] );
426
428 }
429
435 public function isCurrent() {
436 # If no oldid, this is the current version.
437 if ( $this->getOldID() == 0 ) {
438 return true;
439 }
440
441 return $this->mPage->exists() && $this->mRevision && $this->mRevision->isCurrent();
442 }
443
451 public function getRevisionFetched() {
452 $this->fetchContentObject();
453
454 return $this->mRevision;
455 }
456
462 public function getRevIdFetched() {
463 if ( $this->mRevIdFetched ) {
465 } else {
466 return $this->mPage->getLatest();
467 }
468 }
469
474 public function view() {
476
477 # Get variables from query string
478 # As side effect this will load the revision and update the title
479 # in a revision ID is passed in the request, so this should remain
480 # the first call of this method even if $oldid is used way below.
481 $oldid = $this->getOldID();
482
483 $user = $this->getContext()->getUser();
484 # Another whitelist check in case getOldID() is altering the title
485 $permErrors = $this->getTitle()->getUserPermissionsErrors( 'read', $user );
486 if ( count( $permErrors ) ) {
487 wfDebug( __METHOD__ . ": denied on secondary read check\n" );
488 throw new PermissionsError( 'read', $permErrors );
489 }
490
491 $outputPage = $this->getContext()->getOutput();
492 # getOldID() may as well want us to redirect somewhere else
493 if ( $this->mRedirectUrl ) {
494 $outputPage->redirect( $this->mRedirectUrl );
495 wfDebug( __METHOD__ . ": redirecting due to oldid\n" );
496
497 return;
498 }
499
500 # If we got diff in the query, we want to see a diff page instead of the article.
501 if ( $this->getContext()->getRequest()->getCheck( 'diff' ) ) {
502 wfDebug( __METHOD__ . ": showing diff page\n" );
503 $this->showDiffPage();
504
505 return;
506 }
507
508 # Set page title (may be overridden by DISPLAYTITLE)
509 $outputPage->setPageTitle( $this->getTitle()->getPrefixedText() );
510
511 $outputPage->setArticleFlag( true );
512 # Allow frames by default
513 $outputPage->allowClickjacking();
514
515 $parserCache = ParserCache::singleton();
516
517 $parserOptions = $this->getParserOptions();
518 # Render printable version, use printable version cache
519 if ( $outputPage->isPrintable() ) {
520 $parserOptions->setIsPrintable( true );
521 $parserOptions->setEditSection( false );
522 } elseif ( !$this->isCurrent() || !$this->getTitle()->quickUserCan( 'edit', $user ) ) {
523 $parserOptions->setEditSection( false );
524 }
525
526 # Try client and file cache
527 if ( !$wgDebugToolbar && $oldid === 0 && $this->mPage->checkTouched() ) {
528 if ( $wgUseETag ) {
529 $outputPage->setETag( $parserCache->getETag( $this->mPage, $parserOptions ) );
530 }
531
532 # Use the greatest of the page's timestamp or the timestamp of any
533 # redirect in the chain (bug 67849)
534 $timestamp = $this->mPage->getTouched();
535 if ( isset( $this->mRedirectedFrom ) ) {
536 $timestamp = max( $timestamp, $this->mRedirectedFrom->getTouched() );
537
538 # If there can be more than one redirect in the chain, we have
539 # to go through the whole chain too in case an intermediate
540 # redirect was changed.
541 if ( $wgMaxRedirects > 1 ) {
542 $titles = Revision::newFromTitle( $this->mRedirectedFrom )
543 ->getContent( Revision::FOR_THIS_USER, $user )
544 ->getRedirectChain();
545 $thisTitle = $this->getTitle();
546 foreach ( $titles as $title ) {
547 if ( Title::compare( $title, $thisTitle ) === 0 ) {
548 break;
549 }
550 $timestamp = max( $timestamp, $title->getTouched() );
551 }
552 }
553 }
554
555 # Is it client cached?
556 if ( $outputPage->checkLastModified( $timestamp ) ) {
557 wfDebug( __METHOD__ . ": done 304\n" );
558
559 return;
560 # Try file cache
561 } elseif ( $wgUseFileCache && $this->tryFileCache() ) {
562 wfDebug( __METHOD__ . ": done file cache\n" );
563 # tell wgOut that output is taken care of
564 $outputPage->disable();
565 $this->mPage->doViewUpdates( $user, $oldid );
566
567 return;
568 }
569 }
570
571 # Should the parser cache be used?
572 $useParserCache = $this->mPage->shouldCheckParserCache( $parserOptions, $oldid );
573 wfDebug( 'Article::view using parser cache: ' . ( $useParserCache ? 'yes' : 'no' ) . "\n" );
574 if ( $user->getStubThreshold() ) {
575 $this->getContext()->getStats()->increment( 'pcache_miss_stub' );
576 }
577
579 $this->showNamespaceHeader();
580
581 # Iterate through the possible ways of constructing the output text.
582 # Keep going until $outputDone is set, or we run out of things to do.
583 $pass = 0;
584 $outputDone = false;
585 $this->mParserOutput = false;
586
587 while ( !$outputDone && ++$pass ) {
588 switch ( $pass ) {
589 case 1:
590 // Avoid PHP 7.1 warning of passing $this by reference
591 $articlePage = $this;
592 Hooks::run( 'ArticleViewHeader', [ &$articlePage, &$outputDone, &$useParserCache ] );
593 break;
594 case 2:
595 # Early abort if the page doesn't exist
596 if ( !$this->mPage->exists() ) {
597 wfDebug( __METHOD__ . ": showing missing article\n" );
598 $this->showMissingArticle();
599 $this->mPage->doViewUpdates( $user );
600 return;
601 }
602
603 # Try the parser cache
604 if ( $useParserCache ) {
605 $this->mParserOutput = $parserCache->get( $this->mPage, $parserOptions );
606
607 if ( $this->mParserOutput !== false ) {
608 if ( $oldid ) {
609 wfDebug( __METHOD__ . ": showing parser cache contents for current rev permalink\n" );
610 $this->setOldSubtitle( $oldid );
611 } else {
612 wfDebug( __METHOD__ . ": showing parser cache contents\n" );
613 }
614 $outputPage->addParserOutput( $this->mParserOutput );
615 # Ensure that UI elements requiring revision ID have
616 # the correct version information.
617 $outputPage->setRevisionId( $this->mPage->getLatest() );
618 # Preload timestamp to avoid a DB hit
619 $cachedTimestamp = $this->mParserOutput->getTimestamp();
620 if ( $cachedTimestamp !== null ) {
621 $outputPage->setRevisionTimestamp( $cachedTimestamp );
622 $this->mPage->setTimestamp( $cachedTimestamp );
623 }
624 $outputDone = true;
625 }
626 }
627 break;
628 case 3:
629 # This will set $this->mRevision if needed
630 $this->fetchContentObject();
631
632 # Are we looking at an old revision
633 if ( $oldid && $this->mRevision ) {
634 $this->setOldSubtitle( $oldid );
635
636 if ( !$this->showDeletedRevisionHeader() ) {
637 wfDebug( __METHOD__ . ": cannot view deleted revision\n" );
638 return;
639 }
640 }
641
642 # Ensure that UI elements requiring revision ID have
643 # the correct version information.
644 $outputPage->setRevisionId( $this->getRevIdFetched() );
645 # Preload timestamp to avoid a DB hit
646 $outputPage->setRevisionTimestamp( $this->mPage->getTimestamp() );
647
648 # Pages containing custom CSS or JavaScript get special treatment
649 if ( $this->getTitle()->isCssOrJsPage() || $this->getTitle()->isCssJsSubpage() ) {
650 wfDebug( __METHOD__ . ": showing CSS/JS source\n" );
651 $this->showCssOrJsPage();
652 $outputDone = true;
653 } elseif ( !Hooks::run( 'ArticleContentViewCustom',
654 [ $this->fetchContentObject(), $this->getTitle(), $outputPage ] ) ) {
655
656 # Allow extensions do their own custom view for certain pages
657 $outputDone = true;
658 } elseif ( !ContentHandler::runLegacyHooks( 'ArticleViewCustom',
659 [ $this->fetchContentObject(), $this->getTitle(), $outputPage ] ) ) {
660
661 # Allow extensions do their own custom view for certain pages
662 $outputDone = true;
663 }
664 break;
665 case 4:
666 # Run the parse, protected by a pool counter
667 wfDebug( __METHOD__ . ": doing uncached parse\n" );
668
669 $content = $this->getContentObject();
670 $poolArticleView = new PoolWorkArticleView( $this->getPage(), $parserOptions,
671 $this->getRevIdFetched(), $useParserCache, $content );
672
673 if ( !$poolArticleView->execute() ) {
674 $error = $poolArticleView->getError();
675 if ( $error ) {
676 $outputPage->clearHTML(); // for release() errors
677 $outputPage->enableClientCache( false );
678 $outputPage->setRobotPolicy( 'noindex,nofollow' );
679
680 $errortext = $error->getWikiText( false, 'view-pool-error' );
681 $outputPage->addWikiText( '<div class="errorbox">' . $errortext . '</div>' );
682 }
683 # Connection or timeout error
684 return;
685 }
686
687 $this->mParserOutput = $poolArticleView->getParserOutput();
688 $outputPage->addParserOutput( $this->mParserOutput );
689 if ( $content->getRedirectTarget() ) {
690 $outputPage->addSubtitle( "<span id=\"redirectsub\">" .
691 $this->getContext()->msg( 'redirectpagesub' )->parse() . "</span>" );
692 }
693
694 # Don't cache a dirty ParserOutput object
695 if ( $poolArticleView->getIsDirty() ) {
696 $outputPage->setCdnMaxage( 0 );
697 $outputPage->addHTML( "<!-- parser cache is expired, " .
698 "sending anyway due to pool overload-->\n" );
699 }
700
701 $outputDone = true;
702 break;
703 # Should be unreachable, but just in case...
704 default:
705 break 2;
706 }
707 }
708
709 # Get the ParserOutput actually *displayed* here.
710 # Note that $this->mParserOutput is the *current*/oldid version output.
711 $pOutput = ( $outputDone instanceof ParserOutput )
712 ? $outputDone // object fetched by hook
714
715 # Adjust title for main page & pages with displaytitle
716 if ( $pOutput ) {
717 $this->adjustDisplayTitle( $pOutput );
718 }
719
720 # For the main page, overwrite the <title> element with the con-
721 # tents of 'pagetitle-view-mainpage' instead of the default (if
722 # that's not empty).
723 # This message always exists because it is in the i18n files
724 if ( $this->getTitle()->isMainPage() ) {
725 $msg = wfMessage( 'pagetitle-view-mainpage' )->inContentLanguage();
726 if ( !$msg->isDisabled() ) {
727 $outputPage->setHTMLTitle( $msg->title( $this->getTitle() )->text() );
728 }
729 }
730
731 # Check for any __NOINDEX__ tags on the page using $pOutput
732 $policy = $this->getRobotPolicy( 'view', $pOutput );
733 $outputPage->setIndexPolicy( $policy['index'] );
734 $outputPage->setFollowPolicy( $policy['follow'] );
735
736 $this->showViewFooter();
737 $this->mPage->doViewUpdates( $user, $oldid );
738
739 $outputPage->addModules( 'mediawiki.action.view.postEdit' );
740
741 }
742
747 public function adjustDisplayTitle( ParserOutput $pOutput ) {
748 # Adjust the title if it was set by displaytitle, -{T|}- or language conversion
749 $titleText = $pOutput->getTitleText();
750 if ( strval( $titleText ) !== '' ) {
751 $this->getContext()->getOutput()->setPageTitle( $titleText );
752 }
753 }
754
760 protected function showDiffPage() {
761 $request = $this->getContext()->getRequest();
762 $user = $this->getContext()->getUser();
763 $diff = $request->getVal( 'diff' );
764 $rcid = $request->getVal( 'rcid' );
765 $diffOnly = $request->getBool( 'diffonly', $user->getOption( 'diffonly' ) );
766 $purge = $request->getVal( 'action' ) == 'purge';
767 $unhide = $request->getInt( 'unhide' ) == 1;
768 $oldid = $this->getOldID();
769
770 $rev = $this->getRevisionFetched();
771
772 if ( !$rev ) {
773 $this->getContext()->getOutput()->setPageTitle( wfMessage( 'errorpagetitle' ) );
774 $msg = $this->getContext()->msg( 'difference-missing-revision' )
775 ->params( $oldid )
776 ->numParams( 1 )
777 ->parseAsBlock();
778 $this->getContext()->getOutput()->addHTML( $msg );
779 return;
780 }
781
782 $contentHandler = $rev->getContentHandler();
783 $de = $contentHandler->createDifferenceEngine(
784 $this->getContext(),
785 $oldid,
786 $diff,
787 $rcid,
788 $purge,
789 $unhide
790 );
791
792 // DifferenceEngine directly fetched the revision:
793 $this->mRevIdFetched = $de->mNewid;
794 $de->showDiffPage( $diffOnly );
795
796 // Run view updates for the newer revision being diffed (and shown
797 // below the diff if not $diffOnly).
798 list( $old, $new ) = $de->mapDiffPrevNext( $oldid, $diff );
799 // New can be false, convert it to 0 - this conveniently means the latest revision
800 $this->mPage->doViewUpdates( $user, (int)$new );
801 }
802
814 protected function showCssOrJsPage( $showCacheHint = true ) {
815 $outputPage = $this->getContext()->getOutput();
816
817 if ( $showCacheHint ) {
818 $dir = $this->getContext()->getLanguage()->getDir();
819 $lang = $this->getContext()->getLanguage()->getHtmlCode();
820
821 $outputPage->wrapWikiMsg(
822 "<div id='mw-clearyourcache' lang='$lang' dir='$dir' class='mw-content-$dir'>\n$1\n</div>",
823 'clearyourcache'
824 );
825 }
826
827 $this->fetchContentObject();
828
829 if ( $this->mContentObject ) {
830 // Give hooks a chance to customise the output
832 'ShowRawCssJs',
833 [ $this->mContentObject, $this->getTitle(), $outputPage ] )
834 ) {
835 // If no legacy hooks ran, display the content of the parser output, including RL modules,
836 // but excluding metadata like categories and language links
837 $po = $this->mContentObject->getParserOutput( $this->getTitle() );
838 $outputPage->addParserOutputContent( $po );
839 }
840 }
841 }
842
850 public function getRobotPolicy( $action, $pOutput = null ) {
852
853 $ns = $this->getTitle()->getNamespace();
854
855 # Don't index user and user talk pages for blocked users (bug 11443)
856 if ( ( $ns == NS_USER || $ns == NS_USER_TALK ) && !$this->getTitle()->isSubpage() ) {
857 $specificTarget = null;
858 $vagueTarget = null;
859 $titleText = $this->getTitle()->getText();
860 if ( IP::isValid( $titleText ) ) {
861 $vagueTarget = $titleText;
862 } else {
863 $specificTarget = $titleText;
864 }
865 if ( Block::newFromTarget( $specificTarget, $vagueTarget ) instanceof Block ) {
866 return [
867 'index' => 'noindex',
868 'follow' => 'nofollow'
869 ];
870 }
871 }
872
873 if ( $this->mPage->getId() === 0 || $this->getOldID() ) {
874 # Non-articles (special pages etc), and old revisions
875 return [
876 'index' => 'noindex',
877 'follow' => 'nofollow'
878 ];
879 } elseif ( $this->getContext()->getOutput()->isPrintable() ) {
880 # Discourage indexing of printable versions, but encourage following
881 return [
882 'index' => 'noindex',
883 'follow' => 'follow'
884 ];
885 } elseif ( $this->getContext()->getRequest()->getInt( 'curid' ) ) {
886 # For ?curid=x urls, disallow indexing
887 return [
888 'index' => 'noindex',
889 'follow' => 'follow'
890 ];
891 }
892
893 # Otherwise, construct the policy based on the various config variables.
895
896 if ( isset( $wgNamespaceRobotPolicies[$ns] ) ) {
897 # Honour customised robot policies for this namespace
898 $policy = array_merge(
899 $policy,
900 self::formatRobotPolicy( $wgNamespaceRobotPolicies[$ns] )
901 );
902 }
903 if ( $this->getTitle()->canUseNoindex() && is_object( $pOutput ) && $pOutput->getIndexPolicy() ) {
904 # __INDEX__ and __NOINDEX__ magic words, if allowed. Incorporates
905 # a final sanity check that we have really got the parser output.
906 $policy = array_merge(
907 $policy,
908 [ 'index' => $pOutput->getIndexPolicy() ]
909 );
910 }
911
912 if ( isset( $wgArticleRobotPolicies[$this->getTitle()->getPrefixedText()] ) ) {
913 # (bug 14900) site config can override user-defined __INDEX__ or __NOINDEX__
914 $policy = array_merge(
915 $policy,
916 self::formatRobotPolicy( $wgArticleRobotPolicies[$this->getTitle()->getPrefixedText()] )
917 );
918 }
919
920 return $policy;
921 }
922
930 public static function formatRobotPolicy( $policy ) {
931 if ( is_array( $policy ) ) {
932 return $policy;
933 } elseif ( !$policy ) {
934 return [];
935 }
936
937 $policy = explode( ',', $policy );
938 $policy = array_map( 'trim', $policy );
939
940 $arr = [];
941 foreach ( $policy as $var ) {
942 if ( in_array( $var, [ 'index', 'noindex' ] ) ) {
943 $arr['index'] = $var;
944 } elseif ( in_array( $var, [ 'follow', 'nofollow' ] ) ) {
945 $arr['follow'] = $var;
946 }
947 }
948
949 return $arr;
950 }
951
959 public function showRedirectedFromHeader() {
961
962 $context = $this->getContext();
963 $outputPage = $context->getOutput();
965 $rdfrom = $request->getVal( 'rdfrom' );
966
967 // Construct a URL for the current page view, but with the target title
968 $query = $request->getValues();
969 unset( $query['rdfrom'] );
970 unset( $query['title'] );
971 if ( $this->getTitle()->isRedirect() ) {
972 // Prevent double redirects
973 $query['redirect'] = 'no';
974 }
975 $redirectTargetUrl = $this->getTitle()->getLinkURL( $query );
976
977 if ( isset( $this->mRedirectedFrom ) ) {
978 // Avoid PHP 7.1 warning of passing $this by reference
979 $articlePage = $this;
980
981 // This is an internally redirected page view.
982 // We'll need a backlink to the source page for navigation.
983 if ( Hooks::run( 'ArticleViewRedirect', [ &$articlePage ] ) ) {
984 $redir = Linker::linkKnown(
985 $this->mRedirectedFrom,
986 null,
987 [],
988 [ 'redirect' => 'no' ]
989 );
990
991 $outputPage->addSubtitle( "<span class=\"mw-redirectedfrom\">" .
992 $context->msg( 'redirectedfrom' )->rawParams( $redir )->parse()
993 . "</span>" );
994
995 // Add the script to update the displayed URL and
996 // set the fragment if one was specified in the redirect
997 $outputPage->addJsConfigVars( [
998 'wgInternalRedirectTargetUrl' => $redirectTargetUrl,
999 ] );
1000 $outputPage->addModules( 'mediawiki.action.view.redirect' );
1001
1002 // Add a <link rel="canonical"> tag
1003 $outputPage->setCanonicalUrl( $this->getTitle()->getCanonicalURL() );
1004
1005 // Tell the output object that the user arrived at this article through a redirect
1006 $outputPage->setRedirectedFrom( $this->mRedirectedFrom );
1007
1008 return true;
1009 }
1010 } elseif ( $rdfrom ) {
1011 // This is an externally redirected view, from some other wiki.
1012 // If it was reported from a trusted site, supply a backlink.
1013 if ( $wgRedirectSources && preg_match( $wgRedirectSources, $rdfrom ) ) {
1014 $redir = Linker::makeExternalLink( $rdfrom, $rdfrom );
1015 $outputPage->addSubtitle( "<span class=\"mw-redirectedfrom\">" .
1016 $context->msg( 'redirectedfrom' )->rawParams( $redir )->parse()
1017 . "</span>" );
1018
1019 // Add the script to update the displayed URL
1020 $outputPage->addJsConfigVars( [
1021 'wgInternalRedirectTargetUrl' => $redirectTargetUrl,
1022 ] );
1023 $outputPage->addModules( 'mediawiki.action.view.redirect' );
1024
1025 return true;
1026 }
1027 }
1028
1029 return false;
1030 }
1031
1036 public function showNamespaceHeader() {
1037 if ( $this->getTitle()->isTalkPage() ) {
1038 if ( !wfMessage( 'talkpageheader' )->isDisabled() ) {
1039 $this->getContext()->getOutput()->wrapWikiMsg(
1040 "<div class=\"mw-talkpageheader\">\n$1\n</div>",
1041 [ 'talkpageheader' ]
1042 );
1043 }
1044 }
1045 }
1046
1050 public function showViewFooter() {
1051 # check if we're displaying a [[User talk:x.x.x.x]] anonymous talk page
1052 if ( $this->getTitle()->getNamespace() == NS_USER_TALK
1053 && IP::isValid( $this->getTitle()->getText() )
1054 ) {
1055 $this->getContext()->getOutput()->addWikiMsg( 'anontalkpagetext' );
1056 }
1057
1058 // Show a footer allowing the user to patrol the shown revision or page if possible
1059 $patrolFooterShown = $this->showPatrolFooter();
1060
1061 Hooks::run( 'ArticleViewFooter', [ $this, $patrolFooterShown ] );
1062 }
1063
1073 public function showPatrolFooter() {
1075
1076 $outputPage = $this->getContext()->getOutput();
1077 $user = $this->getContext()->getUser();
1078 $title = $this->getTitle();
1079 $rc = false;
1080
1081 if ( !$title->quickUserCan( 'patrol', $user )
1083 || ( $wgUseFilePatrol && $title->inNamespace( NS_FILE ) ) )
1084 ) {
1085 // Patrolling is disabled or the user isn't allowed to
1086 return false;
1087 }
1088
1089 if ( $this->mRevision
1090 && !RecentChange::isInRCLifespan( $this->mRevision->getTimestamp(), 21600 )
1091 ) {
1092 // The current revision is already older than what could be in the RC table
1093 // 6h tolerance because the RC might not be cleaned out regularly
1094 return false;
1095 }
1096
1097 // Check for cached results
1098 $key = wfMemcKey( 'unpatrollable-page', $title->getArticleID() );
1100 if ( $cache->get( $key ) ) {
1101 return false;
1102 }
1103
1104 $dbr = wfGetDB( DB_SLAVE );
1105 $oldestRevisionTimestamp = $dbr->selectField(
1106 'revision',
1107 'MIN( rev_timestamp )',
1108 [ 'rev_page' => $title->getArticleID() ],
1109 __METHOD__
1110 );
1111
1112 // New page patrol: Get the timestamp of the oldest revison which
1113 // the revision table holds for the given page. Then we look
1114 // whether it's within the RC lifespan and if it is, we try
1115 // to get the recentchanges row belonging to that entry
1116 // (with rc_new = 1).
1117 $recentPageCreation = false;
1118 if ( $oldestRevisionTimestamp
1119 && RecentChange::isInRCLifespan( $oldestRevisionTimestamp, 21600 )
1120 ) {
1121 // 6h tolerance because the RC might not be cleaned out regularly
1122 $recentPageCreation = true;
1124 [
1125 'rc_new' => 1,
1126 'rc_timestamp' => $oldestRevisionTimestamp,
1127 'rc_namespace' => $title->getNamespace(),
1128 'rc_cur_id' => $title->getArticleID()
1129 ],
1130 __METHOD__
1131 );
1132 if ( $rc ) {
1133 // Use generic patrol message for new pages
1134 $markPatrolledMsg = wfMessage( 'markaspatrolledtext' );
1135 }
1136 }
1137
1138 // File patrol: Get the timestamp of the latest upload for this page,
1139 // check whether it is within the RC lifespan and if it is, we try
1140 // to get the recentchanges row belonging to that entry
1141 // (with rc_type = RC_LOG, rc_log_type = upload).
1142 $recentFileUpload = false;
1143 if ( ( !$rc || $rc->getAttribute( 'rc_patrolled' ) ) && $wgUseFilePatrol
1144 && $title->getNamespace() === NS_FILE ) {
1145 // Retrieve timestamp of most recent upload
1146 $newestUploadTimestamp = $dbr->selectField(
1147 'image',
1148 'MAX( img_timestamp )',
1149 [ 'img_name' => $title->getDBkey() ],
1150 __METHOD__
1151 );
1152 if ( $newestUploadTimestamp
1153 && RecentChange::isInRCLifespan( $newestUploadTimestamp, 21600 )
1154 ) {
1155 // 6h tolerance because the RC might not be cleaned out regularly
1156 $recentFileUpload = true;
1158 [
1159 'rc_type' => RC_LOG,
1160 'rc_log_type' => 'upload',
1161 'rc_timestamp' => $newestUploadTimestamp,
1162 'rc_namespace' => NS_FILE,
1163 'rc_cur_id' => $title->getArticleID()
1164 ],
1165 __METHOD__
1166 );
1167 if ( $rc ) {
1168 // Use patrol message specific to files
1169 $markPatrolledMsg = wfMessage( 'markaspatrolledtext-file' );
1170 }
1171 }
1172 }
1173
1174 if ( !$recentPageCreation && !$recentFileUpload ) {
1175 // Page creation and latest upload (for files) is too old to be in RC
1176
1177 // We definitely can't patrol so cache the information
1178 // When a new file version is uploaded, the cache is cleared
1179 $cache->set( $key, '1' );
1180
1181 return false;
1182 }
1183
1184 if ( !$rc ) {
1185 // Don't cache: This can be hit if the page gets accessed very fast after
1186 // its creation / latest upload or in case we have high slave lag. In case
1187 // the revision is too old, we will already return above.
1188 return false;
1189 }
1190
1191 if ( $rc->getAttribute( 'rc_patrolled' ) ) {
1192 // Patrolled RC entry around
1193
1194 // Cache the information we gathered above in case we can't patrol
1195 // Don't cache in case we can patrol as this could change
1196 $cache->set( $key, '1' );
1197
1198 return false;
1199 }
1200
1201 if ( $rc->getPerformer()->equals( $user ) ) {
1202 // Don't show a patrol link for own creations/uploads. If the user could
1203 // patrol them, they already would be patrolled
1204 return false;
1205 }
1206
1207 $rcid = $rc->getAttribute( 'rc_id' );
1208
1209 $token = $user->getEditToken( $rcid );
1210
1211 $outputPage->preventClickjacking();
1212 if ( $wgEnableAPI && $wgEnableWriteAPI && $user->isAllowed( 'writeapi' ) ) {
1213 $outputPage->addModules( 'mediawiki.page.patrol.ajax' );
1214 }
1215
1217 $title,
1218 $markPatrolledMsg->escaped(),
1219 [],
1220 [
1221 'action' => 'markpatrolled',
1222 'rcid' => $rcid,
1223 'token' => $token,
1224 ]
1225 );
1226
1227 $outputPage->addHTML(
1228 "<div class='patrollink' data-mw='interface'>" .
1229 wfMessage( 'markaspatrolledlink' )->rawParams( $link )->escaped() .
1230 '</div>'
1231 );
1232
1233 return true;
1234 }
1235
1242 public static function purgePatrolFooterCache( $articleID ) {
1244 $cache->delete( wfMemcKey( 'unpatrollable-page', $articleID ) );
1245 }
1246
1251 public function showMissingArticle() {
1253
1254 $outputPage = $this->getContext()->getOutput();
1255 // Whether the page is a root user page of an existing user (but not a subpage)
1256 $validUserPage = false;
1257
1258 $title = $this->getTitle();
1259
1260 # Show info in user (talk) namespace. Does the user exist? Is he blocked?
1261 if ( $title->getNamespace() == NS_USER
1262 || $title->getNamespace() == NS_USER_TALK
1263 ) {
1264 $rootPart = explode( '/', $title->getText() )[0];
1265 $user = User::newFromName( $rootPart, false /* allow IP users*/ );
1266 $ip = User::isIP( $rootPart );
1267 $block = Block::newFromTarget( $user, $user );
1268
1269 if ( !( $user && $user->isLoggedIn() ) && !$ip ) { # User does not exist
1270 $outputPage->wrapWikiMsg( "<div class=\"mw-userpage-userdoesnotexist error\">\n\$1\n</div>",
1271 [ 'userpage-userdoesnotexist-view', wfEscapeWikiText( $rootPart ) ] );
1272 } elseif ( !is_null( $block ) && $block->getType() != Block::TYPE_AUTO ) {
1273 # Show log extract if the user is currently blocked
1275 $outputPage,
1276 'block',
1277 MWNamespace::getCanonicalName( NS_USER ) . ':' . $block->getTarget(),
1278 '',
1279 [
1280 'lim' => 1,
1281 'showIfEmpty' => false,
1282 'msgKey' => [
1283 'blocked-notice-logextract',
1284 $user->getName() # Support GENDER in notice
1285 ]
1286 ]
1287 );
1288 $validUserPage = !$title->isSubpage();
1289 } else {
1290 $validUserPage = !$title->isSubpage();
1291 }
1292 }
1293
1294 Hooks::run( 'ShowMissingArticle', [ $this ] );
1295
1296 # Show delete and move logs if there were any such events.
1297 # The logging query can DOS the site when bots/crawlers cause 404 floods,
1298 # so be careful showing this. 404 pages must be cheap as they are hard to cache.
1300 $key = wfMemcKey( 'page-recent-delete', md5( $title->getPrefixedText() ) );
1301 $loggedIn = $this->getContext()->getUser()->isLoggedIn();
1302 if ( $loggedIn || $cache->get( $key ) ) {
1303 $logTypes = [ 'delete', 'move' ];
1304 $conds = [ "log_action != 'revision'" ];
1305 // Give extensions a chance to hide their (unrelated) log entries
1306 Hooks::run( 'Article::MissingArticleConditions', [ &$conds, $logTypes ] );
1308 $outputPage,
1309 $logTypes,
1310 $title,
1311 '',
1312 [
1313 'lim' => 10,
1314 'conds' => $conds,
1315 'showIfEmpty' => false,
1316 'msgKey' => [ $loggedIn
1317 ? 'moveddeleted-notice'
1318 : 'moveddeleted-notice-recent'
1319 ]
1320 ]
1321 );
1322 }
1323
1324 if ( !$this->mPage->hasViewableContent() && $wgSend404Code && !$validUserPage ) {
1325 // If there's no backing content, send a 404 Not Found
1326 // for better machine handling of broken links.
1327 $this->getContext()->getRequest()->response()->statusHeader( 404 );
1328 }
1329
1330 // Also apply the robot policy for nonexisting pages (even if a 404 was used for sanity)
1331 $policy = $this->getRobotPolicy( 'view' );
1332 $outputPage->setIndexPolicy( $policy['index'] );
1333 $outputPage->setFollowPolicy( $policy['follow'] );
1334
1335 $hookResult = Hooks::run( 'BeforeDisplayNoArticleText', [ $this ] );
1336
1337 if ( !$hookResult ) {
1338 return;
1339 }
1340
1341 # Show error message
1342 $oldid = $this->getOldID();
1343 if ( !$oldid && $title->getNamespace() === NS_MEDIAWIKI && $title->hasSourceText() ) {
1344 $outputPage->addParserOutput( $this->getContentObject()->getParserOutput( $title ) );
1345 } else {
1346 if ( $oldid ) {
1347 $text = wfMessage( 'missing-revision', $oldid )->plain();
1348 } elseif ( $title->quickUserCan( 'create', $this->getContext()->getUser() )
1349 && $title->quickUserCan( 'edit', $this->getContext()->getUser() )
1350 ) {
1351 $message = $this->getContext()->getUser()->isLoggedIn() ? 'noarticletext' : 'noarticletextanon';
1352 $text = wfMessage( $message )->plain();
1353 } else {
1354 $text = wfMessage( 'noarticletext-nopermission' )->plain();
1355 }
1356
1357 $dir = $this->getContext()->getLanguage()->getDir();
1358 $lang = $this->getContext()->getLanguage()->getCode();
1359 $outputPage->addWikiText( Xml::openElement( 'div', [
1360 'class' => "noarticletext mw-content-$dir",
1361 'dir' => $dir,
1362 'lang' => $lang,
1363 ] ) . "\n$text\n</div>" );
1364 }
1365 }
1366
1373 public function showDeletedRevisionHeader() {
1374 if ( !$this->mRevision->isDeleted( Revision::DELETED_TEXT ) ) {
1375 // Not deleted
1376 return true;
1377 }
1378
1379 $outputPage = $this->getContext()->getOutput();
1380 $user = $this->getContext()->getUser();
1381 // If the user is not allowed to see it...
1382 if ( !$this->mRevision->userCan( Revision::DELETED_TEXT, $user ) ) {
1383 $outputPage->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n",
1384 'rev-deleted-text-permission' );
1385
1386 return false;
1387 // If the user needs to confirm that they want to see it...
1388 } elseif ( $this->getContext()->getRequest()->getInt( 'unhide' ) != 1 ) {
1389 # Give explanation and add a link to view the revision...
1390 $oldid = intval( $this->getOldID() );
1391 $link = $this->getTitle()->getFullURL( "oldid={$oldid}&unhide=1" );
1392 $msg = $this->mRevision->isDeleted( Revision::DELETED_RESTRICTED ) ?
1393 'rev-suppressed-text-unhide' : 'rev-deleted-text-unhide';
1394 $outputPage->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n",
1395 [ $msg, $link ] );
1396
1397 return false;
1398 // We are allowed to see...
1399 } else {
1400 $msg = $this->mRevision->isDeleted( Revision::DELETED_RESTRICTED ) ?
1401 'rev-suppressed-text-view' : 'rev-deleted-text-view';
1402 $outputPage->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n", $msg );
1403
1404 return true;
1405 }
1406 }
1407
1416 public function setOldSubtitle( $oldid = 0 ) {
1417 // Avoid PHP 7.1 warning of passing $this by reference
1418 $articlePage = $this;
1419
1420 if ( !Hooks::run( 'DisplayOldSubtitle', [ &$articlePage, &$oldid ] ) ) {
1421 return;
1422 }
1423
1424 $context = $this->getContext();
1425 $unhide = $context->getRequest()->getInt( 'unhide' ) == 1;
1426
1427 # Cascade unhide param in links for easy deletion browsing
1428 $extraParams = [];
1429 if ( $unhide ) {
1430 $extraParams['unhide'] = 1;
1431 }
1432
1433 if ( $this->mRevision && $this->mRevision->getId() === $oldid ) {
1434 $revision = $this->mRevision;
1435 } else {
1436 $revision = Revision::newFromId( $oldid );
1437 }
1438
1439 $timestamp = $revision->getTimestamp();
1440
1441 $current = ( $oldid == $this->mPage->getLatest() );
1442 $language = $context->getLanguage();
1443 $user = $context->getUser();
1444
1445 $td = $language->userTimeAndDate( $timestamp, $user );
1446 $tddate = $language->userDate( $timestamp, $user );
1447 $tdtime = $language->userTime( $timestamp, $user );
1448
1449 # Show user links if allowed to see them. If hidden, then show them only if requested...
1450 $userlinks = Linker::revUserTools( $revision, !$unhide );
1451
1452 $infomsg = $current && !$context->msg( 'revision-info-current' )->isDisabled()
1453 ? 'revision-info-current'
1454 : 'revision-info';
1455
1456 $outputPage = $context->getOutput();
1457 $outputPage->addSubtitle( "<div id=\"mw-{$infomsg}\">" .
1458 $context->msg( $infomsg, $td )
1459 ->rawParams( $userlinks )
1460 ->params( $revision->getId(), $tddate, $tdtime, $revision->getUserText() )
1461 ->rawParams( Linker::revComment( $revision, true, true ) )
1462 ->parse() .
1463 "</div>"
1464 );
1465
1466 $lnk = $current
1467 ? $context->msg( 'currentrevisionlink' )->escaped()
1469 $this->getTitle(),
1470 $context->msg( 'currentrevisionlink' )->escaped(),
1471 [],
1472 $extraParams
1473 );
1474 $curdiff = $current
1475 ? $context->msg( 'diff' )->escaped()
1477 $this->getTitle(),
1478 $context->msg( 'diff' )->escaped(),
1479 [],
1480 [
1481 'diff' => 'cur',
1482 'oldid' => $oldid
1483 ] + $extraParams
1484 );
1485 $prev = $this->getTitle()->getPreviousRevisionID( $oldid );
1486 $prevlink = $prev
1488 $this->getTitle(),
1489 $context->msg( 'previousrevision' )->escaped(),
1490 [],
1491 [
1492 'direction' => 'prev',
1493 'oldid' => $oldid
1494 ] + $extraParams
1495 )
1496 : $context->msg( 'previousrevision' )->escaped();
1497 $prevdiff = $prev
1499 $this->getTitle(),
1500 $context->msg( 'diff' )->escaped(),
1501 [],
1502 [
1503 'diff' => 'prev',
1504 'oldid' => $oldid
1505 ] + $extraParams
1506 )
1507 : $context->msg( 'diff' )->escaped();
1508 $nextlink = $current
1509 ? $context->msg( 'nextrevision' )->escaped()
1511 $this->getTitle(),
1512 $context->msg( 'nextrevision' )->escaped(),
1513 [],
1514 [
1515 'direction' => 'next',
1516 'oldid' => $oldid
1517 ] + $extraParams
1518 );
1519 $nextdiff = $current
1520 ? $context->msg( 'diff' )->escaped()
1522 $this->getTitle(),
1523 $context->msg( 'diff' )->escaped(),
1524 [],
1525 [
1526 'diff' => 'next',
1527 'oldid' => $oldid
1528 ] + $extraParams
1529 );
1530
1531 $cdel = Linker::getRevDeleteLink( $user, $revision, $this->getTitle() );
1532 if ( $cdel !== '' ) {
1533 $cdel .= ' ';
1534 }
1535
1536 $outputPage->addSubtitle( "<div id=\"mw-revision-nav\">" . $cdel .
1537 $context->msg( 'revision-nav' )->rawParams(
1538 $prevdiff, $prevlink, $lnk, $curdiff, $nextlink, $nextdiff
1539 )->escaped() . "</div>" );
1540 }
1541
1553 public function viewRedirect( $target, $appendSubtitle = true, $forceKnown = false ) {
1554 $lang = $this->getTitle()->getPageLanguage();
1555 $out = $this->getContext()->getOutput();
1556 if ( $appendSubtitle ) {
1557 $out->addSubtitle( wfMessage( 'redirectpagesub' ) );
1558 }
1559 $out->addModuleStyles( 'mediawiki.action.view.redirectPage' );
1560 return static::getRedirectHeaderHtml( $lang, $target, $forceKnown );
1561 }
1562
1575 public static function getRedirectHeaderHtml( Language $lang, $target, $forceKnown = false ) {
1576 if ( !is_array( $target ) ) {
1577 $target = [ $target ];
1578 }
1579
1580 $html = '<ul class="redirectText">';
1582 foreach ( $target as $title ) {
1583 $html .= '<li>' . Linker::link(
1584 $title,
1585 htmlspecialchars( $title->getFullText() ),
1586 [],
1587 // Make sure wiki page redirects are not followed
1588 $title->isRedirect() ? [ 'redirect' => 'no' ] : [],
1589 ( $forceKnown ? [ 'known', 'noclasses' ] : [] )
1590 ) . '</li>';
1591 }
1592 $html .= '</ul>';
1593
1594 $redirectToText = wfMessage( 'redirectto' )->inLanguage( $lang )->escaped();
1595
1596 return '<div class="redirectMsg">' .
1597 '<p>' . $redirectToText . '</p>' .
1598 $html .
1599 '</div>';
1600 }
1601
1610 public function addHelpLink( $to, $overrideBaseUrl = false ) {
1611 $msg = wfMessage(
1612 'namespace-' . $this->getTitle()->getNamespace() . '-helppage'
1613 );
1614
1615 $out = $this->getContext()->getOutput();
1616 if ( !$msg->isDisabled() ) {
1617 $helpUrl = Skin::makeUrl( $msg->plain() );
1618 $out->addHelpLink( $helpUrl, true );
1619 } else {
1620 $out->addHelpLink( $to, $overrideBaseUrl );
1621 }
1622 }
1623
1627 public function render() {
1628 $this->getContext()->getRequest()->response()->header( 'X-Robots-Tag: noindex' );
1629 $this->getContext()->getOutput()->setArticleBodyOnly( true );
1630 $this->getContext()->getOutput()->enableSectionEditLinks( false );
1631 $this->view();
1632 }
1633
1637 public function protect() {
1638 $form = new ProtectionForm( $this );
1639 $form->execute();
1640 }
1641
1645 public function unprotect() {
1646 $this->protect();
1647 }
1648
1652 public function delete() {
1653 # This code desperately needs to be totally rewritten
1654
1655 $title = $this->getTitle();
1656 $context = $this->getContext();
1657 $user = $context->getUser();
1659
1660 # Check permissions
1661 $permissionErrors = $title->getUserPermissionsErrors( 'delete', $user );
1662 if ( count( $permissionErrors ) ) {
1663 throw new PermissionsError( 'delete', $permissionErrors );
1664 }
1665
1666 # Read-only check...
1667 if ( wfReadOnly() ) {
1668 throw new ReadOnlyError;
1669 }
1670
1671 # Better double-check that it hasn't been deleted yet!
1672 $this->mPage->loadPageData(
1674 );
1675 if ( !$this->mPage->exists() ) {
1676 $deleteLogPage = new LogPage( 'delete' );
1677 $outputPage = $context->getOutput();
1678 $outputPage->setPageTitle( $context->msg( 'cannotdelete-title', $title->getPrefixedText() ) );
1679 $outputPage->wrapWikiMsg( "<div class=\"error mw-error-cannotdelete\">\n$1\n</div>",
1680 [ 'cannotdelete', wfEscapeWikiText( $title->getPrefixedText() ) ]
1681 );
1682 $outputPage->addHTML(
1683 Xml::element( 'h2', null, $deleteLogPage->getName()->text() )
1684 );
1686 $outputPage,
1687 'delete',
1688 $title
1689 );
1690
1691 return;
1692 }
1693
1694 $deleteReasonList = $request->getText( 'wpDeleteReasonList', 'other' );
1695 $deleteReason = $request->getText( 'wpReason' );
1696
1697 if ( $deleteReasonList == 'other' ) {
1698 $reason = $deleteReason;
1699 } elseif ( $deleteReason != '' ) {
1700 // Entry from drop down menu + additional comment
1701 $colonseparator = wfMessage( 'colon-separator' )->inContentLanguage()->text();
1702 $reason = $deleteReasonList . $colonseparator . $deleteReason;
1703 } else {
1704 $reason = $deleteReasonList;
1705 }
1706
1707 if ( $request->wasPosted() && $user->matchEditToken( $request->getVal( 'wpEditToken' ),
1708 [ 'delete', $this->getTitle()->getPrefixedText() ] )
1709 ) {
1710 # Flag to hide all contents of the archived revisions
1711 $suppress = $request->getVal( 'wpSuppress' ) && $user->isAllowed( 'suppressrevision' );
1712
1713 $this->doDelete( $reason, $suppress );
1714
1715 WatchAction::doWatchOrUnwatch( $request->getCheck( 'wpWatch' ), $title, $user );
1716
1717 return;
1718 }
1719
1720 // Generate deletion reason
1721 $hasHistory = false;
1722 if ( !$reason ) {
1723 try {
1724 $reason = $this->generateReason( $hasHistory );
1725 } catch ( Exception $e ) {
1726 # if a page is horribly broken, we still want to be able to
1727 # delete it. So be lenient about errors here.
1728 wfDebug( "Error while building auto delete summary: $e" );
1729 $reason = '';
1730 }
1731 }
1732
1733 // If the page has a history, insert a warning
1734 if ( $hasHistory ) {
1735 $title = $this->getTitle();
1736
1737 // The following can use the real revision count as this is only being shown for users
1738 // that can delete this page.
1739 // This, as a side-effect, also makes sure that the following query isn't being run for
1740 // pages with a larger history, unless the user has the 'bigdelete' right
1741 // (and is about to delete this page).
1742 $dbr = wfGetDB( DB_SLAVE );
1743 $revisions = $edits = (int)$dbr->selectField(
1744 'revision',
1745 'COUNT(rev_page)',
1746 [ 'rev_page' => $title->getArticleID() ],
1747 __METHOD__
1748 );
1749
1750 // @todo FIXME: i18n issue/patchwork message
1751 $context->getOutput()->addHTML(
1752 '<strong class="mw-delete-warning-revisions">' .
1753 $context->msg( 'historywarning' )->numParams( $revisions )->parse() .
1754 $context->msg( 'word-separator' )->escaped() . Linker::linkKnown( $title,
1755 $context->msg( 'history' )->escaped(),
1756 [],
1757 [ 'action' => 'history' ] ) .
1758 '</strong>'
1759 );
1760
1761 if ( $title->isBigDeletion() ) {
1763 $context->getOutput()->wrapWikiMsg( "<div class='error'>\n$1\n</div>\n",
1764 [
1765 'delete-warning-toobig',
1766 $context->getLanguage()->formatNum( $wgDeleteRevisionsLimit )
1767 ]
1768 );
1769 }
1770 }
1771
1772 $this->confirmDelete( $reason );
1773 }
1774
1780 public function confirmDelete( $reason ) {
1781 wfDebug( "Article::confirmDelete\n" );
1782
1783 $title = $this->getTitle();
1784 $ctx = $this->getContext();
1785 $outputPage = $ctx->getOutput();
1786 $useMediaWikiUIEverywhere = $ctx->getConfig()->get( 'UseMediaWikiUIEverywhere' );
1787 $outputPage->setPageTitle( wfMessage( 'delete-confirm', $title->getPrefixedText() ) );
1788 $outputPage->addBacklinkSubtitle( $title );
1789 $outputPage->setRobotPolicy( 'noindex,nofollow' );
1790 $backlinkCache = $title->getBacklinkCache();
1791 if ( $backlinkCache->hasLinks( 'pagelinks' ) || $backlinkCache->hasLinks( 'templatelinks' ) ) {
1792 $outputPage->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n",
1793 'deleting-backlinks-warning' );
1794 }
1795 $outputPage->addWikiMsg( 'confirmdeletetext' );
1796
1797 Hooks::run( 'ArticleConfirmDelete', [ $this, $outputPage, &$reason ] );
1798
1799 $user = $this->getContext()->getUser();
1800
1801 if ( $user->isAllowed( 'suppressrevision' ) ) {
1802 $suppress = Html::openElement( 'div', [ 'id' => 'wpDeleteSuppressRow' ] ) .
1803 Xml::checkLabel( wfMessage( 'revdelete-suppress' )->text(),
1804 'wpSuppress', 'wpSuppress', false, [ 'tabindex' => '4' ] ) .
1805 Html::closeElement( 'div' );
1806 } else {
1807 $suppress = '';
1808 }
1809 $checkWatch = $user->getBoolOption( 'watchdeletion' ) || $user->isWatched( $title );
1810
1811 $form = Html::openElement( 'form', [ 'method' => 'post',
1812 'action' => $title->getLocalURL( 'action=delete' ), 'id' => 'deleteconfirm' ] ) .
1813 Html::openElement( 'fieldset', [ 'id' => 'mw-delete-table' ] ) .
1814 Html::element( 'legend', null, wfMessage( 'delete-legend' )->text() ) .
1815 Html::openElement( 'div', [ 'id' => 'mw-deleteconfirm-table' ] ) .
1816 Html::openElement( 'div', [ 'id' => 'wpDeleteReasonListRow' ] ) .
1817 Html::label( wfMessage( 'deletecomment' )->text(), 'wpDeleteReasonList' ) .
1818 '&nbsp;' .
1820 'wpDeleteReasonList',
1821 wfMessage( 'deletereason-dropdown' )->inContentLanguage()->text(),
1822 wfMessage( 'deletereasonotherlist' )->inContentLanguage()->text(),
1823 '',
1824 'wpReasonDropDown',
1825 1
1826 ) .
1827 Html::closeElement( 'div' ) .
1828 Html::openElement( 'div', [ 'id' => 'wpDeleteReasonRow' ] ) .
1829 Html::label( wfMessage( 'deleteotherreason' )->text(), 'wpReason' ) .
1830 '&nbsp;' .
1831 Html::input( 'wpReason', $reason, 'text', [
1832 'size' => '60',
1833 'maxlength' => '255',
1834 'tabindex' => '2',
1835 'id' => 'wpReason',
1836 'class' => 'mw-ui-input-inline',
1837 'autofocus'
1838 ] ) .
1839 Html::closeElement( 'div' );
1840
1841 # Disallow watching if user is not logged in
1842 if ( $user->isLoggedIn() ) {
1843 $form .=
1844 Xml::checkLabel( wfMessage( 'watchthis' )->text(),
1845 'wpWatch', 'wpWatch', $checkWatch, [ 'tabindex' => '3' ] );
1846 }
1847
1848 $form .=
1849 Html::openElement( 'div' ) .
1850 $suppress .
1851 Xml::submitButton( wfMessage( 'deletepage' )->text(),
1852 [
1853 'name' => 'wpConfirmB',
1854 'id' => 'wpConfirmB',
1855 'tabindex' => '5',
1856 'class' => $useMediaWikiUIEverywhere ? 'mw-ui-button mw-ui-destructive' : '',
1857 ]
1858 ) .
1859 Html::closeElement( 'div' ) .
1860 Html::closeElement( 'div' ) .
1861 Xml::closeElement( 'fieldset' ) .
1863 'wpEditToken',
1864 $user->getEditToken( [ 'delete', $title->getPrefixedText() ] )
1865 ) .
1866 Xml::closeElement( 'form' );
1867
1868 if ( $user->isAllowed( 'editinterface' ) ) {
1870 $ctx->msg( 'deletereason-dropdown' )->inContentLanguage()->getTitle(),
1871 wfMessage( 'delete-edit-reasonlist' )->escaped(),
1872 [],
1873 [ 'action' => 'edit' ]
1874 );
1875 $form .= '<p class="mw-delete-editreasons">' . $link . '</p>';
1876 }
1877
1878 $outputPage->addHTML( $form );
1879
1880 $deleteLogPage = new LogPage( 'delete' );
1881 $outputPage->addHTML( Xml::element( 'h2', null, $deleteLogPage->getName()->text() ) );
1882 LogEventsList::showLogExtract( $outputPage, 'delete', $title );
1883 }
1884
1890 public function doDelete( $reason, $suppress = false ) {
1891 $error = '';
1892 $context = $this->getContext();
1893 $outputPage = $context->getOutput();
1894 $user = $context->getUser();
1895 $status = $this->mPage->doDeleteArticleReal( $reason, $suppress, 0, true, $error, $user );
1896
1897 if ( $status->isGood() ) {
1898 $deleted = $this->getTitle()->getPrefixedText();
1899
1900 $outputPage->setPageTitle( wfMessage( 'actioncomplete' ) );
1901 $outputPage->setRobotPolicy( 'noindex,nofollow' );
1902
1903 $loglink = '[[Special:Log/delete|' . wfMessage( 'deletionlog' )->text() . ']]';
1904
1905 $outputPage->addWikiMsg( 'deletedtext', wfEscapeWikiText( $deleted ), $loglink );
1906
1907 Hooks::run( 'ArticleDeleteAfterSuccess', [ $this->getTitle(), $outputPage ] );
1908
1909 $outputPage->returnToMain( false );
1910 } else {
1911 $outputPage->setPageTitle(
1912 wfMessage( 'cannotdelete-title',
1913 $this->getTitle()->getPrefixedText() )
1914 );
1915
1916 if ( $error == '' ) {
1917 $outputPage->addWikiText(
1918 "<div class=\"error mw-error-cannotdelete\">\n" . $status->getWikiText() . "\n</div>"
1919 );
1920 $deleteLogPage = new LogPage( 'delete' );
1921 $outputPage->addHTML( Xml::element( 'h2', null, $deleteLogPage->getName()->text() ) );
1922
1924 $outputPage,
1925 'delete',
1926 $this->getTitle()
1927 );
1928 } else {
1929 $outputPage->addHTML( $error );
1930 }
1931 }
1932 }
1933
1934 /* Caching functions */
1935
1943 protected function tryFileCache() {
1944 static $called = false;
1945
1946 if ( $called ) {
1947 wfDebug( "Article::tryFileCache(): called twice!?\n" );
1948 return false;
1949 }
1950
1951 $called = true;
1952 if ( $this->isFileCacheable() ) {
1953 $cache = new HTMLFileCache( $this->getTitle(), 'view' );
1954 if ( $cache->isCacheGood( $this->mPage->getTouched() ) ) {
1955 wfDebug( "Article::tryFileCache(): about to load file\n" );
1956 $cache->loadFromFileCache( $this->getContext() );
1957 return true;
1958 } else {
1959 wfDebug( "Article::tryFileCache(): starting buffer\n" );
1960 ob_start( [ &$cache, 'saveToFileCache' ] );
1961 }
1962 } else {
1963 wfDebug( "Article::tryFileCache(): not cacheable\n" );
1964 }
1965
1966 return false;
1967 }
1968
1973 public function isFileCacheable() {
1974 $cacheable = false;
1975
1976 if ( HTMLFileCache::useFileCache( $this->getContext() ) ) {
1977 $cacheable = $this->mPage->getId()
1978 && !$this->mRedirectedFrom && !$this->getTitle()->isRedirect();
1979 // Extension may have reason to disable file caching on some pages.
1980 if ( $cacheable ) {
1981 // Avoid PHP 7.1 warning of passing $this by reference
1982 $articlePage = $this;
1983 $cacheable = Hooks::run( 'IsFileCacheable', [ &$articlePage ] );
1984 }
1985 }
1986
1987 return $cacheable;
1988 }
1989
2003 public function getParserOutput( $oldid = null, User $user = null ) {
2004 // XXX: bypasses mParserOptions and thus setParserOptions()
2005
2006 if ( $user === null ) {
2007 $parserOptions = $this->getParserOptions();
2008 } else {
2009 $parserOptions = $this->mPage->makeParserOptions( $user );
2010 }
2011
2012 return $this->mPage->getParserOutput( $parserOptions, $oldid );
2013 }
2014
2022 if ( $this->mParserOptions ) {
2023 throw new MWException( "can't change parser options after they have already been set" );
2024 }
2025
2026 // clone, so if $options is modified later, it doesn't confuse the parser cache.
2027 $this->mParserOptions = clone $options;
2028 }
2029
2034 public function getParserOptions() {
2035 if ( !$this->mParserOptions ) {
2036 $this->mParserOptions = $this->mPage->makeParserOptions( $this->getContext() );
2037 }
2038 // Clone to allow modifications of the return value without affecting cache
2039 return clone $this->mParserOptions;
2040 }
2041
2048 public function setContext( $context ) {
2049 $this->mContext = $context;
2050 }
2051
2058 public function getContext() {
2059 if ( $this->mContext instanceof IContextSource ) {
2060 return $this->mContext;
2061 } else {
2062 wfDebug( __METHOD__ . " called and \$mContext is null. " .
2063 "Return RequestContext::getMain(); for sanity\n" );
2064 return RequestContext::getMain();
2065 }
2066 }
2067
2075 public function __get( $fname ) {
2076 if ( property_exists( $this->mPage, $fname ) ) {
2077 # wfWarn( "Access to raw $fname field " . __CLASS__ );
2078 return $this->mPage->$fname;
2079 }
2080 trigger_error( 'Inaccessible property via __get(): ' . $fname, E_USER_NOTICE );
2081 }
2082
2090 public function __set( $fname, $fvalue ) {
2091 if ( property_exists( $this->mPage, $fname ) ) {
2092 # wfWarn( "Access to raw $fname field of " . __CLASS__ );
2093 $this->mPage->$fname = $fvalue;
2094 // Note: extensions may want to toss on new fields
2095 } elseif ( !in_array( $fname, [ 'mContext', 'mPage' ] ) ) {
2096 $this->mPage->$fname = $fvalue;
2097 } else {
2098 trigger_error( 'Inaccessible property via __set(): ' . $fname, E_USER_NOTICE );
2099 }
2100 }
2101
2106 public function checkFlags( $flags ) {
2107 return $this->mPage->checkFlags( $flags );
2108 }
2109
2114 public function checkTouched() {
2115 return $this->mPage->checkTouched();
2116 }
2117
2122 public function clearPreparedEdit() {
2123 $this->mPage->clearPreparedEdit();
2124 }
2125
2130 public function doDeleteArticleReal(
2131 $reason, $suppress = false, $u1 = null, $u2 = null, &$error = '', User $user = null
2132 ) {
2133 return $this->mPage->doDeleteArticleReal(
2134 $reason, $suppress, $u1, $u2, $error, $user
2135 );
2136 }
2137
2142 public function doDeleteUpdates( $id, Content $content = null ) {
2143 return $this->mPage->doDeleteUpdates( $id, $content );
2144 }
2145
2150 public function doEdit( $text, $summary, $flags = 0, $baseRevId = false, $user = null ) {
2151 ContentHandler::deprecated( __METHOD__, '1.21' );
2152 return $this->mPage->doEdit( $text, $summary, $flags, $baseRevId, $user );
2153 }
2154
2159 public function doEditContent( Content $content, $summary, $flags = 0, $baseRevId = false,
2160 User $user = null, $serialFormat = null
2161 ) {
2162 return $this->mPage->doEditContent( $content, $summary, $flags, $baseRevId,
2163 $user, $serialFormat
2164 );
2165 }
2166
2171 public function doEditUpdates( Revision $revision, User $user, array $options = [] ) {
2172 return $this->mPage->doEditUpdates( $revision, $user, $options );
2173 }
2174
2179 public function doPurge() {
2180 return $this->mPage->doPurge();
2181 }
2182
2187 public function doQuickEditContent(
2188 Content $content, User $user, $comment = '', $minor = false, $serialFormat = null
2189 ) {
2190 return $this->mPage->doQuickEditContent(
2191 $content, $user, $comment, $minor, $serialFormat
2192 );
2193 }
2194
2199 public function doViewUpdates( User $user, $oldid = 0 ) {
2200 $this->mPage->doViewUpdates( $user, $oldid );
2201 }
2202
2207 public function exists() {
2208 return $this->mPage->exists();
2209 }
2210
2215 public function followRedirect() {
2216 return $this->mPage->followRedirect();
2217 }
2218
2223 public function getActionOverrides() {
2224 return $this->mPage->getActionOverrides();
2225 }
2226
2231 public function getAutoDeleteReason( &$hasHistory ) {
2232 return $this->mPage->getAutoDeleteReason( $hasHistory );
2233 }
2234
2239 public function getCategories() {
2240 return $this->mPage->getCategories();
2241 }
2242
2247 public function getComment( $audience = Revision::FOR_PUBLIC, User $user = null ) {
2248 return $this->mPage->getComment( $audience, $user );
2249 }
2250
2255 public function getContentHandler() {
2256 return $this->mPage->getContentHandler();
2257 }
2258
2263 public function getContentModel() {
2264 return $this->mPage->getContentModel();
2265 }
2266
2271 public function getContributors() {
2272 return $this->mPage->getContributors();
2273 }
2274
2279 public function getCreator( $audience = Revision::FOR_PUBLIC, User $user = null ) {
2280 return $this->mPage->getCreator( $audience, $user );
2281 }
2282
2287 public function getDeletionUpdates( Content $content = null ) {
2288 return $this->mPage->getDeletionUpdates( $content );
2289 }
2290
2295 public function getHiddenCategories() {
2296 return $this->mPage->getHiddenCategories();
2297 }
2298
2303 public function getId() {
2304 return $this->mPage->getId();
2305 }
2306
2311 public function getLatest() {
2312 return $this->mPage->getLatest();
2313 }
2314
2319 public function getLinksTimestamp() {
2320 return $this->mPage->getLinksTimestamp();
2321 }
2322
2327 public function getMinorEdit() {
2328 return $this->mPage->getMinorEdit();
2329 }
2330
2335 public function getOldestRevision() {
2336 return $this->mPage->getOldestRevision();
2337 }
2338
2343 public function getRedirectTarget() {
2344 return $this->mPage->getRedirectTarget();
2345 }
2346
2351 public function getRedirectURL( $rt ) {
2352 return $this->mPage->getRedirectURL( $rt );
2353 }
2354
2359 public function getRevision() {
2360 return $this->mPage->getRevision();
2361 }
2362
2367 public function getText( $audience = Revision::FOR_PUBLIC, User $user = null ) {
2368 ContentHandler::deprecated( __METHOD__, '1.21' );
2369 return $this->mPage->getText( $audience, $user );
2370 }
2371
2376 public function getTimestamp() {
2377 return $this->mPage->getTimestamp();
2378 }
2379
2384 public function getTouched() {
2385 return $this->mPage->getTouched();
2386 }
2387
2392 public function getUndoContent( Revision $undo, Revision $undoafter = null ) {
2393 return $this->mPage->getUndoContent( $undo, $undoafter );
2394 }
2395
2400 public function getUser( $audience = Revision::FOR_PUBLIC, User $user = null ) {
2401 return $this->mPage->getUser( $audience, $user );
2402 }
2403
2408 public function getUserText( $audience = Revision::FOR_PUBLIC, User $user = null ) {
2409 return $this->mPage->getUserText( $audience, $user );
2410 }
2411
2416 public function hasViewableContent() {
2417 return $this->mPage->hasViewableContent();
2418 }
2419
2424 public function insertOn( $dbw, $pageId = null ) {
2425 return $this->mPage->insertOn( $dbw, $pageId );
2426 }
2427
2432 public function insertProtectNullRevision( $revCommentMsg, array $limit,
2433 array $expiry, $cascade, $reason, $user = null
2434 ) {
2435 return $this->mPage->insertProtectNullRevision( $revCommentMsg, $limit,
2436 $expiry, $cascade, $reason, $user
2437 );
2438 }
2439
2444 public function insertRedirect() {
2445 return $this->mPage->insertRedirect();
2446 }
2447
2452 public function insertRedirectEntry( Title $rt, $oldLatest = null ) {
2453 return $this->mPage->insertRedirectEntry( $rt, $oldLatest );
2454 }
2455
2460 public function isCountable( $editInfo = false ) {
2461 return $this->mPage->isCountable( $editInfo );
2462 }
2463
2468 public function isRedirect() {
2469 return $this->mPage->isRedirect();
2470 }
2471
2476 public function loadFromRow( $data, $from ) {
2477 return $this->mPage->loadFromRow( $data, $from );
2478 }
2479
2484 public function loadPageData( $from = 'fromdb' ) {
2485 $this->mPage->loadPageData( $from );
2486 }
2487
2492 public function lockAndGetLatest() {
2493 return $this->mPage->lockAndGetLatest();
2494 }
2495
2500 public function makeParserOptions( $context ) {
2501 return $this->mPage->makeParserOptions( $context );
2502 }
2503
2508 public function pageDataFromId( $dbr, $id, $options = [] ) {
2509 return $this->mPage->pageDataFromId( $dbr, $id, $options );
2510 }
2511
2516 public function pageDataFromTitle( $dbr, $title, $options = [] ) {
2517 return $this->mPage->pageDataFromTitle( $dbr, $title, $options );
2518 }
2519
2524 public function prepareContentForEdit(
2525 Content $content, $revision = null, User $user = null,
2526 $serialFormat = null, $useCache = true
2527 ) {
2528 return $this->mPage->prepareContentForEdit(
2529 $content, $revision, $user,
2530 $serialFormat, $useCache
2531 );
2532 }
2533
2538 public function prepareTextForEdit( $text, $revid = null, User $user = null ) {
2539 return $this->mPage->prepareTextForEdit( $text, $revid, $user );
2540 }
2541
2546 public function protectDescription( array $limit, array $expiry ) {
2547 return $this->mPage->protectDescription( $limit, $expiry );
2548 }
2549
2554 public function protectDescriptionLog( array $limit, array $expiry ) {
2555 return $this->mPage->protectDescriptionLog( $limit, $expiry );
2556 }
2557
2562 public function replaceSectionAtRev( $sectionId, Content $sectionContent,
2563 $sectionTitle = '', $baseRevId = null
2564 ) {
2565 return $this->mPage->replaceSectionAtRev( $sectionId, $sectionContent,
2566 $sectionTitle, $baseRevId
2567 );
2568 }
2569
2574 public function replaceSectionContent(
2575 $sectionId, Content $sectionContent, $sectionTitle = '', $edittime = null
2576 ) {
2577 return $this->mPage->replaceSectionContent(
2578 $sectionId, $sectionContent, $sectionTitle, $edittime
2579 );
2580 }
2581
2586 public function setTimestamp( $ts ) {
2587 return $this->mPage->setTimestamp( $ts );
2588 }
2589
2594 public function shouldCheckParserCache( ParserOptions $parserOptions, $oldId ) {
2595 return $this->mPage->shouldCheckParserCache( $parserOptions, $oldId );
2596 }
2597
2602 public function supportsSections() {
2603 return $this->mPage->supportsSections();
2604 }
2605
2611 return $this->mPage->triggerOpportunisticLinksUpdate( $parserOutput );
2612 }
2613
2618 public function updateCategoryCounts( array $added, array $deleted ) {
2619 return $this->mPage->updateCategoryCounts( $added, $deleted );
2620 }
2621
2626 public function updateIfNewerOn( $dbw, $revision ) {
2627 return $this->mPage->updateIfNewerOn( $dbw, $revision );
2628 }
2629
2634 public function updateRedirectOn( $dbw, $redirectTitle, $lastRevIsRedirect = null ) {
2635 return $this->mPage->updateRedirectOn( $dbw, $redirectTitle, $lastRevIsRedirect = null );
2636 }
2637
2642 public function updateRevisionOn( $dbw, $revision, $lastRevision = null,
2643 $lastRevIsRedirect = null
2644 ) {
2645 return $this->mPage->updateRevisionOn( $dbw, $revision, $lastRevision,
2646 $lastRevIsRedirect
2647 );
2648 }
2649
2658 public function doUpdateRestrictions( array $limit, array $expiry, &$cascade,
2659 $reason, User $user
2660 ) {
2661 return $this->mPage->doUpdateRestrictions( $limit, $expiry, $cascade, $reason, $user );
2662 }
2663
2671 public function updateRestrictions( $limit = [], $reason = '',
2672 &$cascade = 0, $expiry = []
2673 ) {
2674 return $this->mPage->doUpdateRestrictions(
2675 $limit,
2676 $expiry,
2677 $cascade,
2678 $reason,
2679 $this->getContext()->getUser()
2680 );
2681 }
2682
2691 public function doDeleteArticle(
2692 $reason, $suppress = false, $u1 = null, $u2 = null, &$error = ''
2693 ) {
2694 return $this->mPage->doDeleteArticle( $reason, $suppress, $u1, $u2, $error );
2695 }
2696
2706 public function doRollback( $fromP, $summary, $token, $bot, &$resultDetails, User $user = null ) {
2707 $user = is_null( $user ) ? $this->getContext()->getUser() : $user;
2708 return $this->mPage->doRollback( $fromP, $summary, $token, $bot, $resultDetails, $user );
2709 }
2710
2719 public function commitRollback( $fromP, $summary, $bot, &$resultDetails, User $guser = null ) {
2720 $guser = is_null( $guser ) ? $this->getContext()->getUser() : $guser;
2721 return $this->mPage->commitRollback( $fromP, $summary, $bot, $resultDetails, $guser );
2722 }
2723
2728 public function generateReason( &$hasHistory ) {
2729 $title = $this->mPage->getTitle();
2731 return $handler->getAutoDeleteReason( $title, $hasHistory );
2732 }
2733
2739 public static function selectFields() {
2740 wfDeprecated( __METHOD__, '1.24' );
2741 return WikiPage::selectFields();
2742 }
2743
2749 public static function onArticleCreate( $title ) {
2750 wfDeprecated( __METHOD__, '1.24' );
2752 }
2753
2759 public static function onArticleDelete( $title ) {
2760 wfDeprecated( __METHOD__, '1.24' );
2762 }
2763
2769 public static function onArticleEdit( $title ) {
2770 wfDeprecated( __METHOD__, '1.24' );
2772 }
2773
2781 public static function getAutosummary( $oldtext, $newtext, $flags ) {
2782 return WikiPage::getAutosummary( $oldtext, $newtext, $flags );
2783 }
2784 // ******
2785}
$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 ...
$wgMaxRedirects
Max number of redirects to follow when resolving redirects.
$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.
$wgUseETag
Whether MediaWiki should send an ETag header.
$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:35
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:2594
getRevisionFetched()
Get the fetched Revision object depending on request parameters or null on failure.
Definition Article.php:451
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:2634
generateReason(&$hasHistory)
Definition Article.php:2728
checkFlags( $flags)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2106
checkTouched()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2114
doDelete( $reason, $suppress=false)
Perform a deletion and output success or failure messages.
Definition Article.php:1890
getHiddenCategories()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2295
static newFromWikiPage(WikiPage $page, IContextSource $context)
Create an Article object of the appropriate class for the given page.
Definition Article.php:146
doViewUpdates(User $user, $oldid=0)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2199
getContext()
Gets the context this Article is executed in.
Definition Article.php:2058
static getAutosummary( $oldtext, $newtext, $flags)
Definition Article.php:2781
getCategories()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2239
commitRollback( $fromP, $summary, $bot, &$resultDetails, User $guser=null)
Definition Article.php:2719
getOldIDFromRequest()
Sets $this->mRedirectUrl to a correct URL if the query parameters are incorrect.
Definition Article.php:266
doEditContent(Content $content, $summary, $flags=0, $baseRevId=false, User $user=null, $serialFormat=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2159
doDeleteArticleReal( $reason, $suppress=false, $u1=null, $u2=null, &$error='', User $user=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2130
getParserOutput( $oldid=null, User $user=null)
#-
Definition Article.php:2003
doEdit( $text, $summary, $flags=0, $baseRevId=false, $user=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2150
insertProtectNullRevision( $revCommentMsg, array $limit, array $expiry, $cascade, $reason, $user=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2432
doPurge()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2179
getUserText( $audience=Revision::FOR_PUBLIC, User $user=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2408
insertOn( $dbw, $pageId=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2424
updateRevisionOn( $dbw, $revision, $lastRevision=null, $lastRevIsRedirect=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2642
prepareTextForEdit( $text, $revid=null, User $user=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2538
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:363
supportsSections()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2602
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:2516
getContentHandler()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2255
view()
This is the default action of the index.php entry point: just view the page of the given title.
Definition Article.php:474
loadPageData( $from='fromdb')
Call to WikiPage function for backwards compatibility.
Definition Article.php:2484
getRobotPolicy( $action, $pOutput=null)
Get the robot policy to be used for the current view.
Definition Article.php:850
doUpdateRestrictions(array $limit, array $expiry, &$cascade, $reason, User $user)
Definition Article.php:2658
protectDescriptionLog(array $limit, array $expiry)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2554
clearPreparedEdit()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2122
__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:1242
followRedirect()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2215
prepareContentForEdit(Content $content, $revision=null, User $user=null, $serialFormat=null, $useCache=true)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2524
static selectFields()
Definition Article.php:2739
replaceSectionAtRev( $sectionId, Content $sectionContent, $sectionTitle='', $baseRevId=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2562
getAutoDeleteReason(&$hasHistory)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2231
getLinksTimestamp()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2319
getOldID()
Definition Article.php:253
protectDescription(array $limit, array $expiry)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2546
getOldestRevision()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2335
isFileCacheable()
Check if the page can be cached.
Definition Article.php:1973
static onArticleEdit( $title)
Definition Article.php:2769
setTimestamp( $ts)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2586
getTitle()
Get the title object of the article.
Definition Article.php:166
getActionOverrides()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2223
doEditUpdates(Revision $revision, User $user, array $options=[])
Call to WikiPage function for backwards compatibility.
Definition Article.php:2171
adjustDisplayTitle(ParserOutput $pOutput)
Adjust title for pages with displaytitle, -{T|}- or language conversion.
Definition Article.php:747
updateIfNewerOn( $dbw, $revision)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2626
getLatest()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2311
pageDataFromId( $dbr, $id, $options=[])
Call to WikiPage function for backwards compatibility.
Definition Article.php:2508
insertRedirect()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2444
doDeleteUpdates( $id, Content $content=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2142
getContributors()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2271
showDeletedRevisionHeader()
If the revision requested for view is deleted, check permissions.
Definition Article.php:1373
isCountable( $editInfo=false)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2460
getParserOptions()
Get parser options suitable for rendering the primary article wikitext.
Definition Article.php:2034
getCreator( $audience=Revision::FOR_PUBLIC, User $user=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2279
clear()
Clear the object.
Definition Article.php:183
getComment( $audience=Revision::FOR_PUBLIC, User $user=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2247
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:2263
static getRedirectHeaderHtml(Language $lang, $target, $forceKnown=false)
Return the HTML for the top of a redirect page.
Definition Article.php:1575
protect()
action=protect handler
Definition Article.php:1637
getText( $audience=Revision::FOR_PUBLIC, User $user=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2367
lockAndGetLatest()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2492
isCurrent()
Returns true if the currently-referenced revision is the current edit to this page (and it exists).
Definition Article.php:435
updateRestrictions( $limit=[], $reason='', &$cascade=0, $expiry=[])
Definition Article.php:2671
showMissingArticle()
Show the error text for a missing article.
Definition Article.php:1251
getUndoContent(Revision $undo, Revision $undoafter=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2392
__set( $fname, $fvalue)
Use PHP's magic __set handler to handle setting of raw WikiPage fields for backwards compatibility.
Definition Article.php:2090
doDeleteArticle( $reason, $suppress=false, $u1=null, $u2=null, &$error='')
Definition Article.php:2691
getId()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2303
unprotect()
action=unprotect handler (alias)
Definition Article.php:1645
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:2468
static onArticleCreate( $title)
Definition Article.php:2749
newPage(Title $title)
Definition Article.php:91
confirmDelete( $reason)
Output deletion confirmation dialog.
Definition Article.php:1780
getPage()
Get the WikiPage object of this instance.
Definition Article.php:176
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
Definition Article.php:1610
getTouched()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2384
getRevision()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2359
updateCategoryCounts(array $added, array $deleted)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2618
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:2376
static newFromID( $id)
Constructor from a page id.
Definition Article.php:100
getRedirectTarget()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2343
getUser( $audience=Revision::FOR_PUBLIC, User $user=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2400
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:930
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:1553
insertRedirectEntry(Title $rt, $oldLatest=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2452
triggerOpportunisticLinksUpdate(ParserOutput $parserOutput)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2610
static onArticleDelete( $title)
Definition Article.php:2759
makeParserOptions( $context)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2500
showPatrolFooter()
If patrol is possible, output a patrol UI box.
Definition Article.php:1073
setOldSubtitle( $oldid=0)
Generate the navigation links when browsing through an article revisions It shows the information as:...
Definition Article.php:1416
ParserOptions $mParserOptions
ParserOptions object for $wgUser articles.
Definition Article.php:42
showViewFooter()
Show the footer section of an ordinary page view.
Definition Article.php:1050
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:2476
setRedirectedFrom(Title $from)
Tell the page view functions that this view was redirected from another page on the wiki.
Definition Article.php:157
getContent()
Note that getContent does not follow redirects anymore.
Definition Article.php:205
tryFileCache()
checkLastModified returns true if it has taken care of all output to the client that is necessary for...
Definition Article.php:1943
getRevIdFetched()
Use this to fetch the rev ID used on page views.
Definition Article.php:462
replaceSectionContent( $sectionId, Content $sectionContent, $sectionTitle='', $edittime=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2574
doQuickEditContent(Content $content, User $user, $comment='', $minor=false, $serialFormat=null)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2187
showNamespaceHeader()
Show a header specific to the namespace currently being viewed, like [[MediaWiki:Talkpagetext]].
Definition Article.php:1036
__get( $fname)
Use PHP's magic __get handler to handle accessing of raw WikiPage fields for backwards compatibility.
Definition Article.php:2075
static newFromTitle( $title, IContextSource $context)
Create an Article object of the appropriate class for the given page.
Definition Article.php:114
showCssOrJsPage( $showCacheHint=true)
Show a page view for a page formatted as CSS or JavaScript.
Definition Article.php:814
hasViewableContent()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2416
getContentObject()
Returns a Content object representing the pages effective display content, not necessarily the revisi...
Definition Article.php:226
showDiffPage()
Show a diff page according to current request variables.
Definition Article.php:760
getMinorEdit()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2327
setParserOptions(ParserOptions $options)
Override the ParserOptions used to render the primary article wikitext.
Definition Article.php:2021
render()
Handle action=render.
Definition Article.php:1627
showRedirectedFromHeader()
If this request is a redirect view, send "redirected from" subtitle to the output.
Definition Article.php:959
exists()
Call to WikiPage function for backwards compatibility.
Definition Article.php:2207
setContext( $context)
Sets the context this Article is executed in.
Definition Article.php:2048
getRedirectURL( $rt)
Call to WikiPage function for backwards compatibility.
Definition Article.php:2351
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:2287
doRollback( $fromP, $summary, $token, $bot, &$resultDetails, User $user=null)
Definition Article.php:2706
fetchContent()
Get text of an article from database Does NOT follow redirects.
Definition Article.php:326
const TYPE_AUTO
Definition Block.php:78
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:1079
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 runLegacyHooks( $event, $args=[], $warn=null)
Call a legacy hook that uses text instead of Content objects.
static getContentText(Content $content=null)
Convenience function for getting flat text from a Content object.
static deprecated( $func, $version, $component=false)
Logs a deprecation warning, visible if $wgDevelopmentWarnings, but only if self::$enableDeprecationWa...
getRequest()
Get the WebRequest object.
Page view caching in the file system.
static useFileCache(IContextSource $context)
Check if pages can be cached for this request/user.
static label( $label, $id, array $attribs=[])
Convenience function for generating a label for inputs.
Definition Html.php:743
static element( $element, $attribs=[], $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition Html.php:230
static input( $name, $value='', $type='text', array $attribs=[])
Convenience function to produce an "<input>" element.
Definition Html.php:676
static openElement( $element, $attribs=[])
Identical to rawElement(), but has no third parameter and omits the end tag (and the self-closing '/'...
Definition Html.php:248
static closeElement( $element)
Returns "</$element>".
Definition Html.php:306
static hidden( $name, $value, array $attribs=[])
Convenience function to produce an input element with type=hidden.
Definition Html.php:759
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:39
static link( $target, $html=null, $customAttribs=[], $query=[], $options=[])
This function returns an HTML link to the given target.
Definition Linker.php:195
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:1656
static revUserTools( $rev, $isPublic=false)
Generate a user tool link cluster if the current user is allowed to view it.
Definition Linker.php:1252
static linkKnown( $target, $html=null, $customAttribs=[], $query=[], $options=[ 'known', 'noclasses'])
Identical to link(), except $options defaults to 'known'.
Definition Linker.php:264
static makeExternalLink( $url, $text, $escape=true, $linktype='', $attribs=[], $title=null)
Make an external link.
Definition Linker.php:1052
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:2258
static showLogExtract(&$out, $types=[], $page='', $user='', $param=[])
Show log extract.
Class to simplify the use of log pages.
Definition LogPage.php:32
MediaWiki exception.
static getCanonicalName( $index)
Returns the canonical (English) name for a given index.
Wrapper allowing us to handle a system message as a Content object.
static getMainWANInstance()
Get the main WAN cache object.
static getMainStashInstance()
Get the cache object for the main stash.
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_SLAVE)
Find the first recent change matching some specific conditions.
static getMain()
Static methods.
const DELETED_TEXT
Definition Revision.php:76
const DELETED_RESTRICTED
Definition Revision.php:79
const FOR_PUBLIC
Definition Revision.php:83
static newFromTitle(LinkTarget $linkTarget, $id=0, $flags=0)
Load either the current, or a specified, revision that's attached to a given link target.
Definition Revision.php:117
const FOR_THIS_USER
Definition Revision.php:84
static newFromId( $id, $flags=0)
Load a page revision from a given revision ID number.
Definition Revision.php:99
static makeUrl( $name, $urlaction='')
Definition Skin.php:1084
Represents a title within MediaWiki.
Definition Title.php:34
static newFromID( $id, $flags=0)
Create a new Title from an article ID.
Definition Title.php:417
getFullURL( $query='', $query2=false, $proto=PROTO_RELATIVE)
Get a real URL referring to this title, with interwiki link and fragment.
Definition Title.php:1666
static & makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition Title.php:524
static compare( $a, $b)
Callback for usort() to do title sorts by (namespace, title)
Definition Title.php:780
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition User.php:47
static doWatchOrUnwatch( $watch, Title $title, User $user)
Watch or unwatch a page.
Class representing a MediaWiki article and history.
Definition WikiPage.php:29
static onArticleEdit(Title $title, Revision $revision=null)
Purge caches on page update etc.
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:266
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:72
const NS_FILE
Definition Defines.php:76
const NS_MEDIAWIKI
Definition Defines.php:78
const RC_LOG
Definition Defines.php:172
const NS_MEDIA
Definition Defines.php:58
const NS_USER_TALK
Definition Defines.php:73
const NS_CATEGORY
Definition Defines.php:84
const DB_SLAVE
Definition Defines.php:47
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:1007
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:1036
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:2379
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 after processing 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
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:1042
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:1040
namespace and then decline to actually register it file or subcat img or subcat $title
Definition hooks.txt:944
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:2360
null for the local wiki Added in
Definition hooks.txt:1421
it s the revision text itself In either if gzip is the revision text is gzipped $flags
Definition hooks.txt:2555
error also a ContextSource you ll probably need to make sure the header is varied on $request
Definition hooks.txt:2530
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:1081
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:846
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:1818
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:1460
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
the value to return A Title object or null for latest to be modified or replaced by the hook handler or if authentication is not possible after cache objects are set for highlighting & $link
Definition hooks.txt:2692
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:885
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:1458
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:1597
returning false will NOT prevent logging $e
Definition hooks.txt:1940
$from
$comment
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
linkcache txt The LinkCache class maintains a list of article titles and the information about whether or not the article exists in the database This is used to mark up links when displaying a page If the same link appears more than once on any page then it only has to be looked up once In most cases link lookups are done in batches with the LinkBatch class or the equivalent in so the link cache is mostly useful for short snippets of parsed and for links in the navigation areas of the skin The link cache was formerly used to track links used in a document for the purposes of updating the link tables This application is now deprecated To create a you can use the following $titles
Definition linkcache.txt:17
$context
Definition load.php:44
$cache
Definition mcc.php:33
if(!isset( $args[0])) $lang