/**
* 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 function getRevId() {
- return $this->mRevId;
- }
+ public abstract function getSearchText( );
- public abstract function getSearchText( $obj );
-
- public abstract function getWikitextForTransclusion( $obj );
-
- public abstract function getParserOutput( ParserOptions $options = NULL );
+ public abstract function getWikitextForTransclusion( );
+ /**
+ * 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 function getIndexUpdateJobs( ParserOptions $options , $recursive = true ) {
- $po = $this->getParserOutput( $options );
- $update = new LinksUpdate( $this->mTitle, $po, $recursive );
- return $update;
- }
+ public abstract function getParserOutput( Title $title = null, $revId = null, ParserOptions $options = NULL );
public function getRedirectChain() {
return null;
}
/**
- * 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: 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
}
-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 ) {
- return $this->getRawData();
+ /**
+ * Returns the text represented by this Content object, as a string.
+ *
+ * @return String the raw text
+ */
+ public function getRawData( ) {
+ $text = $this->mText;
+ return $text;
}
- public function getWikitextForTransclusion( $obj ) {
+ /**
+ * Returns the text represented by this Content object, as a string.
+ *
+ * @return String the raw text
+ */
+ public function getSearchText( ) { #FIXME: use!
return $this->getRawData();
}
+ /**
+ * 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 );
return $po;
}
- public function getHtml( ParserOptions $options ) {
- $html = "";
- $html .= "<pre class=\"mw-code\" dir=\"ltr\">\n";
- $html .= htmlspecialchars( $this->getRawData() );
- $html .= "\n</pre>\n";
-
- return $html;
- }
-
+ protected abstract function getHtml( );
- 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; #TODO: use per-class static member?!
+ }
- $this->mDefaultParserOptions = null;
+ 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();
}
$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 );
-
- if ( !$rev ) {
- wfDebug( "WikiPage::replaceSection asked for bogus section (page: " .
- $this->getId() . "; section: $section; edittime: $edittime)\n" );
- wfProfileOut( __METHOD__ );
- return null;
- }
-
- $oldtext = $rev->getText();
- }
+ $myModelName = $this->getModelName();
+ $sectionModelName = $with->getModelName();
+
+ if ( $sectionModelName != $myModelName ) {
+ throw new MWException( "Incompatible content model for section: document uses $myModelName, section uses $sectionModelName." );
+ }
- 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 );
+ $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 );
}
+ $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;
$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') );
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() );
}
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() );
}
}
-#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
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 ) {
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...
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??
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();
}
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("");
}
}
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("");
}
}
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("");
}
}