示例#1
0
 function setUp()
 {
     global $wgContLang, $wgUser, $wgLanguageCode;
     $wgContLang = Language::factory($wgLanguageCode);
     $this->popts = ParserOptions::newFromUserAndLang($wgUser, $wgContLang);
     $this->pcache = ParserCache::singleton();
 }
示例#2
0
 protected function setUp()
 {
     global $wgParserConf, $wgContLang;
     parent::setUp();
     $this->mOptions = ParserOptions::newFromUserAndLang(new User(), $wgContLang);
     $name = isset($wgParserConf['preprocessorClass']) ? $wgParserConf['preprocessorClass'] : 'Preprocessor_DOM';
     $this->mPreprocessor = new $name($this);
 }
示例#3
0
 /**
  * @dataProvider provideBadNames
  * @expectedException MWException
  * @covers Parser::setFunctionTagHook
  */
 public function testBadFunctionTagHooks($tag)
 {
     global $wgParserConf, $wgContLang;
     $parser = new Parser($wgParserConf);
     $parser->setFunctionTagHook($tag, array($this, 'functionTagCallback'), Parser::SFH_OBJECT_ARGS);
     $parser->parse("Foo<{$tag}>Bar</{$tag}>Baz", Title::newFromText('Test'), ParserOptions::newFromUserAndLang(new User(), $wgContLang));
     $this->fail('Exception not thrown.');
 }
示例#4
0
 /**
  * @dataProvider dataPreloadTransform
  */
 public function testPreloadTransform($text, $expected)
 {
     global $wgContLang;
     $options = ParserOptions::newFromUserAndLang($this->context->getUser(), $wgContLang);
     $content = $this->newContent($text);
     $content = $content->preloadTransform($this->context->getTitle(), $options);
     $this->assertEquals($expected, $content->getNativeData());
 }
 protected function setUp()
 {
     global $wgLanguageCode, $wgUser;
     parent::setUp();
     $langObj = Language::factory($wgLanguageCode);
     $this->setMwGlobals(array('wgContLang' => $langObj, 'wgUseDynamicDates' => true));
     $this->popts = ParserOptions::newFromUserAndLang($wgUser, $langObj);
     $this->pcache = ParserCache::singleton();
 }
示例#6
0
 protected function setUp()
 {
     global $wgContLang;
     parent::setUp();
     $this->mOptions = ParserOptions::newFromUserAndLang(new User(), $wgContLang);
     $this->mPreprocessors = [];
     foreach (self::$classNames as $className) {
         $this->mPreprocessors[$className] = new $className($this);
     }
 }
 protected function setUp()
 {
     parent::setUp();
     $contLang = Language::factory('en');
     $this->setMwGlobals(array('wgShowDBErrorBacktrace' => true, 'wgLanguageCode' => 'en', 'wgContLang' => $contLang, 'wgLang' => Language::factory('en'), 'wgMemc' => new EmptyBagOStuff(), 'wgAlwaysUseTidy' => false, 'wgCleanSignatures' => true));
     $this->options = ParserOptions::newFromUserAndLang(new User(), $contLang);
     $this->options->setTemplateCallback(array(__CLASS__, 'statelessFetchTemplate'));
     $this->parser = new Parser();
     MagicWord::clearCache();
 }
 protected function setUp()
 {
     global $wgContLang;
     parent::setUp();
     $this->testParserOptions = ParserOptions::newFromUserAndLang(new User(), $wgContLang);
     $this->testParser = new Parser();
     $this->testParser->Options($this->testParserOptions);
     $this->testParser->clearState();
     $this->title = Title::newFromText('Preload Test');
 }
 public static function runForTitleInternal(Title $title, Revision $revision, $fname)
 {
     global $wgParser, $wgContLang;
     wfProfileIn($fname . '-parse');
     $options = ParserOptions::newFromUserAndLang(new User(), $wgContLang);
     $parserOutput = $wgParser->parse($revision->getText(), $title, $options, true, true, $revision->getId());
     wfProfileOut($fname . '-parse');
     wfProfileIn($fname . '-update');
     $updates = $parserOutput->getSecondaryDataUpdates($title, false);
     DataUpdate::runUpdates($updates);
     wfProfileOut($fname . '-update');
 }
