Merge "Add type hint for ParserOutput"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Sun, 12 Aug 2018 07:03:19 +0000 (07:03 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Sun, 12 Aug 2018 07:03:19 +0000 (07:03 +0000)
1  2 
includes/EditPage.php
includes/OutputPage.php

diff --combined includes/EditPage.php
@@@ -236,7 -236,7 +236,7 @@@ class EditPage 
        public $action = 'submit';
  
        /** @var bool Whether an edit conflict needs to be resolved. Detected based on whether
 -       * $editRevId is different from the current revision. When a conflict has successfully
 +       * $editRevId is different than the latest revision. When a conflict has successfully
         * been resolved by a 3-way-merge, this field is set to false.
         */
        public $isConflict = false;
        /** @var string */
        public $formtype;
  
 -      /** @var bool */
 +      /** @var bool
 +       * True the first time the edit form is rendered, false after re-rendering
 +       * with diff, save prompts, etc.
 +       */
        public $firsttime;
  
        /** @var bool|stdClass */
        /** @var bool */
        public $recreate = false;
  
 -      /** @var string */
 +      /** @var string
 +       * Page content input field.
 +       */
        public $textbox1 = '';
  
        /** @var string */
        /** @var string */
        public $summary = '';
  
 -      /** @var bool */
 +      /** @var bool
 +       * If true, hide the summary field.
 +       */
        public $nosummary = false;
  
 -      /** @var string */
 +      /** @var string
 +       * Timestamp of the latest revision of the page when editing was initiated
 +       * on the client.
 +       */
        public $edittime = '';
  
 -      /** @var int ID of the current revision at the time editing was initiated on the client.
 -       * This is used to detect and resolve edit conflicts.
 +      /** @var int Revision ID of the latest revision of the page when editing
 +       * was initiated on the client.  This is used to detect and resolve edit
 +       * conflicts.
         *
         * @note 0 if the page did not exist at that time.
         * @note When starting an edit from an old revision, this still records the current
 -       * revision at the time , not the one the edit is based on.
 +       * revision at the time, not the one the edit is based on.
         *
         * @see $oldid
         * @see getBaseRevision()
        /** @var string */
        public $sectiontitle = '';
  
 -      /** @var string */
 +      /** @var string
 +       * Timestamp from the first time the edit form was rendered.
 +       */
        public $starttime = '';
  
        /** @var int Revision ID the edit is based on, or 0 if it's the current revision.
 +       * FIXME: This isn't used in conflict resolution--provide a better
 +       * justification or merge with parentRevId.
         * @see $editRevId
         */
        public $oldid = 0;
         * @since 1.21
         */
        protected function getContentObject( $def_content = null ) {
 -              global $wgContLang;
 -
                $content = false;
  
                $user = $this->context->getUser();
  
                                                if ( $undoMsg === null ) {
                                                        $oldContent = $this->page->getContent( Revision::RAW );
 -                                                      $popts = ParserOptions::newFromUserAndLang( $user, $wgContLang );
 +                                                      $popts = ParserOptions::newFromUserAndLang(
 +                                                              $user, MediaWikiServices::getInstance()->getContentLanguage() );
                                                        $newContent = $content->preSaveTransform( $this->mTitle, $user, $popts );
                                                        if ( $newContent->getModel() !== $oldContent->getModel() ) {
                                                                // The undo may change content
@@@ -3460,6 -3446,8 +3460,6 @@@ ERROR
         * save and then make a comparison.
         */
        public function showDiff() {
 -              global $wgContLang;
 -
                $oldtitlemsg = 'currentrev';
                # if message does not exist, show diff against the preloaded default
                if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI && !$this->mTitle->exists() ) {
                        Hooks::run( 'EditPageGetDiffContent', [ $this, &$newContent ] );
  
                        $user = $this->context->getUser();
 -                      $popts = ParserOptions::newFromUserAndLang( $user, $wgContLang );
 +                      $popts = ParserOptions::newFromUserAndLang( $user,
 +                              MediaWikiServices::getInstance()->getContentLanguage() );
                        $newContent = $newContent->preSaveTransform( $this->mTitle, $user, $popts );
                }
  
         * Get the Limit report for page previews
         *
         * @since 1.22
-        * @param ParserOutput $output ParserOutput object from the parse
+        * @param ParserOutput|null $output ParserOutput object from the parse
         * @return string HTML
         */
-       public static function getPreviewLimitReport( $output ) {
+       public static function getPreviewLimitReport( ParserOutput $output = null ) {
                global $wgLang;
  
                if ( !$output || !$output->getLimitReportData() ) {
        }
  
        /**
 +       * Get the last log record of this page being deleted, if ever.  This is
 +       * used to detect whether a delete occured during editing.
         * @return bool|stdClass
         */
        protected function getLastDelete() {
         * @return string
         */
        public static function getEditToolbar( $title = null ) {
 -              global $wgContLang, $wgOut;
 -              global $wgEnableUploads, $wgForeignFileRepos;
 +              global $wgOut, $wgEnableUploads, $wgForeignFileRepos;
  
                $imagesAvailable = $wgEnableUploads || count( $wgForeignFileRepos );
                $showSignature = true;
                        $showSignature = MWNamespace::wantSignatures( $title->getNamespace() );
                }
  
 +              $contLang = MediaWikiServices::getInstance()->getContentLanguage();
 +
                /**
                 * $toolarray is an array of arrays each of which includes the
                 * opening tag, the closing tag, optionally a sample text that is
                        ],
                        $imagesAvailable ? [
                                'id'     => 'mw-editbutton-image',
 -                              'open'   => '[[' . $wgContLang->getNsText( NS_FILE ) . ':',
 +                              'open'   => '[[' . $contLang->getNsText( NS_FILE ) . ':',
                                'close'  => ']]',
                                'sample' => wfMessage( 'image_sample' )->text(),
                                'tip'    => wfMessage( 'image_tip' )->text(),
                        ] : false,
                        $imagesAvailable ? [
                                'id'     => 'mw-editbutton-media',
 -                              'open'   => '[[' . $wgContLang->getNsText( NS_MEDIA ) . ':',
 +                              'open'   => '[[' . $contLang->getNsText( NS_MEDIA ) . ':',
                                'close'  => ']]',
                                'sample' => wfMessage( 'media_sample' )->text(),
                                'tip'    => wfMessage( 'media_tip' )->text(),
                        ]
                ];
  
 -              $script = 'mw.loader.using("mediawiki.toolbar", function () {';
 +              $script = '';
                foreach ( $toolarray as $tool ) {
                        if ( !$tool ) {
                                continue;
                        );
                }
  
 -              $script .= '});';
 -
                $toolbar = '<div id="toolbar"></div>';
  
                if ( Hooks::run( 'EditPageBeforeEditToolbar', [ &$toolbar ] ) ) {
                        // Only add the old toolbar cruft to the page payload if the toolbar has not
                        // been over-written by a hook caller
                        $nonce = $wgOut->getCSPNonce();
 -                      $wgOut->addScript( ResourceLoader::makeInlineScript( $script, $nonce ) );
 +                      $wgOut->addScript( Html::inlineScript(
 +                              ResourceLoader::makeInlineCodeWithModule( 'mediawiki.toolbar', $script ),
 +                              $nonce
 +                      ) );
                };
  
                return $toolbar;
diff --combined includes/OutputPage.php
@@@ -71,7 -71,7 +71,7 @@@ class OutputPage extends ContextSource 
         * @var bool Is the displayed content related to the source of the
         *   corresponding wiki article.
         */
 -      private $mIsarticle = false;
 +      private $mIsArticle = false;
  
        /** @var bool Stores "article flag" toggle. */
        private $mIsArticleRelated = true;
         */
        public $mNoGallery = false;
  
 -      /** @var string */
 -      private $mPageTitleActionText = '';
 -
        /** @var int Cache stuff. Looks like mEnableClientCache */
        protected $mCdnMaxage = 0;
        /** @var int Upper limit on mCdnMaxage */
  
        private $mIndexPolicy = 'index';
        private $mFollowPolicy = 'follow';
 +
 +      /**
 +       * @var array Headers that cause the cache to vary.  Key is header name, value is an array of
 +       * options for the Key header.
 +       */
        private $mVaryHeader = [
                'Accept-Encoding' => [ 'match=gzip' ],
        ];
                # this breaks strtotime().
                $clientHeader = preg_replace( '/;.*$/', '', $clientHeader );
  
 -              Wikimedia\suppressWarnings(); // E_STRICT system time bitching
 +              Wikimedia\suppressWarnings(); // E_STRICT system time warnings
                $clientHeaderTime = strtotime( $clientHeader );
                Wikimedia\restoreWarnings();
                if ( !$clientHeaderTime ) {
                }
        }
  
 -      /**
 -       * Set the new value of the "action text", this will be added to the
 -       * "HTML title", separated from it with " - ".
 -       *
 -       * @param string $text New value of the "action text"
 -       */
 -      public function setPageTitleActionText( $text ) {
 -              $this->mPageTitleActionText = $text;
 -      }
 -
 -      /**
 -       * Get the value of the "action text"
 -       *
 -       * @return string
 -       */
 -      public function getPageTitleActionText() {
 -              return $this->mPageTitleActionText;
 -      }
 -
        /**
         * "HTML title" means the contents of "<title>".
         * It is stored as plain, unescaped text and will be run through htmlspecialchars in the skin file.
         * corresponding article on the wiki
         * Setting true will cause the change "article related" toggle to true
         *
 -       * @param bool $v
 +       * @param bool $newVal
         */
 -      public function setArticleFlag( $v ) {
 -              $this->mIsarticle = $v;
 -              if ( $v ) {
 -                      $this->mIsArticleRelated = $v;
 +      public function setArticleFlag( $newVal ) {
 +              $this->mIsArticle = $newVal;
 +              if ( $newVal ) {
 +                      $this->mIsArticleRelated = $newVal;
                }
        }
  
         * @return bool
         */
        public function isArticle() {
 -              return $this->mIsarticle;
 +              return $this->mIsArticle;
        }
  
        /**
         * Set whether this page is related an article on the wiki
         * Setting false will cause the change of "article flag" toggle to false
         *
 -       * @param bool $v
 +       * @param bool $newVal
         */
 -      public function setArticleRelated( $v ) {
 -              $this->mIsArticleRelated = $v;
 -              if ( !$v ) {
 -                      $this->mIsarticle = false;
 +      public function setArticleRelated( $newVal ) {
 +              $this->mIsArticleRelated = $newVal;
 +              if ( !$newVal ) {
 +                      $this->mIsArticle = false;
                }
        }
  
         * @param array $categories Mapping category name => sort key
         */
        public function addCategoryLinks( array $categories ) {
 -              global $wgContLang;
 -
 -              if ( !is_array( $categories ) || count( $categories ) == 0 ) {
 +              if ( !$categories ) {
                        return;
                }
  
                        'OutputPageMakeCategoryLinks',
                        [ &$outputPage, $categories, &$this->mCategoryLinks ] )
                ) {
 -                      $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
 +                      $services = MediaWikiServices::getInstance();
 +                      $linkRenderer = $services->getLinkRenderer();
                        foreach ( $categories as $category => $type ) {
                                // array keys will cast numeric category names to ints, so cast back to string
                                $category = (string)$category;
                                if ( !$title ) {
                                        continue;
                                }
 -                              $wgContLang->findVariantLink( $category, $title, true );
 +                              $services->getContentLanguage()->findVariantLink( $category, $title, true );
                                if ( $category != $origcategory && array_key_exists( $category, $categories ) ) {
                                        continue;
                                }
 -                              $text = $wgContLang->convertHtml( $title->getText() );
 +                              $text = $services->getContentLanguage()->convertHtml( $title->getText() );
                                $this->mCategories[$type][] = $title->getText();
                                $this->mCategoryLinks[$type][] = $linkRenderer->makeLink( $title, new HtmlArmor( $text ) );
                        }
         * Set the revision ID which will be seen by the wiki text parser
         * for things such as embedded {{REVISIONID}} variable use.
         *
 -       * @param int|null $revid An positive integer, or null
 +       * @param int|null $revid A positive integer, or null
         * @return mixed Previous value
         */
        public function setRevisionId( $revid ) {
                $val = is_null( $revid ) ? null : intval( $revid );
 -              return wfSetVar( $this->mRevisionId, $val );
 +              return wfSetVar( $this->mRevisionId, $val, true );
        }
  
        /**
         * @return mixed Previous value
         */
        public function setRevisionTimestamp( $timestamp ) {
 -              return wfSetVar( $this->mRevisionTimestamp, $timestamp );
 +              return wfSetVar( $this->mRevisionTimestamp, $timestamp, true );
        }
  
        /**
        /**
         * Set the displayed file version
         *
 -       * @param File|bool $file
 +       * @param File|null $file
         * @return mixed Previous value
         */
        public function setFileVersion( $file ) {
         * Add wikitext with a custom Title object
         *
         * @param string $text Wikitext
 -       * @param Title &$title
 +       * @param Title $title
         * @param bool $linestart Is this the start of a line?
         */
 -      public function addWikiTextWithTitle( $text, &$title, $linestart = true ) {
 +      public function addWikiTextWithTitle( $text, Title $title, $linestart = true ) {
                $this->addWikiTextTitle( $text, $title, $linestart );
        }
  
         * Add wikitext with a custom Title object and tidy enabled.
         *
         * @param string $text Wikitext
 -       * @param Title &$title
 +       * @param Title $title
         * @param bool $linestart Is this the start of a line?
         */
 -      function addWikiTextTitleTidy( $text, &$title, $linestart = true ) {
 +      function addWikiTextTitleTidy( $text, Title $title, $linestart = true ) {
                $this->addWikiTextTitle( $text, $title, $linestart, true );
        }
  
         * @since 1.24
         * @param ParserOutput $parserOutput
         */
-       public function addParserOutputMetadata( $parserOutput ) {
+       public function addParserOutputMetadata( ParserOutput $parserOutput ) {
                $this->mLanguageLinks =
                        array_merge( $this->mLanguageLinks, $parserOutput->getLanguageLinks() );
                $this->addCategoryLinks( $parserOutput->getCategories() );
                foreach ( $parserOutput->getOutputHooks() as $hookInfo ) {
                        list( $hookName, $data ) = $hookInfo;
                        if ( isset( $parserOutputHooks[$hookName] ) ) {
 -                              call_user_func( $parserOutputHooks[$hookName], $this, $parserOutput, $data );
 +                              $parserOutputHooks[$hookName]( $this, $parserOutput, $data );
                        }
                }
  
         * @param ParserOutput $parserOutput
         * @param array $poOptions Options to ParserOutput::getText()
         */
-       public function addParserOutputContent( $parserOutput, $poOptions = [] ) {
+       public function addParserOutputContent( ParserOutput $parserOutput, $poOptions = [] ) {
                $this->addParserOutputText( $parserOutput, $poOptions );
  
                $this->addModules( $parserOutput->getModules() );
         * @param ParserOutput $parserOutput
         * @param array $poOptions Options to ParserOutput::getText()
         */
-       public function addParserOutputText( $parserOutput, $poOptions = [] ) {
+       public function addParserOutputText( ParserOutput $parserOutput, $poOptions = [] ) {
                $text = $parserOutput->getText( $poOptions );
                // Avoid PHP 7.1 warning of passing $this by reference
                $outputPage = $this;
         * @param ParserOutput $parserOutput
         * @param array $poOptions Options to ParserOutput::getText()
         */
-       function addParserOutput( $parserOutput, $poOptions = [] ) {
+       function addParserOutput( ParserOutput $parserOutput, $poOptions = [] ) {
                $this->addParserOutputMetadata( $parserOutput );
                $this->addParserOutputText( $parserOutput, $poOptions );
        }
         *
         * @param string $text
         * @param bool $linestart Is this the start of a line?
 -       * @param bool $interface Use interface language ($wgLang instead of
 -       *   $wgContLang) while parsing language sensitive magic words like GRAMMAR and PLURAL.
 -       *   This also disables LanguageConverter.
 +       * @param bool $interface Use interface language (instead of content language) while parsing
 +       *   language sensitive magic words like GRAMMAR and PLURAL.  This also disables
 +       *   LanguageConverter.
         * @param Language|null $language Target language object, will override $interface
         * @throws MWException
         * @return string HTML
         *
         * @param string $text
         * @param bool $linestart Is this the start of a line?
 -       * @param bool $interface Use interface language ($wgLang instead of
 -       *   $wgContLang) while parsing language sensitive magic
 -       *   words like GRAMMAR and PLURAL
 +       * @param bool $interface Use interface language (instead of content language) while parsing
 +       *   language sensitive magic words like GRAMMAR and PLURAL
         * @return string HTML
         */
        public function parseInline( $text, $linestart = true, $interface = false ) {
        }
  
        /**
 -       * Lower the value of the "s-maxage" part of the "Cache-control" HTTP header
 +       * Set the value of the "s-maxage" part of the "Cache-control" HTTP header to $maxage if that is
 +       * lower than the current s-maxage.  Either way, $maxage is now an upper limit on s-maxage, so
 +       * that future calls to setCdnMaxage() will no longer be able to raise the s-maxage above
 +       * $maxage.
         *
         * @param int $maxage Maximum cache time on the CDN, in seconds
         * @since 1.27
         * TTL is 90% of the age of the object, subject to the min and max.
         *
         * @param string|int|float|bool|null $mtime Last-Modified timestamp
 -       * @param int $minTTL Mimimum TTL in seconds [default: 1 minute]
 +       * @param int $minTTL Minimum TTL in seconds [default: 1 minute]
         * @param int $maxTTL Maximum TTL in seconds [default: $wgSquidMaxage]
 -       * @return int TTL in seconds
 +       * @return int TTL in seconds passed to lowerCdnMaxage() (may not be the same as the new
 +       *  s-maxage)
         * @since 1.28
         */
        public function adaptCdnTTL( $mtime, $minTTL = 0, $maxTTL = 0 ) {
        /**
         * Use enableClientCache(false) to force it to send nocache headers
         *
 -       * @param bool $state
 +       * @param bool|null $state New value, or null to not set the value
         *
 -       * @return bool
 +       * @return bool Old value
         */
        public function enableClientCache( $state ) {
                return wfSetVar( $this->mEnableClientCache, $state );
        }
  
        /**
 -       * Get the list of cookies that will influence on the cache
 +       * Get the list of cookie names that will influence the cache
         *
         * @return array
         */
                if ( !is_array( $option ) ) {
                        $option = [];
                }
 -              $this->mVaryHeader[$header] = array_unique( array_merge( $this->mVaryHeader[$header], $option ) );
 +              $this->mVaryHeader[$header] =
 +                      array_unique( array_merge( $this->mVaryHeader[$header], $option ) );
        }
  
        /**
        }
  
        /**
 -       * T23672: Add Accept-Language to Vary and Key headers
 -       * if there's no 'variant' parameter existed in GET.
 +       * T23672: Add Accept-Language to Vary and Key headers if there's no 'variant' parameter in GET.
         *
         * For example:
 -       *   /w/index.php?title=Main_page should always be served; but
 -       *   /w/index.php?title=Main_page&variant=zh-cn should never be served.
 +       *   /w/index.php?title=Main_page will vary based on Accept-Language; but
 +       *   /w/index.php?title=Main_page&variant=zh-cn will not.
         */
 -      function addAcceptLanguage() {
 +      private function addAcceptLanguage() {
                $title = $this->getTitle();
                if ( !$title instanceof Title ) {
                        return;
                        foreach ( $variants as $variant ) {
                                if ( $variant === $lang->getCode() ) {
                                        continue;
 -                              } else {
 -                                      $aloption[] = 'substr=' . $variant;
 -
 -                                      // IE and some other browsers use BCP 47 standards in
 -                                      // their Accept-Language header, like "zh-CN" or "zh-Hant".
 -                                      // We should handle these too.
 -                                      $variantBCP47 = LanguageCode::bcp47( $variant );
 -                                      if ( $variantBCP47 !== $variant ) {
 -                                              $aloption[] = 'substr=' . $variantBCP47;
 -                                      }
 +                              }
 +
 +                              $aloption[] = "substr=$variant";
 +
 +                              // IE and some other browsers use BCP 47 standards in their Accept-Language header,
 +                              // like "zh-CN" or "zh-Hant".  We should handle these too.
 +                              $variantBCP47 = LanguageCode::bcp47( $variant );
 +                              if ( $variantBCP47 !== $variant ) {
 +                                      $aloption[] = "substr=$variantBCP47";
                                }
                        }
                        $this->addVaryHeader( 'Accept-Language', $aloption );
         * @throws MWException
         */
        public function output( $return = false ) {
 -              global $wgContLang;
 -
                if ( $this->mDoNothing ) {
                        return $return ? '' : null;
                }
                ob_start();
  
                $response->header( 'Content-type: ' . $config->get( 'MimeType' ) . '; charset=UTF-8' );
 -              $response->header( 'Content-language: ' . $wgContLang->getHtmlCode() );
 +              $response->header( 'Content-language: ' .
 +                      MediaWikiServices::getInstance()->getContentLanguage()->getHtmlCode() );
  
                if ( !$this->mArticleBodyOnly ) {
                        $sk = $this->getSkin();
                                $this->rlClientContext = new DerivativeResourceLoaderContext( $this->rlClientContext );
                                $this->rlClientContext->setContentOverrideCallback( function ( Title $title ) {
                                        foreach ( $this->contentOverrideCallbacks as $callback ) {
 -                                              $content = call_user_func( $callback, $title );
 +                                              $content = $callback( $title );
                                                if ( $content !== null ) {
                                                        return $content;
                                                }
         * @return string The doctype, opening "<html>", and head element.
         */
        public function headElement( Skin $sk, $includeStyle = true ) {
 -              global $wgContLang;
 -
                $userdir = $this->getLanguage()->getDir();
 -              $sitedir = $wgContLang->getDir();
 +              $sitedir = MediaWikiServices::getInstance()->getContentLanguage()->getDir();
  
                $pieces = [];
                $pieces[] = Html::htmlHeader( Sanitizer::mergeAttributes(
         * @return array
         */
        public function getJSVars() {
 -              global $wgContLang;
 -
                $curRevisionId = 0;
                $articleId = 0;
                $canonicalSpecialPageName = false; # T23115
                        'wgRelevantPageName' => $relevantTitle->getPrefixedDBkey(),
                        'wgRelevantArticleId' => $relevantTitle->getArticleID(),
                        'wgRequestId' => WebRequest::getRequestId(),
 +                      'wgCSPNonce' => $this->getCSPNonce(),
                ];
  
                if ( $user->isLoggedIn() ) {
                        $vars['wgUserNewMsgRevisionId'] = $user->getNewMessageRevisionId();
                }
  
 -              if ( $wgContLang->hasVariants() ) {
 -                      $vars['wgUserVariant'] = $wgContLang->getPreferredVariant();
 +              $contLang = MediaWikiServices::getInstance()->getContentLanguage();
 +              if ( $contLang->hasVariants() ) {
 +                      $vars['wgUserVariant'] = $contLang->getPreferredVariant();
                }
                // Same test as SkinTemplate
                $vars['wgIsProbablyEditable'] = $title->quickUserCan( 'edit', $user )