/** * Wrapper around Revision::newFromTitle to allow passing additional parameters * without passing them on to it. * * @since 1.24 * @param Title $title * @param Parser|bool $parser * @return Revision|bool False if missing */ public static function statelessFetchRevision(Title $title, $parser = false) { $pageId = $title->getArticleID(); $revId = $title->getLatestRevID(); $rev = Revision::newKnownCurrent(wfGetDB(DB_REPLICA), $pageId, $revId); if ($rev) { $rev->setTitle($title); } return $rev; }
/** * Loads everything except the text * This isn't necessary for all uses, so it's only done if needed. */ protected function loadLastEdit() { if ($this->mLastRevision !== null) { return; // already loaded } $latest = $this->getLatest(); if (!$latest) { return; // page doesn't exist or is missing page_latest info } if ($this->mDataLoadedFrom == self::READ_LOCKING) { // Bug 37225: if session S1 loads the page row FOR UPDATE, the result always // includes the latest changes committed. This is true even within REPEATABLE-READ // transactions, where S1 normally only sees changes committed before the first S1 // SELECT. Thus we need S1 to also gets the revision row FOR UPDATE; otherwise, it // may not find it since a page row UPDATE and revision row INSERT by S2 may have // happened after the first S1 SELECT. // http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html#isolevel_repeatable-read $flags = Revision::READ_LOCKING; $revision = Revision::newFromPageId($this->getId(), $latest, $flags); } elseif ($this->mDataLoadedFrom == self::READ_LATEST) { // Bug T93976: if page_latest was loaded from the master, fetch the // revision from there as well, as it may not exist yet on a replica DB. // Also, this keeps the queries in the same REPEATABLE-READ snapshot. $flags = Revision::READ_LATEST; $revision = Revision::newFromPageId($this->getId(), $latest, $flags); } else { $dbr = wfGetDB(DB_REPLICA); $revision = Revision::newKnownCurrent($dbr, $this->getId(), $latest); } if ($revision) { // sanity $this->setLastEdit($revision); } }
/** * Get a message from the MediaWiki namespace, with caching. The key must * first be converted to two-part lang/msg form if necessary. * * Unlike self::get(), this function doesn't resolve fallback chains, and * some callers require this behavior. LanguageConverter::parseCachedTable() * and self::get() are some examples in core. * * @param string $title Message cache key with initial uppercase letter. * @param string $code Code denoting the language to try. * @return string|bool The message, or false if it does not exist or on error */ public function getMsgFromNamespace($title, $code) { $this->load($code); if (isset($this->mCache[$code][$title])) { $entry = $this->mCache[$code][$title]; if (substr($entry, 0, 1) === ' ') { // The message exists, so make sure a string // is returned. return (string) substr($entry, 1); } elseif ($entry === '!NONEXISTENT') { return false; } elseif ($entry === '!TOO BIG') { // Fall through and try invididual message cache below } } else { // XXX: This is not cached in process cache, should it? $message = false; Hooks::run('MessagesPreLoad', [$title, &$message]); if ($message !== false) { return $message; } return false; } // Try the individual message cache $titleKey = wfMemcKey('messages', 'individual', $title); $curTTL = null; $entry = $this->wanCache->get($titleKey, $curTTL, [wfMemcKey('messages', $code)]); $entry = $curTTL >= 0 ? $entry : false; if ($entry) { if (substr($entry, 0, 1) === ' ') { $this->mCache[$code][$title] = $entry; // The message exists, so make sure a string is returned return (string) substr($entry, 1); } elseif ($entry === '!NONEXISTENT') { $this->mCache[$code][$title] = '!NONEXISTENT'; return false; } else { // Corrupt/obsolete entry, delete it $this->wanCache->delete($titleKey); } } // Try loading it from the database $dbr = wfGetDB(DB_REPLICA); $cacheOpts = Database::getCacheSetOptions($dbr); // Use newKnownCurrent() to avoid querying revision/user tables $titleObj = Title::makeTitle(NS_MEDIAWIKI, $title); if ($titleObj->getLatestRevID()) { $revision = Revision::newKnownCurrent($dbr, $titleObj->getArticleID(), $titleObj->getLatestRevID()); } else { $revision = false; } if ($revision) { $content = $revision->getContent(); if (!$content) { // A possibly temporary loading failure. wfDebugLog('MessageCache', __METHOD__ . ": failed to load message page text for {$title} ({$code})"); $message = null; // no negative caching } else { // XXX: Is this the right way to turn a Content object into a message? // NOTE: $content is typically either WikitextContent, JavaScriptContent or // CssContent. MessageContent is *not* used for storing messages, it's // only used for wrapping them when needed. $message = $content->getWikitextForTransclusion(); if ($message === false || $message === null) { wfDebugLog('MessageCache', __METHOD__ . ": message content doesn't provide wikitext " . "(content model: " . $content->getModel() . ")"); $message = false; // negative caching } else { $this->mCache[$code][$title] = ' ' . $message; $this->wanCache->set($titleKey, ' ' . $message, $this->mExpiry, $cacheOpts); } } } else { $message = false; // negative caching } if ($message === false) { // negative caching $this->mCache[$code][$title] = '!NONEXISTENT'; $this->wanCache->set($titleKey, '!NONEXISTENT', $this->mExpiry, $cacheOpts); } return $message; }