示例#10
0
 protected function setUp()
 {
     parent::setUp();
     $contLang = Language::factory('en');
     $this->setMwGlobals(['wgShowDBErrorBacktrace' => true, 'wgCleanSignatures' => true]);
     $this->setUserLang('en');
     $this->setContentLang($contLang);
     // FIXME: This test should pass without setting global content language
     $this->options = ParserOptions::newFromUserAndLang(new User(), $contLang);
     $this->options->setTemplateCallback([__CLASS__, 'statelessFetchTemplate']);
     $this->parser = new Parser();
     MagicWord::clearCache();
 }
示例#11
0
 /** setup a basic parser object */
 protected function setUp()
 {
     parent::setUp();
     $contLang = Language::factory('en');
     $this->setMwGlobals(array('wgLanguageCode' => 'en', 'wgContLang' => $contLang));
     $this->testParser = new Parser();
     $this->testParser->Options(ParserOptions::newFromUserAndLang(new User(), $contLang));
     # initialize parser output
     $this->testParser->clearState();
     # Needs a title to do magic word stuff
     $title = Title::newFromText('Tests');
     $title->mRedirect = false;
     # Else it needs a db connection just to check if it's a redirect (when deciding the page language)
     $this->testParser->setTitle($title);
 }
示例#12
0
 /**
  * Get parser options suitable for rendering and caching the article
  *
  * @param IContextSource|User|string $context One of the following:
  *        - IContextSource: Use the User and the Language of the provided
  *                                            context
  *        - User: Use the provided User object and $wgLang for the language,
  *                                            so use an IContextSource object if possible.
  *        - 'canonical': Canonical options (anonymous user with default
  *                                            preferences and content language).
  *
  * @throws MWException
  * @return ParserOptions
  */
 public function makeParserOptions($context)
 {
     global $wgContLang, $wgEnableParserLimitReporting;
     if ($context instanceof IContextSource) {
         $options = ParserOptions::newFromContext($context);
     } elseif ($context instanceof User) {
         // settings per user (even anons)
         $options = ParserOptions::newFromUser($context);
     } elseif ($context === 'canonical') {
         // canonical settings
         $options = ParserOptions::newFromUserAndLang(new User(), $wgContLang);
     } else {
         throw new MWException("Bad context for parser options: {$context}");
     }
     $options->enableLimitReport($wgEnableParserLimitReporting);
     // show inclusion/loop reports
     $options->setTidy(true);
     // fix bad HTML
     return $options;
 }
示例#13
0
 /**
  * Prepare text which is about to be saved.
  * Returns a stdclass with source, pst and output members
  * @return bool|object
  */
 public function prepareTextForEdit($text, $revid = null, User $user = null)
 {
     global $wgParser, $wgContLang, $wgUser;
     $user = is_null($user) ? $wgUser : $user;
     // @TODO fixme: check $user->getId() here???
     if ($this->mPreparedEdit && $this->mPreparedEdit->newText == $text && $this->mPreparedEdit->revid == $revid) {
         // Already prepared
         return $this->mPreparedEdit;
     }
     $popts = ParserOptions::newFromUserAndLang($user, $wgContLang);
     wfRunHooks('ArticlePrepareTextForEdit', array($this, $popts));
     $edit = (object) array();
     $edit->revid = $revid;
     $edit->newText = $text;
     $edit->pst = $wgParser->preSaveTransform($text, $this->mTitle, $user, $popts);
     $edit->popts = $this->makeParserOptions('canonical');
     $edit->output = $wgParser->parse($edit->pst, $this->mTitle, $edit->popts, true, true, $revid);
     $edit->oldText = $this->getRawText();
     $this->mPreparedEdit = $edit;
     return $edit;
 }
