/** * @depends testUpdateToSetPredefinedAnnotations */ public function testDoUpdateUsingUserdefinedAnnotations() { $this->pageCreator->createPage($this->title)->doEdit('[[HasFirstLinksUpdatetest::testDoUpdate]] [[HasSecondLinksUpdatetest::testDoUpdate]]'); $parserData = $this->applicationFactory->newParserData($this->title, $this->pageCreator->getEditInfo()->output); $contentParser = $this->applicationFactory->newContentParser($this->title); $contentParser->parse(); $parsedParserData = $this->applicationFactory->newParserData($this->title, $contentParser->getOutput()); $this->assertCount(4, $parserData->getSemanticData()->getProperties()); $this->assertCount(4, $this->getStore()->getSemanticData(DIWikiPage::newFromTitle($this->title))->getProperties()); /** * See #347 and LinksUpdateConstructed */ $linksUpdate = new \LinksUpdate($this->title, new \ParserOutput()); $linksUpdate->doUpdate(); $this->testEnvironment->executePendingDeferredUpdates(); /** * Asserts that before and after the update, the SemanticData container * holds the same amount of properties despite the fact that the ParserOutput * was invoked empty */ $semanticData = $this->getStore()->getSemanticData(DIWikiPage::newFromTitle($this->title)); $this->assertCount(4, $semanticData->getProperties()); $expected = array('propertyKeys' => array('_SKEY', '_MDAT', 'HasFirstLinksUpdatetest', 'HasSecondLinksUpdatetest')); $this->semanticDataValidator->assertThatPropertiesAreSet($expected, $semanticData); return $this->pageCreator->getPage()->getRevision(); }
/** * Run a refreshLinks job * @return boolean success */ function run() { global $wgParser; wfProfileIn(__METHOD__); $linkCache =& LinkCache::singleton(); $linkCache->clear(); if (is_null($this->title)) { $this->error = "refreshLinks: Invalid title"; wfProfileOut(__METHOD__); return false; } $revision = Revision::newFromTitle($this->title); if (!$revision) { $this->error = 'refreshLinks: Article not found "' . $this->title->getPrefixedDBkey() . '"'; wfProfileOut(__METHOD__); return false; } wfProfileIn(__METHOD__ . '-parse'); $options = new ParserOptions(); $parserOutput = $wgParser->parse($revision->getText(), $this->title, $options, true, true, $revision->getId()); wfProfileOut(__METHOD__ . '-parse'); wfProfileIn(__METHOD__ . '-update'); $update = new LinksUpdate($this->title, $parserOutput, false); $update->doUpdate(); wfProfileOut(__METHOD__ . '-update'); wfProfileOut(__METHOD__); return true; }
/** * Call LinksUpdate on the text of this page's approved revision, * if there is one. */ public static function updateLinksAfterEdit(&$page, &$editInfo, $changed) { $title = $page->getTitle(); if (!ApprovedRevs::pageIsApprovable($title)) { return true; } // If this user's revisions get approved automatically, // exit now, because this will be the approved // revision anyway. if (self::userRevsApprovedAutomatically($title)) { return true; } $text = ''; $approvedText = ApprovedRevs::getApprovedContent($title); if (!is_null($approvedText)) { $text = $approvedText; } // If there's no approved revision, and 'blank if // unapproved' is set to true, set the text to blank. if (is_null($approvedText)) { global $egApprovedRevsBlankIfUnapproved; if ($egApprovedRevsBlankIfUnapproved) { $text = ''; } else { // If it's an unapproved page and there's no // page blanking, exit here. return true; } } $editInfo = $page->prepareTextForEdit($text); $u = new LinksUpdate($page->mTitle, $editInfo->output); $u->doUpdate(); return true; }
function fixLinksFromArticle( $id ) { global $wgTitle, $wgParser; $wgTitle = Title::newFromID( $id ); $dbw = wfGetDB( DB_MASTER ); $linkCache =& LinkCache::singleton(); $linkCache->clear(); if ( is_null( $wgTitle ) ) { return; } $dbw->begin(); $revision = Revision::newFromTitle( $wgTitle ); if ( !$revision ) { return; } $options = new ParserOptions; $parserOutput = $wgParser->parse( $revision->getText(), $wgTitle, $options, true, true, $revision->getId() ); $update = new LinksUpdate( $wgTitle, $parserOutput, false ); $update->doUpdate(); $dbw->commit(); }
/** * Purges the cache of a page */ public function execute() { global $wgUser; $params = $this->extractRequestParams(); if (!$wgUser->isAllowed('purge') && !$this->getMain()->isInternalMode() && !$this->getMain()->getRequest()->wasPosted()) { $this->dieUsageMsg(array('mustbeposted', $this->getModuleName())); } $forceLinkUpdate = $params['forcelinkupdate']; $result = array(); foreach ($params['titles'] as $t) { $r = array(); $title = Title::newFromText($t); if (!$title instanceof Title) { $r['title'] = $t; $r['invalid'] = ''; $result[] = $r; continue; } ApiQueryBase::addTitleInfo($r, $title); if (!$title->exists()) { $r['missing'] = ''; $result[] = $r; continue; } $context = $this->createContext(); $context->setTitle($title); $article = Article::newFromTitle($title, $context); $article->doPurge(); // Directly purge and skip the UI part of purge(). $r['purged'] = ''; if ($forceLinkUpdate) { if (!$wgUser->pingLimiter()) { global $wgParser, $wgEnableParserCache; $popts = new ParserOptions(); $p_result = $wgParser->parse($article->getContent(), $title, $popts); # Update the links tables $u = new LinksUpdate($title, $p_result); $u->doUpdate(); $r['linkupdate'] = ''; if ($wgEnableParserCache) { $pcache = ParserCache::singleton(); $pcache->save($p_result, $article, $popts); } } else { $this->setWarning($this->parseMsg(array('actionthrottledtext'))); $forceLinkUpdate = false; } } $result[] = $r; } $apiResult = $this->getResult(); $apiResult->setIndexedTagName($result, 'page'); $apiResult->addValue(null, $this->getModuleName(), $result); }
protected function assertLinksUpdate(Title $title, ParserOutput $parserOutput, $table, $fields, $condition, array $expectedRows) { $update = new LinksUpdate($title, $parserOutput); $update->doUpdate(); $this->assertSelect($table, $fields, $condition, $expectedRows); }
/** * Updates cascading protections * * @param $parserOutput ParserOutput object for the current version */ public function doCascadeProtectionUpdates( ParserOutput $parserOutput ) { if ( wfReadOnly() || !$this->mTitle->areRestrictionsCascading() ) { return; } // templatelinks table may have become out of sync, // especially if using variable-based transclusions. // For paranoia, check if things have changed and if // so apply updates to the database. This will ensure // that cascaded protections apply as soon as the changes // are visible. // Get templates from templatelinks $id = $this->getId(); $tlTemplates = array(); $dbr = wfGetDB( DB_SLAVE ); $res = $dbr->select( array( 'templatelinks' ), array( 'tl_namespace', 'tl_title' ), array( 'tl_from' => $id ), __METHOD__ ); foreach ( $res as $row ) { $tlTemplates["{$row->tl_namespace}:{$row->tl_title}"] = true; } // Get templates from parser output. $poTemplates = array(); foreach ( $parserOutput->getTemplates() as $ns => $templates ) { foreach ( $templates as $dbk => $id ) { $poTemplates["$ns:$dbk"] = true; } } // Get the diff $templates_diff = array_diff_key( $poTemplates, $tlTemplates ); if ( count( $templates_diff ) > 0 ) { // Whee, link updates time. // Note: we are only interested in links here. We don't need to get other DataUpdate items from the parser output. $u = new LinksUpdate( $this->mTitle, $parserOutput, false ); $u->doUpdate(); } }
/** * Do standard deferred updates after page edit. * Update links tables, site stats, search index and message cache. * Every 1000th edit, prune the recent changes table. * * @private * @param $text New text of the article * @param $summary Edit summary * @param $minoredit Minor edit * @param $timestamp_of_pagechange Timestamp associated with the page change * @param $newid rev_id value of the new revision * @param $changed Whether or not the content actually changed */ function editUpdates($text, $summary, $minoredit, $timestamp_of_pagechange, $newid, $changed = true) { global $wgDeferredUpdateList, $wgMessageCache, $wgUser, $wgParser; wfProfileIn(__METHOD__); # Parse the text $options = new ParserOptions(); $options->setTidy(true); $poutput = $wgParser->parse($text, $this->mTitle, $options, true, true, $newid); # Save it to the parser cache $parserCache =& ParserCache::singleton(); $parserCache->save($poutput, $this, $wgUser); # Update the links tables $u = new LinksUpdate($this->mTitle, $poutput); $u->doUpdate(); if (wfRunHooks('ArticleEditUpdatesDeleteFromRecentchanges', array(&$this))) { wfSeedRandom(); if (0 == mt_rand(0, 999)) { # Periodically flush old entries from the recentchanges table. global $wgRCMaxAge; $dbw =& wfGetDB(DB_MASTER); $cutoff = $dbw->timestamp(time() - $wgRCMaxAge); $recentchanges = $dbw->tableName('recentchanges'); $sql = "DELETE FROM {$recentchanges} WHERE rc_timestamp < '{$cutoff}'"; $dbw->query($sql); } } $id = $this->getID(); $title = $this->mTitle->getPrefixedDBkey(); $shortTitle = $this->mTitle->getDBkey(); if (0 == $id) { wfProfileOut(__METHOD__); return; } $u = new SiteStatsUpdate(0, 1, $this->mGoodAdjustment, $this->mTotalAdjustment); array_push($wgDeferredUpdateList, $u); $u = new SearchUpdate($id, $title, $text); array_push($wgDeferredUpdateList, $u); # If this is another user's talk page, update newtalk # Don't do this if $changed = false otherwise some idiot can null-edit a # load of user talk pages and piss people off, nor if it's a minor edit # by a properly-flagged bot. if ($this->mTitle->getNamespace() == NS_USER_TALK && $shortTitle != $wgUser->getTitleKey() && $changed && !($minoredit && $wgUser->isAllowed('nominornewtalk'))) { if (wfRunHooks('ArticleEditUpdateNewTalk', array(&$this))) { $other = User::newFromName($shortTitle); if (is_null($other) && User::isIP($shortTitle)) { // An anonymous user $other = new User(); $other->setName($shortTitle); } if ($other) { $other->setNewtalk(true); } } } if ($this->mTitle->getNamespace() == NS_MEDIAWIKI) { $wgMessageCache->replace($shortTitle, $text); } wfProfileOut(__METHOD__); }
protected function assertLinksUpdate(Title $title, ParserOutput $parserOutput, $table, $fields, $condition, array $expectedRows) { $update = new LinksUpdate($title, $parserOutput); // NOTE: make sure LinksUpdate does not generate warnings when called inside a transaction. $update->beginTransaction(); $update->doUpdate(); $update->commitTransaction(); $this->assertSelect($table, $fields, $condition, $expectedRows); return $update; }
/** * Run LinksUpdate for all links on a given page_id * @param $id int The page_id */ public static function fixLinksFromArticle($id) { global $wgParser, $wgContLang; $page = WikiPage::newFromID($id); LinkCache::singleton()->clear(); if ($page === null) { return; } $text = $page->getRawText(); if ($text === false) { return; } $dbw = wfGetDB(DB_MASTER); $dbw->begin(__METHOD__); $options = ParserOptions::newFromUserAndLang(new User(), $wgContLang); $parserOutput = $wgParser->parse($text, $page->getTitle(), $options, true, true, $page->getLatest()); $update = new LinksUpdate($page->getTitle(), $parserOutput, false); $update->doUpdate(); $dbw->commit(__METHOD__); }
public function updateLinks($parserOutput) { $update = new \LinksUpdate($this->title, $parserOutput, false); $update->doUpdate(); }
protected function doCascadeProtectionUpdates($parserOutput) { if (!$this->isCurrent() || wfReadOnly() || !$this->mTitle->areRestrictionsCascading()) { return; } // templatelinks table may have become out of sync, // especially if using variable-based transclusions. // For paranoia, check if things have changed and if // so apply updates to the database. This will ensure // that cascaded protections apply as soon as the changes // are visible. # Get templates from templatelinks $id = $this->mTitle->getArticleID(); $tlTemplates = array(); $dbr = wfGetDB(DB_SLAVE); $res = $dbr->select(array('templatelinks'), array('tl_namespace', 'tl_title'), array('tl_from' => $id), __METHOD__); global $wgContLang; foreach ($res as $row) { $tlTemplates["{$row->tl_namespace}:{$row->tl_title}"] = true; } # Get templates from parser output. $poTemplates = array(); foreach ($parserOutput->getTemplates() as $ns => $templates) { foreach ($templates as $dbk => $id) { $poTemplates["{$ns}:{$dbk}"] = true; } } # Get the diff # Note that we simulate array_diff_key in PHP <5.0.x $templates_diff = array_diff_key($poTemplates, $tlTemplates); if (count($templates_diff) > 0) { # Whee, link updates time. $u = new LinksUpdate($this->mTitle, $parserOutput, false); $u->doUpdate(); } }
/** * Run a refreshLinks2 job * @return boolean success */ function run() { global $wgParser; wfProfileIn(__METHOD__); $linkCache = LinkCache::singleton(); $linkCache->clear(); if (is_null($this->title)) { $this->error = "refreshLinks2: Invalid title"; wfProfileOut(__METHOD__); return false; } if (!isset($this->params['start']) || !isset($this->params['end'])) { $this->error = "refreshLinks2: Invalid params"; wfProfileOut(__METHOD__); return false; } $start = intval($this->params['start']); $end = intval($this->params['end']); $dbr = wfGetDB(DB_SLAVE); $res = $dbr->select(array('templatelinks', 'page'), array('page_namespace', 'page_title'), array('page_id=tl_from', "tl_from >= '{$start}'", "tl_from <= '{$end}'", 'tl_namespace' => $this->title->getNamespace(), 'tl_title' => $this->title->getDBkey()), __METHOD__); # Not suitable for page load triggered job running! # Gracefully switch to refreshLinks jobs if this happens. if (php_sapi_name() != 'cli') { $jobs = array(); while ($row = $dbr->fetchObject($res)) { $title = Title::makeTitle($row->page_namespace, $row->page_title); $jobs[] = new RefreshLinksJob($title, ''); } Job::batchInsert($jobs); return true; } # Re-parse each page that transcludes this page and update their tracking links... while ($row = $dbr->fetchObject($res)) { $title = Title::makeTitle($row->page_namespace, $row->page_title); $revision = Revision::newFromTitle($title); if (!$revision) { $this->error = 'refreshLinks: Article not found "' . $title->getPrefixedDBkey() . '"'; wfProfileOut(__METHOD__); return false; } wfProfileIn(__METHOD__ . '-parse'); $options = new ParserOptions(); $parserOutput = $wgParser->parse($revision->getText(), $title, $options, true, true, $revision->getId()); wfProfileOut(__METHOD__ . '-parse'); wfProfileIn(__METHOD__ . '-update'); $update = new LinksUpdate($title, $parserOutput, false); $update->doUpdate(); wfProfileOut(__METHOD__ . '-update'); wfProfileOut(__METHOD__); } return true; }
/** * Run a refreshLinks job * @return boolean success */ function refreshLinks() { global $wgParser; $fname = 'Job::refreshLinks'; wfProfileIn($fname); $dbw =& wfGetDB(DB_MASTER); $linkCache =& LinkCache::singleton(); $linkCache->clear(); if (is_null($this->title)) { $this->error = "refreshLinks: Invalid title"; wfProfileOut($fname); return false; } $revision = Revision::newFromTitle($this->title); if (!$revision) { $this->error = 'refreshLinks: Article not found "' . $this->title->getPrefixedDBkey() . '"'; wfProfileOut($fname); return false; } wfProfileIn("{$fname}-parse"); $options = new ParserOptions(); $parserOutput = $wgParser->parse($revision->getText(), $this->title, $options, true, true, $revision->getId()); wfProfileOut("{$fname}-parse"); wfProfileIn("{$fname}-update"); $update = new LinksUpdate($this->title, $parserOutput, false); $update->doUpdate(); wfProfileOut("{$fname}-update"); wfProfileOut($fname); return true; }
/** * Run a refreshLinks2 job * @return boolean success */ function run() { global $wgParser, $wgContLang; wfProfileIn(__METHOD__); $linkCache = LinkCache::singleton(); $linkCache->clear(); if (is_null($this->title)) { $this->error = "refreshLinks2: Invalid title"; wfProfileOut(__METHOD__); return false; } if (!isset($this->params['start']) || !isset($this->params['end'])) { $this->error = "refreshLinks2: Invalid params"; wfProfileOut(__METHOD__); return false; } // Back compat for pre-r94435 jobs $table = isset($this->params['table']) ? $this->params['table'] : 'templatelinks'; $titles = $this->title->getBacklinkCache()->getLinks($table, $this->params['start'], $this->params['end']); # Not suitable for page load triggered job running! # Gracefully switch to refreshLinks jobs if this happens. if (php_sapi_name() != 'cli') { $jobs = array(); foreach ($titles as $title) { $jobs[] = new RefreshLinksJob($title, ''); } Job::batchInsert($jobs); wfProfileOut(__METHOD__); return true; } $options = ParserOptions::newFromUserAndLang(new User(), $wgContLang); # Re-parse each page that transcludes this page and update their tracking links... foreach ($titles as $title) { $revision = Revision::newFromTitle($title); if (!$revision) { $this->error = 'refreshLinks: Article not found "' . $title->getPrefixedDBkey() . '"'; wfProfileOut(__METHOD__); return false; } wfProfileIn(__METHOD__ . '-parse'); $parserOutput = $wgParser->parse($revision->getText(), $title, $options, true, true, $revision->getId()); wfProfileOut(__METHOD__ . '-parse'); wfProfileIn(__METHOD__ . '-update'); $update = new LinksUpdate($title, $parserOutput, false); $update->doUpdate(); wfProfileOut(__METHOD__ . '-update'); wfWaitForSlaves(); } wfProfileOut(__METHOD__); return true; }
/** * Add the primary page-view wikitext to the output buffer * Saves the text into the parser cache if possible. * Updates templatelinks if it is out of date. * * @param $text String * @param $cache Boolean */ public function outputWikiText($text, $cache = true) { global $wgParser, $wgUser, $wgOut, $wgEnableParserCache, $wgUseFileCache; $popts = $wgOut->parserOptions(); $popts->setTidy(true); $popts->enableLimitReport(); $parserOutput = $wgParser->parse($text, $this->mTitle, $popts, true, true, $this->getRevIdFetched()); $popts->setTidy(false); $popts->enableLimitReport(false); if ($wgEnableParserCache && $cache && $this && $parserOutput->getCacheTime() != -1) { $parserCache = ParserCache::singleton(); $parserCache->save($parserOutput, $this, $wgUser); } // Make sure file cache is not used on uncacheable content. // Output that has magic words in it can still use the parser cache // (if enabled), though it will generally expire sooner. if ($parserOutput->getCacheTime() == -1 || $parserOutput->containsOldMagic()) { $wgUseFileCache = false; } if ($this->isCurrent() && !wfReadOnly() && $this->mTitle->areRestrictionsCascading()) { // templatelinks table may have become out of sync, // especially if using variable-based transclusions. // For paranoia, check if things have changed and if // so apply updates to the database. This will ensure // that cascaded protections apply as soon as the changes // are visible. # Get templates from templatelinks $id = $this->mTitle->getArticleID(); $tlTemplates = array(); $dbr = wfGetDB(DB_SLAVE); $res = $dbr->select(array('templatelinks'), array('tl_namespace', 'tl_title'), array('tl_from' => $id), __METHOD__); global $wgContLang; if ($res !== false) { foreach ($res as $row) { $tlTemplates[] = $wgContLang->getNsText($row->tl_namespace) . ':' . $row->tl_title; } } # Get templates from parser output. $poTemplates_allns = $parserOutput->getTemplates(); $poTemplates = array(); foreach ($poTemplates_allns as $ns_templates) { $poTemplates = array_merge($poTemplates, $ns_templates); } # Get the diff $templates_diff = array_diff($poTemplates, $tlTemplates); if (count($templates_diff) > 0) { # Whee, link updates time. $u = new LinksUpdate($this->mTitle, $parserOutput); $u->doUpdate(); } } $wgOut->addParserOutput($parserOutput); }
/** * Add the primary page-view wikitext to the output buffer * Saves the text into the parser cache if possible. * Updates templatelinks if it is out of date. * * @param string $text * @param bool $cache */ public function outputWikiText($text, $cache = true) { global $wgParser, $wgUser, $wgOut, $wgEnableParserCache; wfRunHooks('ArticleBeforeOutputWikiText', array(&$this, &$text)); $popts = $wgOut->parserOptions(); $popts->setTidy(true); $popts->enableLimitReport(); $parserOutput = $wgParser->parse($text, $this->mTitle, $popts, true, true, $this->getRevIdFetched()); $popts->setTidy(false); $popts->enableLimitReport(false); if ($wgEnableParserCache && $cache && $this && $parserOutput->getCacheTime() != -1) { $parserCache =& ParserCache::singleton(); $parserCache->save($parserOutput, $this, $wgUser); } if (!wfReadOnly() && $this->mTitle->areRestrictionsCascading()) { // templatelinks table may have become out of sync, // especially if using variable-based transclusions. // For paranoia, check if things have changed and if // so apply updates to the database. This will ensure // that cascaded protections apply as soon as the changes // are visible. # Get templates from templatelinks $id = $this->mTitle->getArticleID(); $tlTemplates = array(); $dbr = wfGetDB(DB_SLAVE); $res = $dbr->select(array('templatelinks'), array('tl_namespace', 'tl_title'), array('tl_from' => $id), 'Article:getUsedTemplates'); global $wgContLang; if (false !== $res) { if ($dbr->numRows($res)) { while ($row = $dbr->fetchObject($res)) { $tlTemplates[] = $wgContLang->getNsText($row->tl_namespace) . ':' . $row->tl_title; } } } # Get templates from parser output. $poTemplates_allns = $parserOutput->getTemplates(); $poTemplates = array(); foreach ($poTemplates_allns as $ns_templates) { $poTemplates = array_merge($poTemplates, $ns_templates); } # Get the diff $templates_diff = array_diff($poTemplates, $tlTemplates); if (count($templates_diff) > 0) { # Whee, link updates time. $u = new LinksUpdate($this->mTitle, $parserOutput); $dbw = wfGetDb(DB_MASTER); $dbw->begin(); $u->doUpdate(); $dbw->commit(); } } wfRunHooks('ArticleAfterOutputWikiText', array(&$parserOutput)); $wgOut->addParserOutput($parserOutput); }
/** * Unsets the approved revision for this page in the approved_revs DB * table; calls a "links update" on this page so that category * information can be stored correctly, as well as info for * extensions such as Semantic MediaWiki; and logs the action. */ public static function unsetApproval($title) { global $egApprovedRevsBlankIfUnapproved; self::deleteRevisionApproval($title); $parser = new Parser(); $parser->setTitle($title); if ($egApprovedRevsBlankIfUnapproved) { $text = ''; } else { $text = self::getPageText($title); } $options = new ParserOptions(); $parser->parse($text, $title, $options); $u = new LinksUpdate($title, $parser->getOutput()); $u->doUpdate(); self::setPageSearchText($title, $text); $log = new LogPage('approval'); $log->addEntry('unapprove', $title, ''); wfRunHooks('ApprovedRevsRevisionUnapproved', array($parser, $title)); }
protected function assertRecentChangeByCategorization(Title $pageTitle, ParserOutput $parserOutput, Title $categoryTitle, $expectedRows) { $update = new LinksUpdate($pageTitle, $parserOutput); $revision = Revision::newFromTitle($pageTitle); $update->setRevision($revision); $update->beginTransaction(); $update->doUpdate(); $update->commitTransaction(); $this->assertSelect('recentchanges', 'rc_title, rc_comment', array('rc_type' => RC_CATEGORIZE, 'rc_namespace' => NS_CATEGORY, 'rc_title' => $categoryTitle->getDBkey()), $expectedRows); }
/** * This is the meaty bit -- restores archived revisions of the given page * to the cur/old tables. If the page currently exists, all revisions will * be stuffed into old, otherwise the most recent will go into cur. * * @param array $timestamps Pass an empty array to restore all revisions, otherwise list the ones to undelete. * @param string $comment * @param array $fileVersions * * @return int number of revisions restored */ private function undeleteRevisions($timestamps) { global $wgParser, $wgDBtype; $fname = __CLASS__ . '::' . __FUNCTION__; $restoreAll = empty($timestamps); $dbw =& wfGetDB(DB_MASTER); extract($dbw->tableNames('page', 'archive')); # Does this page already exist? We'll have to update it... $article = new Article($this->title); $options = $wgDBtype == 'postgres' ? '' : 'FOR UPDATE'; $page = $dbw->selectRow('page', array('page_id', 'page_latest'), array('page_namespace' => $this->title->getNamespace(), 'page_title' => $this->title->getDBkey()), $fname, $options); if ($page) { # Page already exists. Import the history, and if necessary # we'll update the latest revision field in the record. $newid = 0; $pageId = $page->page_id; $previousRevId = $page->page_latest; } else { # Have to create a new article... $newid = $article->insertOn($dbw); $pageId = $newid; $previousRevId = 0; } if ($restoreAll) { $oldones = '1 = 1'; # All revisions... } else { $oldts = implode(',', array_map(array(&$dbw, 'addQuotes'), array_map(array(&$dbw, 'timestamp'), $timestamps))); $oldones = "ar_timestamp IN ( {$oldts} )"; } /** * Restore each revision... */ $result = $dbw->select('archive', array('ar_rev_id', 'ar_text', 'ar_comment', 'ar_user', 'ar_user_text', 'ar_timestamp', 'ar_minor_edit', 'ar_flags', 'ar_text_id'), array('ar_namespace' => $this->title->getNamespace(), 'ar_title' => $this->title->getDBkey(), $oldones), $fname, array('ORDER BY' => 'ar_timestamp')); if ($dbw->numRows($result) < count($timestamps)) { wfDebug("{$fname}: couldn't find all requested rows\n"); return false; } $revision = null; $newRevId = $previousRevId; $restored = 0; while ($row = $dbw->fetchObject($result)) { if ($row->ar_text_id) { // Revision was deleted in 1.5+; text is in // the regular text table, use the reference. // Specify null here so the so the text is // dereferenced for page length info if needed. $revText = null; } else { // Revision was deleted in 1.4 or earlier. // Text is squashed into the archive row, and // a new text table entry will be created for it. $revText = Revision::getRevisionText($row, 'ar_'); } $revision = new Revision(array('page' => $pageId, 'id' => $row->ar_rev_id, 'text' => $revText, 'comment' => $row->ar_comment, 'user' => $row->ar_user, 'user_text' => $row->ar_user_text, 'timestamp' => $row->ar_timestamp, 'minor_edit' => $row->ar_minor_edit, 'text_id' => $row->ar_text_id)); $newRevId = $revision->insertOn($dbw); $restored++; } if ($revision) { # FIXME: Update latest if newer as well... if ($newid) { # FIXME: update article count if changed... $article->updateRevisionOn($dbw, $revision, $previousRevId); # Finally, clean up the link tables $options = new ParserOptions(); $parserOutput = $wgParser->parse($revision->getText(), $this->title, $options, true, true, $newRevId); $u = new LinksUpdate($this->title, $parserOutput); $u->doUpdate(); #TODO: SearchUpdate, etc. } // WERELATE: watch article global $wgUser; $watchthis = false; if ($newid) { Article::onArticleCreate($this->title); $watchthis = $wgUser->getOption('watchcreations') || $wgUser->getOption('watchdefault'); } else { Article::onArticleEdit($this->title); $watchthis = $wgUser->getOption('watchdefault'); } if ($watchthis && !$article->getTitle()->userIsWatching()) { $article->doWatch(); } } else { # Something went terribly wrong! } # Now that it's safely stored, take it out of the archive $dbw->delete('archive', array('ar_namespace' => $this->title->getNamespace(), 'ar_title' => $this->title->getDBkey(), $oldones), $fname); return $restored; }