/** * Get template and image versions from parsing a revision * @param Page $article * @param Revision $rev * @param User $user * @param string $regen use 'regen' to force regeneration * @return array( templateIds, fileSHA1Keys ) * templateIds like ParserOutput->mTemplateIds * fileSHA1Keys like ParserOutput->mImageTimeKeys */ public static function getRevIncludes(Page $article, Revision $rev, User $user, $regen = '') { global $wgParser, $wgMemc; wfProfileIn(__METHOD__); $versions = false; $key = self::getCacheKey($article->getTitle(), $rev->getId()); if ($regen !== 'regen') { // check cache $versions = FlaggedRevs::getMemcValue($wgMemc->get($key), $article, 'allowStale'); } if (!is_array($versions)) { // cache miss $pOut = false; if ($rev->isCurrent()) { $parserCache = ParserCache::singleton(); # Try current version parser cache (as anon)... $pOut = $parserCache->get($article, $article->makeParserOptions($user)); if ($pOut == false && $rev->getUser()) { // try the user who saved the change $author = User::newFromId($rev->getUser()); $pOut = $parserCache->get($article, $article->makeParserOptions($author)); } } // ParserOutput::mImageTimeKeys wasn't always there if ($pOut == false || !FlaggedRevs::parserOutputIsVersioned($pOut)) { $title = $article->getTitle(); $pOpts = ParserOptions::newFromUser($user); // Note: tidy off $pOut = $wgParser->parse($rev->getText(), $title, $pOpts, true, true, $rev->getId()); } # Get the template/file versions used... $versions = array($pOut->getTemplateIds(), $pOut->getFileSearchOptions()); # Save to cache (check cache expiry for dynamic elements)... $data = FlaggedRevs::makeMemcObj($versions); $wgMemc->set($key, $data, $pOut->getCacheExpiry()); } else { $tVersions =& $versions[0]; // templates # Do a link batch query for page_latest... $lb = new LinkBatch(); foreach ($tVersions as $ns => $tmps) { foreach ($tmps as $dbKey => $revIdDraft) { $lb->add($ns, $dbKey); } } $lb->execute(); # Update array with the current page_latest values. # This kludge is there since $newTemplates (thus $revIdDraft) is cached. foreach ($tVersions as $ns => &$tmps) { foreach ($tmps as $dbKey => &$revIdDraft) { $title = Title::makeTitle($ns, $dbKey); $revIdDraft = (int) $title->getLatestRevID(); } } } wfProfileOut(__METHOD__); return $versions; }
/** * Get template and image versions from parsing a revision * @param Page $article * @param Revision $rev * @param User $user * @param string $regen use 'regen' to force regeneration * @return array( templateIds, fileSHA1Keys ) * templateIds like ParserOutput->mTemplateIds * fileSHA1Keys like ParserOutput->mImageTimeKeys */ public static function getRevIncludes(Page $article, Revision $rev, User $user, $regen = '') { global $wgMemc; wfProfileIn(__METHOD__); $key = self::getCacheKey($article->getTitle(), $rev->getId()); if ($regen === 'regen') { $versions = false; // skip cache } elseif ($rev->isCurrent()) { // Check cache entry against page_touched $versions = FlaggedRevs::getMemcValue($wgMemc->get($key), $article); } else { // Old revs won't always be invalidated with template/file changes. // Also, we don't care if page_touched changed due to a direct edit. $versions = FlaggedRevs::getMemcValue($wgMemc->get($key), $article, 'allowStale'); if (is_array($versions)) { // entry exists // Sanity check that the cache is reasonably up to date list($templates, $files) = $versions; if (self::templatesStale($templates) || self::filesStale($files)) { $versions = false; // no good } } } if (!is_array($versions)) { // cache miss $pOut = false; if ($rev->isCurrent()) { $parserCache = ParserCache::singleton(); # Try current version parser cache for this user... $pOut = $parserCache->get($article, $article->makeParserOptions($user)); if ($pOut == false) { # Try current version parser cache for the revision author... $optsUser = $rev->getUser() ? User::newFromId($rev->getUser()) : 'canonical'; $pOut = $parserCache->get($article, $article->makeParserOptions($optsUser)); } } // ParserOutput::mImageTimeKeys wasn't always there if ($pOut == false || !FlaggedRevs::parserOutputIsVersioned($pOut)) { $content = $rev->getContent(Revision::RAW); if (!$content) { // Just for extra sanity $pOut = new ParserOutput(); } else { $pOut = $content->getParserOutput($article->getTitle(), $rev->getId(), ParserOptions::newFromUser($user)); } } # Get the template/file versions used... $versions = array($pOut->getTemplateIds(), $pOut->getFileSearchOptions()); # Save to cache (check cache expiry for dynamic elements)... $data = FlaggedRevs::makeMemcObj($versions); $wgMemc->set($key, $data, $pOut->getCacheExpiry()); } wfProfileOut(__METHOD__); return $versions; }
/** * Checks if the stable version is synced with the current revision * Note: slower than getPendingRevCount() * @return bool */ public function stableVersionIsSynced() { global $wgMemc, $wgParserCacheExpireTime; $srev = $this->getStableRev(); if (!$srev) { return true; } # Stable text revision must be the same as the current if ($this->revsArePending()) { return false; # Stable file revision must be the same as the current } elseif ($this->mTitle->getNamespace() == NS_FILE) { $file = $this->getFile(); // current upload version if ($file && $file->getTimestamp() > $srev->getFileTimestamp()) { return false; } } # If using the current version of includes, there is nothing else to check. if (FlaggedRevs::inclusionSetting() == FR_INCLUDES_CURRENT) { return true; // short-circuit } # Try the cache... $key = wfMemcKey('flaggedrevs', 'includesSynced', $this->getId()); $value = FlaggedRevs::getMemcValue($wgMemc->get($key), $this); if ($value === "true") { return true; } elseif ($value === "false") { return false; } # Since the stable and current revisions have the same text and only outputs, # the only other things to check for are template and file differences in the output. # (a) Check if the current output has a newer template/file used # (b) Check if the stable version has a file/template that was deleted $synced = !$srev->findPendingTemplateChanges() && !$srev->findPendingFileChanges('noForeign'); # Save to cache. This will be updated whenever the page is touched. $data = FlaggedRevs::makeMemcObj($synced ? "true" : "false"); $wgMemc->set($key, $data, $wgParserCacheExpireTime); return $synced; }
public static function overrideRedirect(Title $title, WebRequest $request, &$ignoreRedirect, &$target, Article &$article) { global $wgMemc, $wgParserCacheExpireTime; $fa = FlaggableWikiPage::getTitleInstance($title); // on $wgTitle if (!$fa->isReviewable()) { return true; // nothing to do } # Viewing an old reviewed version... if ($request->getVal('stableid')) { $ignoreRedirect = true; // don't redirect (same as ?oldid=x) return true; } $srev = $fa->getStableRev(); $view = FlaggablePageView::singleton(); # Check if we are viewing an unsynced stable version... if ($srev && $view->showingStable() && $srev->getRevId() != $article->getLatest()) { # Check the stable redirect properties from the cache... $key = wfMemcKey('flaggedrevs', 'overrideRedirect', $article->getId()); $tuple = FlaggedRevs::getMemcValue($wgMemc->get($key), $article); if (is_array($tuple)) { // cache hit list($ignoreRedirect, $target) = $tuple; } else { // cache miss; fetch the stable rev text... $text = $srev->getRevText(); $redirect = $fa->getRedirectURL(Title::newFromRedirectRecurse($text)); if ($redirect) { $target = $redirect; // use stable redirect } else { $ignoreRedirect = true; // make MW skip redirection } $data = FlaggedRevs::makeMemcObj(array($ignoreRedirect, $target)); $wgMemc->set($key, $data, $wgParserCacheExpireTime); // cache results } $clearEnvironment = (bool) $target; # Check if the we are viewing a draft or synced stable version... } else { # In both cases, we can just let MW use followRedirect() # on the draft as normal, avoiding any page text hits. $clearEnvironment = $article->isRedirect(); } # Environment (e.g. $wgTitle) will change in MediaWiki::initializeArticle if ($clearEnvironment) { $view->clear(); } return true; }