Remove empty lines at end of functions
[lhc/web/wiklou.git] / includes / Title.php
index 2021e0a..3c51bae 100644 (file)
@@ -91,7 +91,13 @@ class Title implements LinkTarget {
         * @var bool|string ID of the page's content model, i.e. one of the
         *   CONTENT_MODEL_XXX constants
         */
-       public $mContentModel = false;
+       private $mContentModel = false;
+
+       /**
+        * @var bool If a content model was forced via setContentModel()
+        *   this will be true to avoid having other code paths reset it
+        */
+       private $mForcedContentModel = false;
 
        /** @var int Estimated number of revisions; null of not loaded */
        private $mEstimateRevisions;
@@ -394,7 +400,7 @@ class Title implements LinkTarget {
         * @return Title|null The new object, or null on an error
         */
        public static function newFromID( $id, $flags = 0 ) {
-               $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
+               $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_REPLICA );
                $row = $db->selectRow(
                        'page',
                        self::getSelectFields(),
@@ -419,7 +425,7 @@ class Title implements LinkTarget {
                if ( !count( $ids ) ) {
                        return [];
                }
-               $dbr = wfGetDB( DB_SLAVE );
+               $dbr = wfGetDB( DB_REPLICA );
 
                $res = $dbr->select(
                        'page',
@@ -467,9 +473,9 @@ class Title implements LinkTarget {
                        if ( isset( $row->page_latest ) ) {
                                $this->mLatestID = (int)$row->page_latest;
                        }
-                       if ( isset( $row->page_content_model ) ) {
+                       if ( !$this->mForcedContentModel && isset( $row->page_content_model ) ) {
                                $this->mContentModel = strval( $row->page_content_model );
-                       } else {
+                       } elseif ( !$this->mForcedContentModel ) {
                                $this->mContentModel = false; # initialized lazily in getContentModel()
                        }
                        if ( isset( $row->page_lang ) ) {
@@ -483,7 +489,9 @@ class Title implements LinkTarget {
                        $this->mLength = 0;
                        $this->mRedirect = false;
                        $this->mLatestID = 0;
-                       $this->mContentModel = false; # initialized lazily in getContentModel()
+                       if ( !$this->mForcedContentModel ) {
+                               $this->mContentModel = false; # initialized lazily in getContentModel()
+                       }
                }
        }
 
@@ -561,7 +569,7 @@ class Title implements LinkTarget {
         * @return Title|null An object representing the article, or null if no such article was found
         */
        public static function nameOf( $id ) {
-               $dbr = wfGetDB( DB_SLAVE );
+               $dbr = wfGetDB( DB_REPLICA );
 
                $s = $dbr->selectRow(
                        'page',
@@ -751,12 +759,12 @@ class Title implements LinkTarget {
        /**
         * Callback for usort() to do title sorts by (namespace, title)
         *
-        * @param Title $a
-        * @param Title $b
+        * @param LinkTarget $a
+        * @param LinkTarget $b
         *
         * @return int Result of string comparison, or namespace comparison
         */
-       public static function compare( $a, $b ) {
+       public static function compare( LinkTarget $a, LinkTarget $b ) {
                if ( $a->getNamespace() == $b->getNamespace() ) {
                        return strcmp( $a->getText(), $b->getText() );
                } else {
@@ -921,8 +929,9 @@ class Title implements LinkTarget {
         * @return string Content model id
         */
        public function getContentModel( $flags = 0 ) {
-               if ( ( !$this->mContentModel || $flags === Title::GAID_FOR_UPDATE ) &&
-                       $this->getArticleID( $flags )
+               if ( !$this->mForcedContentModel
+                       && ( !$this->mContentModel || $flags === Title::GAID_FOR_UPDATE )
+                       && $this->getArticleID( $flags )
                ) {
                        $linkCache = LinkCache::singleton();
                        $linkCache->addLinkObj( $this ); # in case we already had an article ID
@@ -946,6 +955,22 @@ class Title implements LinkTarget {
                return $this->getContentModel() == $id;
        }
 
+       /**
+        * Set a proposed content model for the page for permissions
+        * checking. This does not actually change the content model
+        * of a title!
+        *
+        * Additionally, you should make sure you've checked
+        * ContentHandler::canBeUsedOn() first.
+        *
+        * @since 1.28
+        * @param string $model CONTENT_MODEL_XXX constant
+        */
+       public function setContentModel( $model ) {
+               $this->mContentModel = $model;
+               $this->mForcedContentModel = true;
+       }
+
        /**
         * Get the namespace text
         *
@@ -1079,7 +1104,7 @@ class Title implements LinkTarget {
        /**
         * Returns true if the title is inside one of the specified namespaces.
         *
-        * @param int $namespaces,... The namespaces to check for
+        * @param int|int[] $namespaces,... The namespaces to check for
         * @return bool
         * @since 1.19
         */
@@ -1387,7 +1412,6 @@ class Title implements LinkTarget {
                        $fragment,
                        $this->getInterwiki()
                );
-
        }
 
        /**
@@ -1886,8 +1910,8 @@ class Title implements LinkTarget {
         * @param string $action Action that permission needs to be checked for
         * @param User $user User to check
         * @param string $rigor One of (quick,full,secure)
-        *   - quick  : does cheap permission checks from slaves (usable for GUI creation)
-        *   - full   : does cheap and expensive checks possibly from a slave
+        *   - quick  : does cheap permission checks from replica DBs (usable for GUI creation)
+        *   - full   : does cheap and expensive checks possibly from a replica DB
         *   - secure : does cheap and expensive checks, using the master as needed
         * @param array $ignoreErrors Array of Strings Set this to a list of message keys
         *   whose corresponding errors may be ignored.
@@ -2416,8 +2440,8 @@ class Title implements LinkTarget {
         * @param string $action Action that permission needs to be checked for
         * @param User $user User to check
         * @param string $rigor One of (quick,full,secure)
-        *   - quick  : does cheap permission checks from slaves (usable for GUI creation)
-        *   - full   : does cheap and expensive checks possibly from a slave
+        *   - quick  : does cheap permission checks from replica DBs (usable for GUI creation)
+        *   - full   : does cheap and expensive checks possibly from a replica DB
         *   - secure : does cheap and expensive checks, using the master as needed
         * @param bool $short Set this to true to stop after the first permission error.
         * @return array Array of arrays of the arguments to wfMessage to explain permissions problems.
@@ -2540,7 +2564,7 @@ class Title implements LinkTarget {
                }
 
                if ( $this->mTitleProtection === null ) {
-                       $dbr = wfGetDB( DB_SLAVE );
+                       $dbr = wfGetDB( DB_REPLICA );
                        $res = $dbr->select(
                                'protected_titles',
                                [
@@ -2708,7 +2732,7 @@ class Title implements LinkTarget {
                        return [ $this->mHasCascadingRestrictions, $pagerestrictions ];
                }
 
-               $dbr = wfGetDB( DB_SLAVE );
+               $dbr = wfGetDB( DB_REPLICA );
 
                if ( $this->getNamespace() == NS_FILE ) {
                        $tables = [ 'imagelinks', 'page_restrictions' ];
@@ -2848,23 +2872,6 @@ class Title implements LinkTarget {
                return $this->mCascadeRestriction;
        }
 
-       /**
-        * Loads a string into mRestrictions array
-        *
-        * @param ResultWrapper $res Resource restrictions as an SQL result.
-        * @param string $oldFashionedRestrictions Comma-separated list of page
-        *        restrictions from page table (pre 1.10)
-        */
-       private function loadRestrictionsFromResultWrapper( $res, $oldFashionedRestrictions = null ) {
-               $rows = [];
-
-               foreach ( $res as $row ) {
-                       $rows[] = $row;
-               }
-
-               $this->loadRestrictionsFromRows( $rows, $oldFashionedRestrictions );
-       }
-
        /**
         * Compiles list of active page restrictions from both page table (pre 1.10)
         * and page_restrictions table for this existing page.
@@ -2875,7 +2882,7 @@ class Title implements LinkTarget {
         *   restrictions from page table (pre 1.10)
         */
        public function loadRestrictionsFromRows( $rows, $oldFashionedRestrictions = null ) {
-               $dbr = wfGetDB( DB_SLAVE );
+               $dbr = wfGetDB( DB_REPLICA );
 
                $restrictionTypes = $this->getRestrictionTypes();
 
@@ -2918,7 +2925,6 @@ class Title implements LinkTarget {
 
                        # Cycle through all the restrictions.
                        foreach ( $rows as $row ) {
-
                                // Don't take care of restrictions types that aren't allowed
                                if ( !in_array( $row->pr_type, $restrictionTypes ) ) {
                                        continue;
@@ -2948,36 +2954,53 @@ class Title implements LinkTarget {
         *   restrictions from page table (pre 1.10)
         */
        public function loadRestrictions( $oldFashionedRestrictions = null ) {
-               if ( !$this->mRestrictionsLoaded ) {
-                       $dbr = wfGetDB( DB_SLAVE );
-                       if ( $this->exists() ) {
-                               $res = $dbr->select(
-                                       'page_restrictions',
-                                       [ 'pr_type', 'pr_expiry', 'pr_level', 'pr_cascade' ],
-                                       [ 'pr_page' => $this->getArticleID() ],
-                                       __METHOD__
-                               );
+               if ( $this->mRestrictionsLoaded ) {
+                       return;
+               }
 
-                               $this->loadRestrictionsFromResultWrapper( $res, $oldFashionedRestrictions );
-                       } else {
-                               $title_protection = $this->getTitleProtection();
-
-                               if ( $title_protection ) {
-                                       $now = wfTimestampNow();
-                                       $expiry = $dbr->decodeExpiry( $title_protection['expiry'] );
-
-                                       if ( !$expiry || $expiry > $now ) {
-                                               // Apply the restrictions
-                                               $this->mRestrictionsExpiry['create'] = $expiry;
-                                               $this->mRestrictions['create'] = explode( ',', trim( $title_protection['permission'] ) );
-                                       } else { // Get rid of the old restrictions
-                                               $this->mTitleProtection = false;
-                                       }
-                               } else {
-                                       $this->mRestrictionsExpiry['create'] = 'infinity';
+               $id = $this->getArticleID();
+               if ( $id ) {
+                       $cache = ObjectCache::getMainWANInstance();
+                       $rows = $cache->getWithSetCallback(
+                               // Page protections always leave a new null revision
+                               $cache->makeKey( 'page-restrictions', $id, $this->getLatestRevID() ),
+                               $cache::TTL_DAY,
+                               function ( $curValue, &$ttl, array &$setOpts ) {
+                                       $dbr = wfGetDB( DB_REPLICA );
+
+                                       $setOpts += Database::getCacheSetOptions( $dbr );
+
+                                       return iterator_to_array(
+                                               $dbr->select(
+                                                       'page_restrictions',
+                                                       [ 'pr_type', 'pr_expiry', 'pr_level', 'pr_cascade' ],
+                                                       [ 'pr_page' => $this->getArticleID() ],
+                                                       __METHOD__
+                                               )
+                                       );
                                }
-                               $this->mRestrictionsLoaded = true;
+                       );
+
+                       $this->loadRestrictionsFromRows( $rows, $oldFashionedRestrictions );
+               } else {
+                       $title_protection = $this->getTitleProtection();
+
+                       if ( $title_protection ) {
+                               $now = wfTimestampNow();
+                               $expiry = wfGetDB( DB_REPLICA )->decodeExpiry( $title_protection['expiry'] );
+
+                               if ( !$expiry || $expiry > $now ) {
+                                       // Apply the restrictions
+                                       $this->mRestrictionsExpiry['create'] = $expiry;
+                                       $this->mRestrictions['create'] =
+                                               explode( ',', trim( $title_protection['permission'] ) );
+                               } else { // Get rid of the old restrictions
+                                       $this->mTitleProtection = false;
+                               }
+                       } else {
+                               $this->mRestrictionsExpiry['create'] = 'infinity';
                        }
+                       $this->mRestrictionsLoaded = true;
                }
        }
 
@@ -3069,7 +3092,7 @@ class Title implements LinkTarget {
                        return [];
                }
 
-               $dbr = wfGetDB( DB_SLAVE );
+               $dbr = wfGetDB( DB_REPLICA );
                $conds['page_namespace'] = $this->getNamespace();
                $conds[] = 'page_title ' . $dbr->buildLike( $this->getDBkey() . '/', $dbr->anyString() );
                $options = [];
@@ -3096,7 +3119,7 @@ class Title implements LinkTarget {
                if ( $this->getNamespace() < 0 ) {
                        $n = 0;
                } else {
-                       $dbr = wfGetDB( DB_SLAVE );
+                       $dbr = wfGetDB( DB_REPLICA );
 
                        $n = $dbr->selectField( 'archive', 'COUNT(*)',
                                [ 'ar_namespace' => $this->getNamespace(), 'ar_title' => $this->getDBkey() ],
@@ -3121,7 +3144,7 @@ class Title implements LinkTarget {
                if ( $this->getNamespace() < 0 ) {
                        return false;
                }
-               $dbr = wfGetDB( DB_SLAVE );
+               $dbr = wfGetDB( DB_REPLICA );
                $deleted = (bool)$dbr->selectField( 'archive', '1',
                        [ 'ar_namespace' => $this->getNamespace(), 'ar_title' => $this->getDBkey() ],
                        __METHOD__
@@ -3258,7 +3281,7 @@ class Title implements LinkTarget {
         * This clears some fields in this object, and clears any associated
         * keys in the "bad links" section of the link cache.
         *
-        * - This is called from WikiPage::doEdit() and WikiPage::insertOn() to allow
+        * - This is called from WikiPage::doEditContent() and WikiPage::insertOn() to allow
         * loading of the new page_id. It's also called from
         * WikiPage::doDeleteArticleReal()
         *
@@ -3375,7 +3398,7 @@ class Title implements LinkTarget {
                if ( count( $options ) > 0 ) {
                        $db = wfGetDB( DB_MASTER );
                } else {
-                       $db = wfGetDB( DB_SLAVE );
+                       $db = wfGetDB( DB_REPLICA );
                }
 
                $res = $db->select(
@@ -3437,7 +3460,7 @@ class Title implements LinkTarget {
                        return [];
                }
 
-               $db = wfGetDB( DB_SLAVE );
+               $db = wfGetDB( DB_REPLICA );
 
                $blNamespace = "{$prefix}_namespace";
                $blTitle = "{$prefix}_title";
@@ -3500,7 +3523,7 @@ class Title implements LinkTarget {
                        return [];
                }
 
-               $dbr = wfGetDB( DB_SLAVE );
+               $dbr = wfGetDB( DB_REPLICA );
                $res = $dbr->select(
                        [ 'page', 'pagelinks' ],
                        [ 'pl_namespace', 'pl_title' ],
@@ -3860,7 +3883,7 @@ class Title implements LinkTarget {
                        return $data;
                }
 
-               $dbr = wfGetDB( DB_SLAVE );
+               $dbr = wfGetDB( DB_REPLICA );
 
                $res = $dbr->select(
                        'categorylinks',
@@ -3928,7 +3951,7 @@ class Title implements LinkTarget {
         * @return int|bool Old revision ID, or false if none exists
         */
        public function getPreviousRevisionID( $revId, $flags = 0 ) {
-               $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
+               $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_REPLICA );
                $revId = $db->selectField( 'revision', 'rev_id',
                        [
                                'rev_page' => $this->getArticleID( $flags ),
@@ -3953,7 +3976,7 @@ class Title implements LinkTarget {
         * @return int|bool Next revision ID, or false if none exists
         */
        public function getNextRevisionID( $revId, $flags = 0 ) {
-               $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
+               $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_REPLICA );
                $revId = $db->selectField( 'revision', 'rev_id',
                        [
                                'rev_page' => $this->getArticleID( $flags ),
@@ -3979,7 +4002,7 @@ class Title implements LinkTarget {
        public function getFirstRevision( $flags = 0 ) {
                $pageId = $this->getArticleID( $flags );
                if ( $pageId ) {
-                       $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
+                       $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_REPLICA );
                        $row = $db->selectRow( 'revision', Revision::selectFields(),
                                [ 'rev_page' => $pageId ],
                                __METHOD__,
@@ -4009,7 +4032,7 @@ class Title implements LinkTarget {
         * @return bool
         */
        public function isNewPage() {
-               $dbr = wfGetDB( DB_SLAVE );
+               $dbr = wfGetDB( DB_REPLICA );
                return (bool)$dbr->selectField( 'page', 'page_is_new', $this->pageCond(), __METHOD__ );
        }
 
@@ -4026,7 +4049,7 @@ class Title implements LinkTarget {
                }
 
                if ( $this->mIsBigDeletion === null ) {
-                       $dbr = wfGetDB( DB_SLAVE );
+                       $dbr = wfGetDB( DB_REPLICA );
 
                        $revCount = $dbr->selectRowCount(
                                'revision',
@@ -4053,7 +4076,7 @@ class Title implements LinkTarget {
                }
 
                if ( $this->mEstimateRevisions === null ) {
-                       $dbr = wfGetDB( DB_SLAVE );
+                       $dbr = wfGetDB( DB_REPLICA );
                        $this->mEstimateRevisions = $dbr->estimateRowCount( 'revision', '*',
                                [ 'rev_page' => $this->getArticleID() ], __METHOD__ );
                }
@@ -4080,7 +4103,7 @@ class Title implements LinkTarget {
                if ( !$old || !$new ) {
                        return 0; // nothing to compare
                }
-               $dbr = wfGetDB( DB_SLAVE );
+               $dbr = wfGetDB( DB_REPLICA );
                $conds = [
                        'rev_page' => $this->getArticleID(),
                        'rev_timestamp > ' . $dbr->addQuotes( $dbr->timestamp( $old->getTimestamp() ) ),
@@ -4158,7 +4181,7 @@ class Title implements LinkTarget {
                        }
                        return $authors;
                }
-               $dbr = wfGetDB( DB_SLAVE );
+               $dbr = wfGetDB( DB_REPLICA );
                $res = $dbr->select( 'revision', 'DISTINCT rev_user_text',
                        [
                                'rev_page' => $this->getArticleID(),
@@ -4366,16 +4389,19 @@ class Title implements LinkTarget {
        public function invalidateCache( $purgeTime = null ) {
                if ( wfReadOnly() ) {
                        return false;
-               }
-
-               if ( $this->mArticleID === 0 ) {
+               } elseif ( $this->mArticleID === 0 ) {
                        return true; // avoid gap locking if we know it's not there
                }
 
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->onTransactionPreCommitOrIdle( function () {
+                       ResourceLoaderWikiModule::invalidateModuleCache( $this, null, null, wfWikiID() );
+               } );
+
                $conds = $this->pageCond();
                DeferredUpdates::addUpdate(
                        new AutoCommitUpdate(
-                               wfGetDB( DB_MASTER ),
+                               $dbw,
                                __METHOD__,
                                function ( IDatabase $dbw, $fname ) use ( $conds, $purgeTime ) {
                                        $dbTimestamp = $dbw->timestamp( $purgeTime ?: time() );
@@ -4385,6 +4411,7 @@ class Title implements LinkTarget {
                                                $conds + [ 'page_touched < ' . $dbw->addQuotes( $dbTimestamp ) ],
                                                $fname
                                        );
+                                       MediaWikiServices::getInstance()->getLinkCache()->invalidateTitle( $this );
                                }
                        ),
                        DeferredUpdates::PRESEND
@@ -4413,7 +4440,7 @@ class Title implements LinkTarget {
         */
        public function getTouched( $db = null ) {
                if ( $db === null ) {
-                       $db = wfGetDB( DB_SLAVE );
+                       $db = wfGetDB( DB_REPLICA );
                }
                $touched = $db->selectField( 'page', 'page_touched', $this->pageCond(), __METHOD__ );
                return $touched;
@@ -4497,7 +4524,7 @@ class Title implements LinkTarget {
        public function getRedirectsHere( $ns = null ) {
                $redirs = [];
 
-               $dbr = wfGetDB( DB_SLAVE );
+               $dbr = wfGetDB( DB_REPLICA );
                $where = [
                        'rd_namespace' => $this->getNamespace(),
                        'rd_title' => $this->getDBkey(),
@@ -4571,7 +4598,6 @@ class Title implements LinkTarget {
                        : $wgExemptFromUserRobotsControl;
 
                return !in_array( $this->mNamespace, $bannedNamespaces );
-
        }
 
        /**