/** * 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; }
/** * Tag output function must be called by caller * Parser cache control deferred to caller * @param $srev stable version * @param $tag review box/bar info * @param $prot protection notice * @return ParserOutput */ protected function showStableVersion(FlaggedRevision $srev, &$tag, $prot) { $reqUser = $this->getUser(); $this->load(); $flags = $srev->getTags(); $time = $this->getLang()->date($srev->getTimestamp(), true); # Set display revision ID $this->out->setRevisionId($srev->getRevId()); # Get quality level $quality = FlaggedRevs::isQuality($flags); $synced = $this->article->stableVersionIsSynced(); # Construct some tagging if (!$this->out->isPrintable() && !($this->article->lowProfileUI() && $synced)) { $revsSince = $this->article->getPendingRevCount(); // Simple icon-based UI if ($this->useSimpleUI()) { $icon = ''; # For protection based configs, show lock only if it's not redundant. if ($this->showRatingIcon()) { $icon = FlaggedRevsXML::stableStatusIcon($quality); } if (!$reqUser->getId()) { $msgHTML = ''; // Anons just see simple icons } else { $msg = $quality ? 'revreview-quick-quality' : 'revreview-quick-basic'; # Uses messages 'revreview-quick-quality-same', 'revreview-quick-basic-same' $msg = $synced ? "{$msg}-same" : $msg; $msgHTML = wfMsgExt($msg, 'parseinline', $srev->getRevId(), $revsSince); } $msgHTML = $prot . $icon . $msgHTML; $tag = FlaggedRevsXML::prettyRatingBox($srev, $msgHTML, $revsSince, 'stable', $synced); // Standard UI } else { $icon = FlaggedRevsXML::stableStatusIcon($quality); $msg = $quality ? 'revreview-quality' : 'revreview-basic'; if ($synced) { # uses messages 'revreview-quality-same', 'revreview-basic-same' $msg .= '-same'; } elseif ($revsSince == 0) { # uses messages 'revreview-quality-i', 'revreview-basic-i' $msg .= '-i'; } $tag = $prot . $icon; $tag .= wfMsgExt($msg, 'parseinline', $srev->getRevId(), $time, $revsSince); if (!empty($flags)) { $tag .= FlaggedRevsXML::ratingToggle(); $tag .= "<div id='mw-fr-revisiondetails' style='display:block;'>" . FlaggedRevsXML::addTagRatings($flags) . '</div>'; } } } # Get parsed stable version and output HTML $pOpts = $this->article->makeParserOptions($reqUser); $parserCache = FRParserCacheStable::singleton(); $parserOut = $parserCache->get($this->article, $pOpts); # Do not use the parser cache if it lacks mImageTimeKeys and there is a # chance that a review form will be added to this page (which requires the versions). $canReview = $this->article->getTitle()->userCan('review'); if ($parserOut && (!$canReview || FlaggedRevs::parserOutputIsVersioned($parserOut))) { # Cache hit. Note that redirects are not cached. $this->out->addParserOutput($parserOut); } else { $text = $srev->getRevText(); # Get the new stable parser output... $parserOut = FlaggedRevs::parseStableText($this->article->getTitle(), $text, $srev->getRevId(), $pOpts); $redirHtml = $this->getRedirectHtml($text); if ($redirHtml == '') { // page is not a redirect... # Update the stable version cache $parserCache->save($parserOut, $this->article, $pOpts); # Add the stable output to the page view $this->out->addParserOutput($parserOut); } else { // page is a redirect... $this->out->addHtml($redirHtml); # Add output to set categories, displaytitle, etc. $this->out->addParserOutputNoText($parserOut); } # Update the stable version dependancies FlaggedRevs::updateStableOnlyDeps($this->article, $parserOut); } # Update page sync status for tracking purposes. # NOTE: avoids master hits and doesn't have to be perfect for what it does if ($this->article->syncedInTracking() != $synced) { if (wfGetLB()->safeGetLag(wfGetDB(DB_SLAVE)) <= 5) { // avoid write-delay cycles $this->article->updateSyncStatus($synced); } } return $parserOut; }
/** * Detect if a ParserOutput object was added without mImageTimeKeys set. * This is needed for older, cached, ParserOutput objects. */ public static function outputSetVersioningFlag(OutputPage $out, ParserOutput $parserOut) { if (!FlaggedRevs::parserOutputIsVersioned($parserOut)) { $out->fr_unversionedIncludes = true; } return true; }