* @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;
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 ) ) {
$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()
+ }
}
}
/**
* 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 {
* @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
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
*
/**
* 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
*/
$fragment,
$this->getInterwiki()
);
-
}
/**
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.
# 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;
* restrictions from page table (pre 1.10)
*/
public function loadRestrictions( $oldFashionedRestrictions = null ) {
- if ( !$this->mRestrictionsLoaded ) {
- $dbr = wfGetDB( DB_REPLICA );
- 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;
}
}
* 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()
*
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() );
$conds + [ 'page_touched < ' . $dbw->addQuotes( $dbTimestamp ) ],
$fname
);
+ MediaWikiServices::getInstance()->getLinkCache()->invalidateTitle( $this );
}
),
DeferredUpdates::PRESEND
: $wgExemptFromUserRobotsControl;
return !in_array( $this->mNamespace, $bannedNamespaces );
-
}
/**