示例#14
0
 /**
  * Get a diff between the current contents of the edit box and the
  * version of the page we're editing from.
  *
  * If this is a section edit, we'll replace the section as for final
  * save and then make a comparison.
  */
 function showDiff()
 {
     global $wgUser, $wgContLang, $wgParser, $wgOut;
     $oldtext = $this->mArticle->getRawText();
     $newtext = $this->mArticle->replaceSection($this->section, $this->textbox1, $this->summary, $this->edittime);
     wfRunHooks('EditPageGetDiffText', array($this, &$newtext));
     $popts = ParserOptions::newFromUserAndLang($wgUser, $wgContLang);
     $newtext = $wgParser->preSaveTransform($newtext, $this->mTitle, $wgUser, $popts);
     if ($oldtext !== false || $newtext != '') {
         $oldtitle = wfMsgExt('currentrev', array('parseinline'));
         $newtitle = wfMsgExt('yourtext', array('parseinline'));
         $de = new DifferenceEngine($this->mArticle->getContext());
         $de->setText($oldtext, $newtext);
         $difftext = $de->getDiff($oldtitle, $newtitle);
         $de->showDiffStyle();
     } else {
         $difftext = '';
     }
     $wgOut->addHTML('<div id="wikiDiff">' . $difftext . '</div>');
 }
示例#15
0
 /**
  * Get a diff between the current contents of the edit box and the
  * version of the page we're editing from.
  *
  * If this is a section edit, we'll replace the section as for final
  * save and then make a comparison.
  */
 function showDiff()
 {
     global $wgUser, $wgContLang, $wgOut;
     $oldtitlemsg = 'currentrev';
     # if message does not exist, show diff against the preloaded default
     if ($this->mTitle->getNamespace() == NS_MEDIAWIKI && !$this->mTitle->exists()) {
         $oldtext = $this->mTitle->getDefaultMessageText();
         if ($oldtext !== false) {
             $oldtitlemsg = 'defaultmessagetext';
             $oldContent = $this->toEditContent($oldtext);
         } else {
             $oldContent = null;
         }
     } else {
         $oldContent = $this->getCurrentContent();
     }
     $textboxContent = $this->toEditContent($this->textbox1);
     $newContent = $this->mArticle->replaceSectionContent($this->section, $textboxContent, $this->summary, $this->edittime);
     if ($newContent) {
         ContentHandler::runLegacyHooks('EditPageGetDiffText', array($this, &$newContent));
         wfRunHooks('EditPageGetDiffContent', array($this, &$newContent));
         $popts = ParserOptions::newFromUserAndLang($wgUser, $wgContLang);
         $newContent = $newContent->preSaveTransform($this->mTitle, $wgUser, $popts);
     }
     if ($oldContent && !$oldContent->isEmpty() || $newContent && !$newContent->isEmpty()) {
         $oldtitle = wfMessage($oldtitlemsg)->parse();
         $newtitle = wfMessage('yourtext')->parse();
         if (!$oldContent) {
             $oldContent = $newContent->getContentHandler()->makeEmptyContent();
         }
         if (!$newContent) {
             $newContent = $oldContent->getContentHandler()->makeEmptyContent();
         }
         $de = $oldContent->getContentHandler()->createDifferenceEngine($this->mArticle->getContext());
         $de->setContent($oldContent, $newContent);
         $difftext = $de->getDiff($oldtitle, $newtitle);
         $de->showDiffStyle();
     } else {
         $difftext = '';
     }
     $wgOut->addHTML('<div id="wikiDiff">' . $difftext . '</div>');
 }
