Merge "Introduce mediawiki.router for handling hash fragment navigation"
[lhc/web/wiklou.git] / includes / page / WikiPage.php
index 3308890..040a6f3 100644 (file)
  * @file
  */
 
-/**
- * Interface for type hinting (accepts WikiPage, Article, ImagePage, CategoryPage)
- */
-interface Page {
-}
-
 /**
  * Class representing a MediaWiki article and history.
  *
@@ -100,7 +94,7 @@ class WikiPage implements Page, IDBAccessObject {
         * @param Title $title
         *
         * @throws MWException
-        * @return WikiPage Object of the appropriate type
+        * @return WikiPage|WikiCategoryPage|WikiFilePage
         */
        public static function factory( Title $title ) {
                $ns = $title->getNamespace();
@@ -1351,76 +1345,6 @@ class WikiPage implements Page, IDBAccessObject {
                return $handler->getUndoContent( $this->getRevision(), $undo, $undoafter );
        }
 
-       /**
-        * Get the text that needs to be saved in order to undo all revisions
-        * between $undo and $undoafter. Revisions must belong to the same page,
-        * must exist and must not be deleted
-        * @param Revision $undo
-        * @param Revision $undoafter Must be an earlier revision than $undo
-        * @return string|bool String on success, false on failure
-        * @deprecated since 1.21: use ContentHandler::getUndoContent() instead.
-        */
-       public function getUndoText( Revision $undo, Revision $undoafter = null ) {
-               ContentHandler::deprecated( __METHOD__, '1.21' );
-
-               $this->loadLastEdit();
-
-               if ( $this->mLastRevision ) {
-                       if ( is_null( $undoafter ) ) {
-                               $undoafter = $undo->getPrevious();
-                       }
-
-                       $handler = $this->getContentHandler();
-                       $undone = $handler->getUndoContent( $this->mLastRevision, $undo, $undoafter );
-
-                       if ( !$undone ) {
-                               return false;
-                       } else {
-                               return ContentHandler::getContentText( $undone );
-                       }
-               }
-
-               return false;
-       }
-
-       /**
-        * @param string|number|null|bool $sectionId Section identifier as a number or string
-        * (e.g. 0, 1 or 'T-1'), null/false or an empty string for the whole page
-        * or 'new' for a new section.
-        * @param string $text New text of the section.
-        * @param string $sectionTitle New section's subject, only if $section is "new".
-        * @param string $edittime Revision timestamp or null to use the current revision.
-        *
-        * @throws MWException
-        * @return string|null New complete article text, or null if error.
-        *
-        * @deprecated since 1.21, use replaceSectionAtRev() instead
-        */
-       public function replaceSection( $sectionId, $text, $sectionTitle = '',
-               $edittime = null
-       ) {
-               ContentHandler::deprecated( __METHOD__, '1.21' );
-
-               // NOTE: keep condition in sync with condition in replaceSectionContent!
-               if ( strval( $sectionId ) === '' ) {
-                       // Whole-page edit; let the whole text through
-                       return $text;
-               }
-
-               if ( !$this->supportsSections() ) {
-                       throw new MWException( "sections not supported for content model " .
-                               $this->getContentHandler()->getModelID() );
-               }
-
-               // could even make section title, but that's not required.
-               $sectionContent = ContentHandler::makeContent( $text, $this->getTitle() );
-
-               $newContent = $this->replaceSectionContent( $sectionId, $sectionContent, $sectionTitle,
-                       $edittime );
-
-               return ContentHandler::getContentText( $newContent );
-       }
-
        /**
         * Returns true if this page's content model supports sections.
         *
@@ -2191,7 +2115,13 @@ class WikiPage implements Page, IDBAccessObject {
                        : '';
                $edit->pst = $edit->pstContent ? $edit->pstContent->serialize( $serialFormat ) : '';
 
+               if ( $edit->output ) {
+                       $edit->output->setCacheTime( wfTimestampNow() );
+               }
+
+               // Process cache the result
                $this->mPreparedEdit = $edit;
+
                return $edit;
        }
 
@@ -2261,6 +2191,7 @@ class WikiPage implements Page, IDBAccessObject {
                                DeferredUpdates::addUpdate( $update );
                        }
                        if ( $wgRCWatchCategoryMembership
+                               && $this->getContentHandler()->supportsCategories() === true
                                && ( $options['changed'] || $options['created'] )
                                && !$options['restored']
                        ) {
@@ -2403,10 +2334,13 @@ class WikiPage implements Page, IDBAccessObject {
         * @param int &$cascade Set to false if cascading protection isn't allowed.
         * @param string $reason
         * @param User $user The user updating the restrictions
-        * @return Status
+        * @param string|string[] $tags Change tags to add to the pages and protection log entries
+        *   ($user should be able to add the specified tags before this is called)
+        * @return Status Status object; if action is taken, $status->value is the log_id of the
+        *   protection log entry.
         */
        public function doUpdateRestrictions( array $limit, array $expiry,
-               &$cascade, $reason, User $user
+               &$cascade, $reason, User $user, $tags = null
        ) {
                global $wgCascadingRestrictionLevels, $wgContLang;
 
@@ -2488,6 +2422,9 @@ class WikiPage implements Page, IDBAccessObject {
                $logRelationsField = null;
                $logParamsDetails = [];
 
+               // Null revision (used for change tag insertion)
+               $nullRevision = null;
+
                if ( $id ) { // Protection of existing page
                        if ( !Hooks::run( 'ArticleProtect', [ &$this, &$user, $limit, $reason ] ) ) {
                                return Status::newGood();
@@ -2631,13 +2568,17 @@ class WikiPage implements Page, IDBAccessObject {
                $logEntry->setComment( $reason );
                $logEntry->setPerformer( $user );
                $logEntry->setParameters( $params );
+               if ( !is_null( $nullRevision ) ) {
+                       $logEntry->setAssociatedRevId( $nullRevision->getId() );
+               }
+               $logEntry->setTags( $tags );
                if ( $logRelationsField !== null && count( $logRelationsValues ) ) {
                        $logEntry->setRelations( [ $logRelationsField => $logRelationsValues ] );
                }
                $logId = $logEntry->insert();
                $logEntry->publish( $logId );
 
-               return Status::newGood();
+               return Status::newGood( $logId );
        }
 
        /**
@@ -2869,7 +2810,7 @@ class WikiPage implements Page, IDBAccessObject {
                $dbw->startAtomic( __METHOD__ );
 
                $this->loadPageData( self::READ_LATEST );
-               $id = $this->getID();
+               $id = $this->getId();
                // T98706: lock the page from various other updates but avoid using
                // WikiPage::READ_LOCKING as that will carry over the FOR UPDATE to
                // the revisions queries (which also JOIN on user). Only lock the page
@@ -3568,6 +3509,8 @@ class WikiPage implements Page, IDBAccessObject {
                        return;
                }
 
+               $config = RequestContext::getMain()->getConfig();
+
                $params = [
                        'isOpportunistic' => true,
                        'rootJobTimestamp' => $parserOutput->getCacheTime()
@@ -3578,7 +3521,7 @@ class WikiPage implements Page, IDBAccessObject {
                        JobQueueGroup::singleton()->lazyPush(
                                RefreshLinksJob::newPrioritized( $this->mTitle, $params )
                        );
-               } elseif ( $parserOutput->hasDynamicContent() ) {
+               } elseif ( !$config->get( 'MiserMode' ) && $parserOutput->hasDynamicContent() ) {
                        // Assume the output contains "dynamic" time/random based magic words.
                        // Only update pages that expired due to dynamic content and NOT due to edits
                        // to referenced templates/files. When the cache expires due to dynamic content,
@@ -3590,7 +3533,8 @@ class WikiPage implements Page, IDBAccessObject {
                                // Although it would be de-duplicated, it would still waste I/O.
                                $cache = ObjectCache::getLocalClusterInstance();
                                $key = $cache->makeKey( 'dynamic-linksupdate', 'last', $this->getId() );
-                               if ( $cache->add( $key, time(), 60 ) ) {
+                               $ttl = max( $parserOutput->getCacheExpiry(), 3600 );
+                               if ( $cache->add( $key, time(), $ttl ) ) {
                                        JobQueueGroup::singleton()->lazyPush(
                                                RefreshLinksJob::newDynamic( $this->mTitle, $params )
                                        );