Merge "Add action/user tracking to html cache purge jobs"
[lhc/web/wiklou.git] / includes / page / WikiPage.php
index aa26105..8b34928 100644 (file)
@@ -88,12 +88,6 @@ class WikiPage implements Page, IDBAccessObject {
         */
        protected $mLinksUpdated = '19700101000000';
 
-       /** @deprecated since 1.29. Added in 1.28 for partial purging, no longer used. */
-       const PURGE_CDN_CACHE = 1;
-       const PURGE_CLUSTER_PCACHE = 2;
-       const PURGE_GLOBAL_PCACHE = 4;
-       const PURGE_ALL = 7;
-
        /**
         * Constructor and clear the article
         * @param Title $title Reference to a Title object.
@@ -164,8 +158,11 @@ class WikiPage implements Page, IDBAccessObject {
 
                $from = self::convertSelectType( $from );
                $db = wfGetDB( $from === self::READ_LATEST ? DB_MASTER : DB_REPLICA );
+               $pageQuery = self::getQueryInfo();
                $row = $db->selectRow(
-                       'page', self::selectFields(), [ 'page_id' => $id ], __METHOD__ );
+                       $pageQuery['tables'], $pageQuery['fields'], [ 'page_id' => $id ], __METHOD__,
+                       [], $pageQuery['joins']
+               );
                if ( !$row ) {
                        return null;
                }
@@ -283,11 +280,14 @@ class WikiPage implements Page, IDBAccessObject {
         * Return the list of revision fields that should be selected to create
         * a new page.
         *
+        * @deprecated since 1.31, use self::getQueryInfo() instead.
         * @return array
         */
        public static function selectFields() {
                global $wgContentHandlerUseDB, $wgPageLanguageUseDB;
 
+               wfDeprecated( __METHOD__, '1.31' );
+
                $fields = [
                        'page_id',
                        'page_namespace',
@@ -313,6 +313,47 @@ class WikiPage implements Page, IDBAccessObject {
                return $fields;
        }
 
+       /**
+        * Return the tables, fields, and join conditions to be selected to create
+        * a new page object.
+        * @since 1.31
+        * @return array With three keys:
+        *   - tables: (string[]) to include in the `$table` to `IDatabase->select()`
+        *   - fields: (string[]) to include in the `$vars` to `IDatabase->select()`
+        *   - joins: (array) to include in the `$join_conds` to `IDatabase->select()`
+        */
+       public static function getQueryInfo() {
+               global $wgContentHandlerUseDB, $wgPageLanguageUseDB;
+
+               $ret = [
+                       'tables' => [ 'page' ],
+                       'fields' => [
+                               'page_id',
+                               'page_namespace',
+                               'page_title',
+                               'page_restrictions',
+                               'page_is_redirect',
+                               'page_is_new',
+                               'page_random',
+                               'page_touched',
+                               'page_links_updated',
+                               'page_latest',
+                               'page_len',
+                       ],
+                       'joins' => [],
+               ];
+
+               if ( $wgContentHandlerUseDB ) {
+                       $ret['fields'][] = 'page_content_model';
+               }
+
+               if ( $wgPageLanguageUseDB ) {
+                       $ret['fields'][] = 'page_lang';
+               }
+
+               return $ret;
+       }
+
        /**
         * Fetch a page record with the given conditions
         * @param IDatabase $dbr
@@ -321,14 +362,23 @@ class WikiPage implements Page, IDBAccessObject {
         * @return object|bool Database result resource, or false on failure
         */
        protected function pageData( $dbr, $conditions, $options = [] ) {
-               $fields = self::selectFields();
+               $pageQuery = self::getQueryInfo();
 
                // Avoid PHP 7.1 warning of passing $this by reference
                $wikiPage = $this;
 
-               Hooks::run( 'ArticlePageDataBefore', [ &$wikiPage, &$fields ] );
+               Hooks::run( 'ArticlePageDataBefore', [
+                       &$wikiPage, &$pageQuery['fields'], &$pageQuery['tables'], &$pageQuery['joins']
+               ] );
 
-               $row = $dbr->selectRow( 'page', $fields, $conditions, __METHOD__, $options );
+               $row = $dbr->selectRow(
+                       $pageQuery['tables'],
+                       $pageQuery['fields'],
+                       $conditions,
+                       __METHOD__,
+                       $options,
+                       $pageQuery['joins']
+               );
 
                Hooks::run( 'ArticlePageDataAfter', [ &$wikiPage, &$row ] );
 
@@ -1134,18 +1184,6 @@ class WikiPage implements Page, IDBAccessObject {
                return true;
        }
 
-       /**
-        * Get the last time a user explicitly purged the page via action=purge
-        *
-        * @return string|bool TS_MW timestamp or false
-        * @since 1.28
-        * @deprecated since 1.29. It will always return false.
-        */
-       public function getLastPurgeTimestamp() {
-               wfDeprecated( __METHOD__, '1.29' );
-               return false;
-       }
-
        /**
         * Insert a new empty page record for this article.
         * This *must* be followed up by creating a revision
@@ -1667,27 +1705,27 @@ class WikiPage implements Page, IDBAccessObject {
                        throw new MWException( "Could not find text for current revision {$oldid}." );
                }
 
-               // @TODO: pass content object?!
-               $revision = new Revision( [
-                       'page'       => $this->getId(),
-                       'title'      => $this->mTitle, // for determining the default content model
-                       'comment'    => $summary,
-                       'minor_edit' => $meta['minor'],
-                       'text'       => $meta['serialized'],
-                       'len'        => $newsize,
-                       'parent_id'  => $oldid,
-                       'user'       => $user->getId(),
-                       'user_text'  => $user->getName(),
-                       'timestamp'  => $now,
-                       'content_model' => $content->getModel(),
-                       'content_format' => $meta['serialFormat'],
-               ] );
-
                $changed = !$content->equals( $oldContent );
 
                $dbw = wfGetDB( DB_MASTER );
 
                if ( $changed ) {
+                       // @TODO: pass content object?!
+                       $revision = new Revision( [
+                               'page'       => $this->getId(),
+                               'title'      => $this->mTitle, // for determining the default content model
+                               'comment'    => $summary,
+                               'minor_edit' => $meta['minor'],
+                               'text'       => $meta['serialized'],
+                               'len'        => $newsize,
+                               'parent_id'  => $oldid,
+                               'user'       => $user->getId(),
+                               'user_text'  => $user->getName(),
+                               'timestamp'  => $now,
+                               'content_model' => $content->getModel(),
+                               'content_format' => $meta['serialFormat'],
+                       ] );
+
                        $prepStatus = $content->prepareSave( $this, $flags, $oldid, $user );
                        $status->merge( $prepStatus );
                        if ( !$status->isOK() ) {
@@ -1753,11 +1791,9 @@ class WikiPage implements Page, IDBAccessObject {
                } else {
                        // T34948: revision ID must be set to page {{REVISIONID}} and
                        // related variables correctly. Likewise for {{REVISIONUSER}} (T135261).
-                       $revision->setId( $this->getLatest() );
-                       $revision->setUserIdAndName(
-                               $this->getUser( Revision::RAW ),
-                               $this->getUserText( Revision::RAW )
-                       );
+                       // Since we don't insert a new revision into the database, the least
+                       // error-prone way is to reuse given old revision.
+                       $revision = $meta['oldRevision'];
                }
 
                if ( $changed ) {
@@ -2806,13 +2842,13 @@ class WikiPage implements Page, IDBAccessObject {
                $revCommentStore = new CommentStore( 'rev_comment' );
                $arCommentStore = new CommentStore( 'ar_comment' );
 
-               $fields = Revision::selectFields();
+               $revQuery = Revision::getQueryInfo();
                $bitfield = false;
 
                // Bitfields to further suppress the content
                if ( $suppress ) {
                        $bitfield = Revision::SUPPRESSED_ALL;
-                       $fields = array_diff( $fields, [ 'rev_deleted' ] );
+                       $revQuery['fields'] = array_diff( $revQuery['fields'], [ 'rev_deleted' ] );
                }
 
                // For now, shunt the revision data into the archive table.
@@ -2823,14 +2859,13 @@ class WikiPage implements Page, IDBAccessObject {
                // the rev_deleted field, which is reserved for this purpose.
 
                // Get all of the page revisions
-               $commentQuery = $revCommentStore->getJoin();
                $res = $dbw->select(
-                       [ 'revision' ] + $commentQuery['tables'],
-                       $fields + $commentQuery['fields'],
+                       $revQuery['tables'],
+                       $revQuery['fields'],
                        [ 'rev_page' => $id ],
                        __METHOD__,
                        'FOR UPDATE',
-                       $commentQuery['joins']
+                       $revQuery['joins']
                );
 
                // Build their equivalent archive rows
@@ -3282,7 +3317,9 @@ class WikiPage implements Page, IDBAccessObject {
                MediaWikiServices::getInstance()->getLinkCache()->invalidateTitle( $title );
 
                // Invalidate caches of articles which include this page
-               DeferredUpdates::addUpdate( new HTMLCacheUpdate( $title, 'templatelinks' ) );
+               DeferredUpdates::addUpdate(
+                       new HTMLCacheUpdate( $title, 'templatelinks', 'page-create' )
+               );
 
                if ( $title->getNamespace() == NS_CATEGORY ) {
                        // Load the Category object, which will schedule a job to create
@@ -3320,7 +3357,9 @@ class WikiPage implements Page, IDBAccessObject {
 
                // Images
                if ( $title->getNamespace() == NS_FILE ) {
-                       DeferredUpdates::addUpdate( new HTMLCacheUpdate( $title, 'imagelinks' ) );
+                       DeferredUpdates::addUpdate(
+                               new HTMLCacheUpdate( $title, 'imagelinks', 'page-delete' )
+                       );
                }
 
                // User talk pages
@@ -3343,10 +3382,14 @@ class WikiPage implements Page, IDBAccessObject {
         */
        public static function onArticleEdit( Title $title, Revision $revision = null ) {
                // Invalidate caches of articles which include this page
-               DeferredUpdates::addUpdate( new HTMLCacheUpdate( $title, 'templatelinks' ) );
+               DeferredUpdates::addUpdate(
+                       new HTMLCacheUpdate( $title, 'templatelinks', 'page-edit' )
+               );
 
                // Invalidate the caches of all pages which redirect here
-               DeferredUpdates::addUpdate( new HTMLCacheUpdate( $title, 'redirect' ) );
+               DeferredUpdates::addUpdate(
+                       new HTMLCacheUpdate( $title, 'redirect', 'page-edit' )
+               );
 
                MediaWikiServices::getInstance()->getLinkCache()->invalidateTitle( $title );