示例#16
0
 /**
  * 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;
 }
示例#17
0
 /**
  * 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__);
 }
示例#18
0
 /**
  * Prepare content which is about to be saved.
  * Returns a stdClass with source, pst and output members
  *
  * @param Content $content
  * @param Revision|int|null $revision Revision object. For backwards compatibility, a
  *        revision ID is also accepted, but this is deprecated.
  * @param User|null $user
  * @param string|null $serialFormat
  * @param bool $useCache Check shared prepared edit cache
  *
  * @return object
  *
  * @since 1.21
  */
 public function prepareContentForEdit(Content $content, $revision = null, User $user = null, $serialFormat = null, $useCache = true)
 {
     global $wgContLang, $wgUser, $wgAjaxEditStash;
     if (is_object($revision)) {
         $revid = $revision->getId();
     } else {
         $revid = $revision;
         // This code path is deprecated, and nothing is known to
         // use it, so performance here shouldn't be a worry.
         if ($revid !== null) {
             $revision = Revision::newFromId($revid, Revision::READ_LATEST);
         } else {
             $revision = null;
         }
     }
     $user = is_null($user) ? $wgUser : $user;
     // XXX: check $user->getId() here???
     // Use a sane default for $serialFormat, see bug 57026
     if ($serialFormat === null) {
         $serialFormat = $content->getContentHandler()->getDefaultFormat();
     }
     if ($this->mPreparedEdit && isset($this->mPreparedEdit->newContent) && $this->mPreparedEdit->newContent->equals($content) && $this->mPreparedEdit->revid == $revid && $this->mPreparedEdit->format == $serialFormat) {
         // Already prepared
         return $this->mPreparedEdit;
     }
     // The edit may have already been prepared via api.php?action=stashedit
     $cachedEdit = $useCache && $wgAjaxEditStash ? ApiStashEdit::checkCache($this->getTitle(), $content, $user) : false;
     $popts = ParserOptions::newFromUserAndLang($user, $wgContLang);
     Hooks::run('ArticlePrepareTextForEdit', [$this, $popts]);
     $edit = (object) [];
     if ($cachedEdit) {
         $edit->timestamp = $cachedEdit->timestamp;
     } else {
         $edit->timestamp = wfTimestampNow();
     }
     // @note: $cachedEdit is safely not used if the rev ID was referenced in the text
     $edit->revid = $revid;
     if ($cachedEdit) {
         $edit->pstContent = $cachedEdit->pstContent;
     } else {
         $edit->pstContent = $content ? $content->preSaveTransform($this->mTitle, $user, $popts) : null;
     }
     $edit->format = $serialFormat;
     $edit->popts = $this->makeParserOptions('canonical');
     if ($cachedEdit) {
         $edit->output = $cachedEdit->output;
     } else {
         if ($revision) {
             // We get here if vary-revision is set. This means that this page references
             // itself (such as via self-transclusion). In this case, we need to make sure
             // that any such self-references refer to the newly-saved revision, and not
             // to the previous one, which could otherwise happen due to replica DB lag.
             $oldCallback = $edit->popts->getCurrentRevisionCallback();
             $edit->popts->setCurrentRevisionCallback(function (Title $title, $parser = false) use($revision, &$oldCallback) {
                 if ($title->equals($revision->getTitle())) {
                     return $revision;
                 } else {
                     return call_user_func($oldCallback, $title, $parser);
                 }
             });
         } else {
             // Try to avoid a second parse if {{REVISIONID}} is used
             $edit->popts->setSpeculativeRevIdCallback(function () {
                 return 1 + (int) wfGetDB(DB_MASTER)->selectField('revision', 'MAX(rev_id)', [], __METHOD__);
             });
         }
         $edit->output = $edit->pstContent ? $edit->pstContent->getParserOutput($this->mTitle, $revid, $edit->popts) : null;
     }
     $edit->newContent = $content;
     $edit->oldContent = $this->getContent(Revision::RAW);
     // NOTE: B/C for hooks! don't use these fields!
     $edit->newText = $edit->newContent ? ContentHandler::getContentText($edit->newContent) : '';
     $edit->oldText = $edit->oldContent ? ContentHandler::getContentText($edit->oldContent) : '';
     $edit->pst = $edit->pstContent ? $edit->pstContent->serialize($serialFormat) : '';
     if ($edit->output) {
         $edit->output->setCacheTime(wfTimestampNow());
     }
     // Process cache the result
     $this->mPreparedEdit = $edit;
     return $edit;
 }
