https://www.mediawiki.org/wiki/Special:Code/MediaWiki/114155
Revision: 114155 Author: daniel Date: 2012-03-19 17:10:15 +0000 (Mon, 19 Mar 2012) Log Message: ----------- messing with replaceSection() Modified Paths: -------------- branches/Wikidata/phase3/includes/Content.php branches/Wikidata/phase3/includes/ContentHandler.php branches/Wikidata/phase3/includes/EditPage.php branches/Wikidata/phase3/includes/WikiPage.php Modified: branches/Wikidata/phase3/includes/Content.php =================================================================== --- branches/Wikidata/phase3/includes/Content.php 2012-03-19 17:09:23 UTC (rev 114154) +++ branches/Wikidata/phase3/includes/Content.php 2012-03-19 17:10:15 UTC (rev 114155) @@ -2,47 +2,33 @@ /** * A content object represents page content, e.g. the text to show on a page. + * Content objects have no knowledge about how they relate to Wiki pages. + * Content objects are imutable. * */ abstract class Content { - public function __construct( Title $title = null, $revId = null, $modelName = null ) { #FIXME: really need revId? annoying! #FIXME: really $title? or just when parsing, every time? + public function __construct( $modelName = null ) { #FIXME: really need revId? annoying! #FIXME: really $title? or just when parsing, every time? $this->mModelName = $modelName; - $this->mTitle = $title; - $this->mRevId = $revId; } public function getModelName() { return $this->mModelName; } - public function getTitle() { - return $this->mTitle; - } + public abstract function getSearchText( ); - public function getRevId() { - return $this->mRevId; - } + public abstract function getWikitextForTransclusion( ); - public abstract function getSearchText( $obj ); - - public abstract function getWikitextForTransclusion( $obj ); - - public abstract function getParserOutput( ParserOptions $options = NULL ); - + /** + * Returns native represenation of the data. Interpretation depends on the data model used, + * as given by getDataModel(). + * + */ public abstract function getRawData( ); - public function getHtml( ParserOptions $options ) { - $po = $this->getParserOutput( $options ); - return $po->getText(); - } + public abstract function getParserOutput( Title $title = null, $revId = null, ParserOptions $options = NULL ); - public function getIndexUpdateJobs( ParserOptions $options , $recursive = true ) { - $po = $this->getParserOutput( $options ); - $update = new LinksUpdate( $this->mTitle, $po, $recursive ); - return $update; - } - public function getRedirectChain() { return null; } @@ -60,20 +46,20 @@ } /** - * Replaces the section with the given id. + * Replaces a section of the content. * - * The default implementation returns $this. - * - * @param String $sectionId the section's id - * @param Content $with the section's new content - * @return Content a new content object with the section replaced, or this content object if the section couldn't be replaced. + * @param $section empty/null/false or a section number (0, 1, 2, T1, T2...), or "new" + * @param $with Content: new content of the section + * @param $sectionTitle String: new section's subject, only if $section is 'new' + * @return string Complete article text, or null if error */ - public function replaceSection( $sectionId ) { + public function replaceSection( $section, Content $with, $sectionTitle = '' ) { + return $this; } - #XXX: is the native model for wikitext a string or the parser output? parse early or parse late? + #TODO: implement specialized ParserOutput for Wikidata model + #TODO: provide addToParserOutput fule Multipart... somehow. - # TODO: EditPage::mergeChanges( Content $a, Content $b ) # TODO: Wikipage::isCountable(Content $a) # TODO: Title::newFromRedirectRecurse( $this->getRawText() ); @@ -82,7 +68,6 @@ # TODO: getSize( ) # TODO: WikiPage::getUndoText( Revision $undo, Revision $undoafter = null ) - # TODO: WikiPage::replaceSection( $section, $text, $sectionTitle = '', $edittime = null ) # TODO: WikiPage::getAutosummary( $oldtext, $text, $flags ) # TODO: EditPage::getPreloadedText( $preload ) // $wgParser->getPreloadText @@ -94,23 +79,50 @@ } -class TextContent extends Content { - public function __construct( $text, Title $title = null, $revId = null, $modelName = null ) { - parent::__construct($title, $revId, $modelName); +/** + * Content object implementation for representing flat text. The + */ +abstract class TextContent extends Content { + public function __construct( $text, $modelName = null ) { + parent::__construct($modelName); $this->mText = $text; } - public function getSearchText( $obj ) { + /** + * Returns the text represented by this Content object, as a string. + * + * @return String the raw text + */ + public function getRawData( ) { + $text = $this->mText; + return $text; + } + + /** + * Returns the text represented by this Content object, as a string. + * + * @return String the raw text + */ + public function getSearchText( ) { #FIXME: use! return $this->getRawData(); } - public function getWikitextForTransclusion( $obj ) { + /** + * Returns the text represented by this Content object, as a string. + * + * @return String the raw text + */ + public function getWikitextForTransclusion( ) { #FIXME: use! return $this->getRawData(); } - - public function getParserOutput( ParserOptions $options = null ) { + /** + * Returns a generic ParserOutput object, wrapping the HTML returned by getHtml(). + * + * @return ParserOutput representing the HTML form of the text + */ + public function getParserOutput( Title $title = null, $revId = null, ParserOptions $options = null ) { # generic implementation, relying on $this->getHtml() $html = $this->getHtml( $options ); @@ -123,53 +135,39 @@ return $po; } - public function getHtml( ParserOptions $options ) { - $html = ""; - $html .= "<pre class=\"mw-code\" dir=\"ltr\">\n"; - $html .= htmlspecialchars( $this->getRawData() ); - $html .= "\n</pre>\n"; + protected abstract function getHtml( ); - return $html; - } - - - public function getRawData( ) { - $text = $this->mText; - return $text; - } - - public function getRedirectChain() { - #XXX: really do this for all text, or just in WikitextContent? - $text = $this->getRawData(); - return Title::newFromRedirectArray( $text ); - } } class WikitextContent extends TextContent { - public function __construct( $text, Title $title, $revId = null) { - parent::__construct($text, $title, $revId, CONTENT_MODEL_WIKITEXT); + public function __construct( $text ) { + parent::__construct($text, CONTENT_MODEL_WIKITEXT); - $this->mDefaultParserOptions = null; + $this->mDefaultParserOptions = null; #TODO: use per-class static member?! } + protected function getHtml( ) { + throw new MWException( "getHtml() not implemented for wikitext. Use getParserOutput()->getText()." ); + } + public function getDefaultParserOptions() { global $wgUser, $wgContLang; - if ( !$this->mDefaultParserOptions ) { - #TODO: use static member?! + if ( !$this->mDefaultParserOptions ) { #TODO: use per-class static member?! $this->mDefaultParserOptions = ParserOptions::newFromUserAndLang( $wgUser, $wgContLang ); } return $this->mDefaultParserOptions; } - public function getParserOutput( ParserOptions $options = null ) { + /** + * Returns a ParserOutput object reesulting from parsing the content's text using $wgParser + * + * @return ParserOutput representing the HTML form of the text + */ + public function getParserOutput( Title $title = null, $revId = null, ParserOptions $options = null ) { global $wgParser; - #TODO: quick local cache: if $options is NULL, use ->mParserOutput! - #FIXME: need setParserOutput, so we can use stuff from the parser cache?? - #FIXME: ...or we somehow need to know the parser cache key?? - if ( !$options ) { $options = $this->getDefaultParserOptions(); } @@ -190,80 +188,64 @@ $text = $this->getRawData(); $sect = $wgParser->getSection( $text, $section, false ); - $title = Title::newFromDBkey( $this->mTitle->getText() . '#' . $section, $this->mTitle->getNamespace() ); #FIXME: get rid of titles here - return new WikitextContent( $sect, $title ); + return new WikitextContent( $sect ); } /** - * Replaces the section with the given id. + * Replaces a section in the wikitext * - * @param String $sectionId the section's id - * @param Content $with the section's new content - * @return Boolean true if te section was replaced sucessfully, false otherwise - */ - #FIXME: implement replaceSection(), use in WikiPage - - /** - * @param $section empty/null/false or a section number (0, 1, 2, T1, T2...) - * @param $text String: new text of the section + * @param $section empty/null/false or a section number (0, 1, 2, T1, T2...), or "new" + * @param $with Content: new content of the section * @param $sectionTitle String: new section's subject, only if $section is 'new' - * @param $edittime String: revision timestamp or null to use the current revision * @return string Complete article text, or null if error */ - /*public function replaceSection( $section, $text, $sectionTitle = '', $edittime = null ) { #FIXME: adopt this! + public function replaceSection( $section, Content $with, $sectionTitle = '' ) { + global $wgParser; + wfProfileIn( __METHOD__ ); - if ( strval( $section ) == '' ) { - // Whole-page edit; let the whole text through - } else { - // Bug 30711: always use current version when adding a new section - if ( is_null( $edittime ) || $section == 'new' ) { - $oldtext = $this->getRawText(); - if ( $oldtext === false ) { - wfDebug( __METHOD__ . ": no page text\n" ); - wfProfileOut( __METHOD__ ); - return null; - } - } else { - $dbw = wfGetDB( DB_MASTER ); - $rev = Revision::loadFromTimestamp( $dbw, $this->mTitle, $edittime ); + $myModelName = $this->getModelName(); + $sectionModelName = $with->getModelName(); - if ( !$rev ) { - wfDebug( "WikiPage::replaceSection asked for bogus section (page: " . - $this->getId() . "; section: $section; edittime: $edittime)\n" ); - wfProfileOut( __METHOD__ ); - return null; - } + if ( $sectionModelName != $myModelName ) { + throw new MWException( "Incompatible content model for section: document uses $myModelName, section uses $sectionModelName." ); + } - $oldtext = $rev->getText(); - } + $oldtext = $this->getRawData(); + $text = $with->getRawData(); - if ( $section == 'new' ) { - # Inserting a new section - $subject = $sectionTitle ? wfMsgForContent( 'newsectionheaderdefaultlevel', $sectionTitle ) . "\n\n" : ''; - if ( wfRunHooks( 'PlaceNewSection', array( $this, $oldtext, $subject, &$text ) ) ) { - $text = strlen( trim( $oldtext ) ) > 0 - ? "{$oldtext}\n\n{$subject}{$text}" - : "{$subject}{$text}"; - } - } else { - # Replacing an existing section; roll out the big guns - global $wgParser; - - $text = $wgParser->replaceSection( $oldtext, $section, $text ); + if ( $section == 'new' ) { + # Inserting a new section + $subject = $sectionTitle ? wfMsgForContent( 'newsectionheaderdefaultlevel', $sectionTitle ) . "\n\n" : ''; + if ( wfRunHooks( 'PlaceNewSection', array( $this, $oldtext, $subject, &$text ) ) ) { + $text = strlen( trim( $oldtext ) ) > 0 + ? "{$oldtext}\n\n{$subject}{$text}" + : "{$subject}{$text}"; } + } else { + # Replacing an existing section; roll out the big guns + global $wgParser; + + $text = $wgParser->replaceSection( $oldtext, $section, $text ); } + $newContent = new WikitextContent( $text ); + wfProfileOut( __METHOD__ ); - return $text; - } */ + return $newContent; + } + public function getRedirectChain() { + $text = $this->getRawData(); + return Title::newFromRedirectArray( $text ); + } + } class MessageContent extends TextContent { public function __construct( $msg_key, $params = null, $options = null ) { - parent::__construct(null, null, null, CONTENT_MODEL_WIKITEXT); + parent::__construct(null, CONTENT_MODEL_WIKITEXT); $this->mMessageKey = $msg_key; @@ -275,13 +257,19 @@ $this->mHtmlOptions = null; } - - public function getHtml( ParserOptions $options ) { + /** + * Returns the message as rendered HTML, using the options supplied to the constructor plus "parse". + */ + protected function getHtml( ) { $opt = array_merge( $this->mOptions, array('parse') ); + return wfMsgExt( $this->mMessageKey, $this->mParameters, $opt ); } + /** + * Returns the message as raw text, using the options supplied to the constructor minus "parse" and "parseinline". + */ public function getRawData( ) { $opt = array_diff( $this->mOptions, array('parse', 'parseinline') ); @@ -292,11 +280,11 @@ class JavaScriptContent extends TextContent { - public function __construct( $text, Title $title, $revId = null ) { - parent::__construct($text, $title, $revId, CONTENT_MODEL_JAVASCRIPT); + public function __construct( $text ) { + parent::__construct($text, CONTENT_MODEL_JAVASCRIPT); } - public function getHtml( ParserOptions $options ) { + protected function getHtml( ) { $html = ""; $html .= "<pre class=\"mw-code mw-js\" dir=\"ltr\">\n"; $html .= htmlspecialchars( $this->getRawData() ); @@ -308,11 +296,11 @@ } class CssContent extends TextContent { - public function __construct( $text, Title $title, $revId = null ) { - parent::__construct($text, $title, $revId, CONTENT_MODEL_CSS); + public function __construct( $text ) { + parent::__construct($text, CONTENT_MODEL_CSS); } - public function getHtml( ParserOptions $options ) { + protected function getHtml( ) { $html = ""; $html .= "<pre class=\"mw-code mw-css\" dir=\"ltr\">\n"; $html .= htmlspecialchars( $this->getRawData() ); @@ -322,10 +310,8 @@ } } -#FIXME: special type for redirects?! -#FIXME: special type for message-based pseudo-content? with raw html? - -#TODO: MultipartMultipart < WikipageContent (Main + Links + X) -#TODO: LinksContent < LanguageLinksContent, CategoriesContent +#FUTURE: special type for redirects?! +#FUTURE: MultipartMultipart < WikipageContent (Main + Links + X) +#FUTURE: LinksContent < LanguageLinksContent, CategoriesContent #EXAMPLE: CoordinatesContent #EXAMPLE: WikidataContent Modified: branches/Wikidata/phase3/includes/ContentHandler.php =================================================================== --- branches/Wikidata/phase3/includes/ContentHandler.php 2012-03-19 17:09:23 UTC (rev 114154) +++ branches/Wikidata/phase3/includes/ContentHandler.php 2012-03-19 17:10:15 UTC (rev 114155) @@ -29,11 +29,13 @@ return null; } - public static function makeContent( $text, Title $title, $format = null, $revId = null ) { - $handler = ContentHandler::getForTitle( $title ); + public static function makeContent( $text, Title $title, $modelName = null, $format = null ) { + if ( !$modelName ) { + $modelName = $title->getContentModelName(); + } - #FIXME: pass revid? - return $handler->unserialize( $text, $title, $format ); + $handler = ContentHandler::getForModelName( $modelName ); + return $handler->unserialize( $text, $format ); } public static function getDefaultModelFor( Title $title ) { @@ -141,11 +143,11 @@ return $this->mSupportedFormats[0]; } - public abstract function serialize( Content $content, Title $title, $format = null ); + public abstract function serialize( Content $content, $format = null ); - public abstract function unserialize( $blob, Title $title, $format = null ); #FIXME: ...and revId? + public abstract function unserialize( $blob, $format = null ); - public abstract function newContent( Title $title ); + public abstract function emptyContent(); # public abstract function doPreSaveTransform( $title, $obj ); #TODO... @@ -199,13 +201,6 @@ return $de; } - public function getIndexUpdateJobs( Title $title, ParserOutput $parserOutput, $recursive = true ) { - # for wikitext, create a LinksUpdate object - # for wikidata: serialize arrays to json - $update = new LinksUpdate( $title, $parserOutput, $recursive ); - return $update; - } - #XXX: is the native model for wikitext a string or the parser output? parse early or parse late? #TODO: how to handle extra message for JS/CSS previews?? @@ -221,7 +216,8 @@ parent::__construct( $modelName, $formats ); } - public function serialize( Content $content, Title $title, $format = null ) { + public function serialize( Content $content, $format = null ) { + #FIXME: assert format return $content->getRawData(); } @@ -232,12 +228,13 @@ parent::__construct( $modelName, array( 'application/x-wikitext' ) ); #FIXME: mime } - public function unserialize( $text, Title $title, $format = null ) { - return new WikitextContent($text, $title); + public function unserialize( $text, $format = null ) { + #FIXME: assert format + return new WikitextContent($text); } - public function newContent( Title $title) { - return new WikitextContent("", $title); + public function emptyContent() { + return new WikitextContent(""); } } @@ -248,12 +245,12 @@ parent::__construct( $modelName, array( 'text/javascript' ) ); } - public function unserialize( $text, Title $title, $format = null ) { - return new JavaScriptContent($text, $title); + public function unserialize( $text, $format = null ) { + return new JavaScriptContent($text); } - public function newContent( Title $title) { - return new JavaScriptContent("", $title); + public function emptyContent() { + return new JavaScriptContent(""); } } @@ -263,12 +260,12 @@ parent::__construct( $modelName, array( 'text/css' ) ); } - public function unserialize( $text, Title $title, $format = null ) { - return new CssContent($text, $title); + public function unserialize( $text, $format = null ) { + return new CssContent($text); } - public function newContent( Title $title) { - return new CssContent("", $title); + public function emptyContent() { + return new CssContent(""); } } Modified: branches/Wikidata/phase3/includes/EditPage.php =================================================================== --- branches/Wikidata/phase3/includes/EditPage.php 2012-03-19 17:09:23 UTC (rev 114154) +++ branches/Wikidata/phase3/includes/EditPage.php 2012-03-19 17:10:15 UTC (rev 114155) @@ -1299,10 +1299,12 @@ if ( $this->isConflict ) { wfDebug( __METHOD__ . ": conflict! getting section '$this->section' for time '$this->edittime' (article time '{$timestamp}')\n" ); - $text = $this->mArticle->replaceSection( $this->section, $this->textbox1, $sectionTitle, $this->edittime ); + $cnt = $this->mArticle->replaceSection( $this->section, $this->textbox1, $sectionTitle, $this->edittime ); + $text = ContentHandler::getContentText($cnt); #FIXME: use Content object throughout, make edit form aware of content model and serialization format } else { wfDebug( __METHOD__ . ": getting section '$this->section'\n" ); - $text = $this->mArticle->replaceSection( $this->section, $this->textbox1, $sectionTitle ); + $cnt = $this->mArticle->replaceSection( $this->section, $this->textbox1, $sectionTitle ); + $text = ContentHandler::getContentText($cnt); #FIXME: use Content object throughout, make edit form aware of content model and serialization format } if ( is_null( $text ) ) { wfDebug( __METHOD__ . ": activating conflict; section replace failed.\n" ); Modified: branches/Wikidata/phase3/includes/WikiPage.php =================================================================== --- branches/Wikidata/phase3/includes/WikiPage.php 2012-03-19 17:09:23 UTC (rev 114154) +++ branches/Wikidata/phase3/includes/WikiPage.php 2012-03-19 17:10:15 UTC (rev 114155) @@ -1127,18 +1127,21 @@ * @param $text String: new text of the section * @param $sectionTitle String: new section's subject, only if $section is 'new' * @param $edittime String: revision timestamp or null to use the current revision - * @return string Complete article text, or null if error + * @return Content new complete article content, or null if error */ - public function replaceSection( $section, $text, $sectionTitle = '', $edittime = null ) { #FIXME: move to Content object! + public function replaceSection( $section, $text, $sectionTitle = '', $edittime = null ) { wfProfileIn( __METHOD__ ); + $sectionContent = ContentHandler::makeContent( $text, $this->getTitle() ); #XXX: could make section title, but that's not required. + if ( strval( $section ) == '' ) { // Whole-page edit; let the whole text through + $newContent = $sectionContent; } else { // Bug 30711: always use current version when adding a new section if ( is_null( $edittime ) || $section == 'new' ) { - $oldtext = $this->getRawText(); - if ( $oldtext === false ) { + $oldContent = $this->getContent(); + if ( ! $oldContent ) { wfDebug( __METHOD__ . ": no page text\n" ); wfProfileOut( __METHOD__ ); return null; @@ -1154,27 +1157,14 @@ return null; } - $oldtext = $rev->getText(); + $oldContent = $rev->getContent(); } - if ( $section == 'new' ) { - # Inserting a new section - $subject = $sectionTitle ? wfMsgForContent( 'newsectionheaderdefaultlevel', $sectionTitle ) . "\n\n" : ''; - if ( wfRunHooks( 'PlaceNewSection', array( $this, $oldtext, $subject, &$text ) ) ) { - $text = strlen( trim( $oldtext ) ) > 0 - ? "{$oldtext}\n\n{$subject}{$text}" - : "{$subject}{$text}"; - } - } else { - # Replacing an existing section; roll out the big guns - global $wgParser; - - $text = $wgParser->replaceSection( $oldtext, $section, $text ); - } + $newContent = $oldContent->replaceSection( $section, $sectionContent, $sectionTitle ); } wfProfileOut( __METHOD__ ); - return $text; + return $newContent; } /** @@ -2831,7 +2821,9 @@ */ function __construct( Page $page, ParserOptions $parserOptions, $revid, $useParserCache, $content = null ) { if ( is_string($content) ) { #BC: old style call - $content = ContentHandler::makeContent( $content, $page->getTitle(), null, $this->revid ); #FIXME: format? from revision? + $modelName = $page->getRevision()->getContentModelName(); + $format = $page->getRevision()->getContentFormat(); + $content = ContentHandler::makeContent( $content, $page->getTitle(), $modelName, $format ); } $this->page = $page; _______________________________________________ MediaWiki-CVS mailing list MediaWiki-CVS@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs