/**
  * 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;
 }