示例#19
0
 /**
  * Get a diff between the current contents of the edit box and the
  * version of the page we're editing from.
  *
  * If this is a section edit, we'll replace the section as for final
  * save and then make a comparison.
  */
 function showDiff()
 {
     global $wgUser, $wgContLang, $wgParser, $wgOut;
     $oldtitlemsg = 'currentrev';
     # if message does not exist, show diff against the preloaded default
     if ($this->mTitle->getNamespace() == NS_MEDIAWIKI && !$this->mTitle->exists()) {
         $oldtext = $this->mTitle->getDefaultMessageText();
         if ($oldtext !== false) {
             $oldtitlemsg = 'defaultmessagetext';
         }
     } else {
         $oldtext = $this->mArticle->getRawText();
     }
     $newtext = $this->mArticle->replaceSection($this->section, $this->textbox1, $this->summary, $this->edittime);
     wfRunHooks('EditPageGetDiffText', array($this, &$newtext));
     $popts = ParserOptions::newFromUserAndLang($wgUser, $wgContLang);
     $newtext = $wgParser->preSaveTransform($newtext, $this->mTitle, $wgUser, $popts);
     if ($oldtext !== false || $newtext != '') {
         $oldtitle = wfMessage($oldtitlemsg)->parse();
         $newtitle = wfMessage('yourtext')->parse();
         $de = new DifferenceEngine($this->mArticle->getContext());
         $de->setText($oldtext, $newtext);
         $difftext = $de->getDiff($oldtitle, $newtitle);
         $de->showDiffStyle();
     } else {
         $difftext = '';
     }
     $wgOut->addHTML('<div id="wikiDiff">' . $difftext . '</div>');
 }
 public static function onPageContentSave(&$page, &$user, &$content, &$summary, $is_minor, $is_watch, $section, &$flags, &$status)
 {
     global $wgOut, $wgContLang;
     if (ModerationCanSkip::canSkip($user)) {
         return true;
     }
     $old_content = $page->getContent(Revision::RAW);
     // current revision's content
     $request = $user->getRequest();
     $title = $page->getTitle();
     $popts = ParserOptions::newFromUserAndLang($user, $wgContLang);
     $dbw = wfGetDB(DB_MASTER);
     $fields = array('mod_timestamp' => $dbw->timestamp(wfTimestampNow()), 'mod_user' => $user->getId(), 'mod_user_text' => $user->getName(), 'mod_cur_id' => $page->getId(), 'mod_namespace' => $title->getNamespace(), 'mod_title' => $title->getText(), 'mod_comment' => $summary, 'mod_minor' => $is_minor, 'mod_bot' => $flags & EDIT_FORCE_BOT, 'mod_new' => $page->exists() ? 0 : 1, 'mod_last_oldid' => $page->getLatest(), 'mod_ip' => $request->getIP(), 'mod_old_len' => $old_content ? $old_content->getSize() : 0, 'mod_new_len' => $content->getSize(), 'mod_header_xff' => $request->getHeader('X-Forwarded-For'), 'mod_header_ua' => $request->getHeader('User-Agent'), 'mod_text' => $content->preSaveTransform($title, $user, $popts)->getNativeData(), 'mod_preload_id' => ModerationPreload::generatePreloadId(), 'mod_preloadable' => 1);
     $mblockCheck = new ModerationBlockCheck();
     if ($mblockCheck->isModerationBlocked($user->getName())) {
         $fields['mod_rejected'] = 1;
         $fields['mod_rejected_by_user'] = 0;
         $fields['mod_rejected_by_user_text'] = wfMessage('Moderation block')->inContentLanguage()->text();
         $fields['mod_rejected_auto'] = 1;
         $fields['mod_preloadable'] = 1;
         # User can still edit this change, so that spammers won't notice that they are blocked
     }
     // Check if we need to update existing row (if this edit is by the same user to the same page)
     $row = ModerationPreload::loadUnmoderatedEdit($title);
     if (!$row) {
         $dbw->insert('moderation', $fields, __METHOD__);
         ModerationEditHooks::$LastInsertId = $dbw->insertId();
     } else {
         $section = $request->getVal('wpSection', $request->getVal('section'));
         if ($section) {
             #
             # We must recalculate $fields['mod_text'] here.
             # Otherwise if the user adds or modifies two (or more) different sections (in consequent edits),
             # then only modification to the last one will be saved,
             # because $content is [old content] PLUS [modified section from the edit].
             #
             # Difference between $index and $section:
             # $index: section number in $content. $index can't be "new". If $section was "new", then we need to recalculate $index.
             # $section: section number in $saved_content. $section can be "new". Used when calling replaceSection().
             #
             $index = $section;
             if ($section == 'new') {
                 #
                 # Parser doesn't allow to get the LAST section directly.
                 # We have to get the entire TOC - just for a single index.
                 #
                 $sections = $content->getParserOutput($title, null, null, false)->getSections();
                 $new_section_content = end($sections);
                 $index = $new_section_content['index'];
             }
             # $new_section_content is exactly what the user just wrote in the edit form (one section only).
             $new_section_content = $content->getSection($index);
             $saved_content = ContentHandler::makeContent($row->text, null, $content->getModel());
             $new_content = $saved_content->replaceSection($section, $new_section_content, '');
             $fields['mod_text'] = $new_content->preSaveTransform($title, $user, $popts)->getNativeData();
         }
         $dbw->update('moderation', $fields, array('mod_id' => $row->id), __METHOD__);
         ModerationEditHooks::$LastInsertId = $row->id;
     }
     // In case the caller treats "edit-hook-aborted" as an error.
     $dbw->commit();
     /*
     	We have queued this edit for moderation.
     	No need to save anything at this point.
     	Later (if approved) the edit will be saved via doEditContent().
     
     	Here we just redirect the users back to the page they edited
     	(as was the behavior for unmoderated edits).
     	Notification "Your edit was successfully sent for moderation"
     	will be shown by JavaScript.
     */
     $wgOut->redirect($title->getFullURL(array('modqueued' => 1)));
     return false;
 }
示例#21
0
	/**
	 * Prepare content which is about to be saved.
	 * Returns a stdclass with source, pst and output members
	 *
	 * @param Content $content
	 * @param int|null $revid
	 * @param User|null $user
	 * @param string|null $serialization_format
	 *
	 * @return bool|object
	 *
	 * @since 1.21
	 */
	public function prepareContentForEdit( Content $content, $revid = null, User $user = null,
		$serialization_format = null
	) {
		global $wgContLang, $wgUser;
		$user = is_null( $user ) ? $wgUser : $user;
		//XXX: check $user->getId() here???

		if ( $this->mPreparedEdit
			&& $this->mPreparedEdit->newContent
			&& $this->mPreparedEdit->newContent->equals( $content )
			&& $this->mPreparedEdit->revid == $revid
			&& $this->mPreparedEdit->format == $serialization_format
			// XXX: also check $user here?
		) {
			// Already prepared
			return $this->mPreparedEdit;
		}

		$popts = ParserOptions::newFromUserAndLang( $user, $wgContLang );
		wfRunHooks( 'ArticlePrepareTextForEdit', array( $this, $popts ) );

		$edit = (object)array();
		$edit->revid = $revid;

		$edit->pstContent = $content ? $content->preSaveTransform( $this->mTitle, $user, $popts ) : null;

		$edit->format = $serialization_format;
		$edit->popts = $this->makeParserOptions( 'canonical' );
		$edit->output = $edit->pstContent ? $edit->pstContent->getParserOutput( $this->mTitle, $revid, $edit->popts ) : null;

		$edit->newContent = $content;
		$edit->oldContent = $this->getContent( Revision::RAW );

		// NOTE: B/C for hooks! don't use these fields!
		$edit->newText = $edit->newContent ? ContentHandler::getContentText( $edit->newContent ) : '';
		$edit->oldText = $edit->oldContent ? ContentHandler::getContentText( $edit->oldContent ) : '';
		$edit->pst = $edit->pstContent ? $edit->pstContent->serialize( $serialization_format ) : '';

		$this->mPreparedEdit = $edit;
		return $edit;
	}
 protected function getParserOptions()
 {
     return \ParserOptions::newFromUserAndLang(new \User(), $this->getLanguage());
 }