* The last element in the array is the final destination after all redirects
* have been resolved (up to $wgMaxRedirects times).
*
+ * There is usually no need to override the default behaviour, subclasses that
+ * want to implement redirects should override getRedirectTarget().
+ *
* @since WD.1
*
* @return Array of Titles, with the destination last
+ * @note: migrated here from Title::newFromRedirectArray
*/
public function getRedirectChain() {
- return null;
+ global $wgMaxRedirects;
+ $title = $this->getRedirectTarget();
+ if ( is_null( $title ) ) {
+ return null;
+ }
+ // recursive check to follow double redirects
+ $recurse = $wgMaxRedirects;
+ $titles = array( $title );
+ while ( --$recurse > 0 ) {
+ if ( $title->isRedirect() ) {
+ $page = WikiPage::factory( $title );
+ $newtitle = $page->getRedirectTarget();
+ } else {
+ break;
+ }
+ // Redirects to some special pages are not permitted
+ if ( $newtitle instanceOf Title && $newtitle->isValidRedirectTarget() ) {
+ // the new title passes the checks, so make that our current title so that further recursion can be checked
+ $title = $newtitle;
+ $titles[] = $newtitle;
+ } else {
+ break;
+ }
+ }
+ return $titles;
}
/**
* Construct the redirect destination from this content and return a Title,
* or null if this content doesn't represent a redirect.
- * This will only return the immediate redirect target, useful for
+ *
+ * This shall only return the immediate redirect target, useful for
* the redirect table and other checks that don't need full recursion.
*
+ * This implementation always returns null, subclasses should implement it
+ * according to their data model.
+ *
* @since WD.1
*
* @return Title: The corresponding Title
* This will recurse down $wgMaxRedirects times or until a non-redirect target is hit
* in order to provide (hopefully) the Title of the final destination instead of another redirect.
*
+ * There is usually no need to override the default behaviour, subclasses that
+ * want to implement redirects should override getRedirectTarget().
+ *
* @since WD.1
*
* @return Title
+ * @note: migrated here from Title::newFromRedirectRecurse
*/
public function getUltimateRedirectTarget() {
- return null;
+ $titles = $this->getRedirectChain();
+ return $titles ? array_pop( $titles ) : null;
}
/**
return new WikitextContent( $plt );
}
- public function getRedirectChain() {
- $text = $this->getNativeData();
- return Title::newFromRedirectArray( $text );
- }
-
+ /**
+ * Implement redirect extraction for wikitext.
+ *
+ * @return null|Title
+ *
+ * @note: migrated here from Title::newFromRedirectInternal()
+ *
+ * @see Content::getRedirectTarget
+ * @see AbstractContent::getRedirectTarget
+ */
public function getRedirectTarget() {
- $text = $this->getNativeData();
- return Title::newFromRedirect( $text );
- }
-
- public function getUltimateRedirectTarget() {
- $text = $this->getNativeData();
- return Title::newFromRedirectRecurse( $text );
+ global $wgMaxRedirects;
+ if ( $wgMaxRedirects < 1 ) {
+ //redirects are disabled, so quit early
+ return null;
+ }
+ $redir = MagicWord::get( 'redirect' );
+ $text = trim( $this->getNativeData() );
+ if ( $redir->matchStartAndRemove( $text ) ) {
+ // Extract the first link and see if it's usable
+ // Ensure that it really does come directly after #REDIRECT
+ // Some older redirects included a colon, so don't freak about that!
+ $m = array();
+ if ( preg_match( '!^\s*:?\s*\[{2}(.*?)(?:\|.*?)?\]{2}!', $text, $m ) ) {
+ // Strip preceding colon used to "escape" categories, etc.
+ // and URL-decode links
+ if ( strpos( $m[1], '%' ) !== false ) {
+ // Match behavior of inline link parsing here;
+ $m[1] = rawurldecode( ltrim( $m[1], ':' ) );
+ }
+ $title = Title::newFromText( $m[1] );
+ // If the title is a redirect to bad special pages or is invalid, return null
+ if ( !$title instanceof Title || !$title->isValidRedirectTarget() ) {
+ return null;
+ }
+ return $title;
+ }
+ }
+ return null;
}
/**
* @return bool true if the content is countable
*/
public function isCountable( $hasLinks = null, Title $title = null ) {
- global $wgArticleCountMethod, $wgRequest;
+ global $wgArticleCountMethod;
if ( $this->isRedirect( ) ) {
return false;
* @since WD.1
*
* @static
- * @param string $text the textual representation, will be unserialized to create the Content object
- * @param Title $title the title of the page this text belongs to, required as a context for deserialization
+ *
+ * @param string $text the textual representation, will be unserialized to create the Content object
+ * @param null|Title $title the title of the page this text belongs to. Required if $modelId is not provided.
* @param null|String $modelId the model to deserialize to. If not provided, $title->getContentModel() is used.
- * @param null|String $format the format to use for deserialization. If not given, the model's default format is used.
+ * @param null|String $format the format to use for deserialization. If not given, the model's default format is used.
*
* @return Content a Content object representing $text
+ *
* @throw MWException if $model or $format is not supported or if $text can not be unserialized using $format.
*/
- public static function makeContent( $text, Title $title, $modelId = null, $format = null ) {
+ public static function makeContent( $text, Title $title = null, $modelId = null, $format = null ) {
if ( is_null( $modelId ) ) {
+ if ( is_null( $title ) ) {
+ throw new MWException( "Must provide a Title object or a content model ID." );
+ }
+
$modelId = $title->getContentModel();
}
$content = $rev->getContent();
$blank = false;
+ $this->checkModelID( $content->getModel() );
+
// If the page is blank, use the text from the previous revision,
// which can only be blank if there's a move/import/protect dummy revision involved
if ( $content->getSize() == 0 ) {
$undo_content = $undo->getContent();
$undoafter_content = $undoafter->getContent();
+ $this->checkModelID( $cur_content->getModel() );
+ $this->checkModelID( $undo_content->getModel() );
+ $this->checkModelID( $undoafter_content->getModel() );
+
if ( $cur_content->equals( $undo_content ) ) {
// No use doing a merge if it's just a straight revert.
return $undoafter_content;
* @return ParserOutput representing the HTML form of the text
*/
public function getParserOutput( Content $content, Title $title, $revId = null, ParserOptions $options = null, $generateHtml = true ) {
+ $this->checkModelID( $content->getModel() );
+
# generic implementation, relying on $this->getHtml()
if ( $generateHtml ) $html = $this->getHtml( $content );
/**
* Generates an HTML version of the content, for display.
- * Used by getParserOutput() to construct a ParserOutput object
+ * Used by getParserOutput() to construct a ParserOutput object.
+ *
+ * This default implementation just calls getHighlightHtml(). Content models that
+ * have another mapping to HTML (as is the case for markup languages like wikitext)
+ * should override this method to generate the appropriate html.
*
* @param Content $content the content to render
*
- * @return String
+ * @return String an HTML representation of the content
*/
- protected abstract function getHtml( Content $content );
+ protected function getHtml( Content $content ) {
+ $this->checkModelID( $content->getModel() );
+
+ #XXX: hook?
+ return $this->getHighlighteHtml( $content );
+ }
+
+ /**
+ * Generates a syntax-highlighted version the content, as HTML.
+ * Used by the default implementation if getHtml().
+ *
+ * @param Content $content the content to render
+ *
+ * @return String an HTML representation of the content's markup
+ */
+ protected function getHighlightHtml( Content $content ) {
+ $this->checkModelID( $content->getModel() );
+
+ #TODO: use highlighter, if available
+ #XXX: hook?
+ return htmlspecialchars( $content->getNativeData() );
+ }
}
public function getParserOutput( Content $content, Title $title, $revId = null, ParserOptions $options = null, $generateHtml = true ) {
global $wgParser;
+ $this->checkModelID( $content->getModel() );
+
if ( !$options ) {
$options = new ParserOptions();
}
/**
* Returns true because wikitext supports sections.
- *
+ *
* @return boolean whether sections are supported.
*/
public function supportsSections() {
protected function getHtml( Content $content ) {
$html = "";
$html .= "<pre class=\"mw-code mw-js\" dir=\"ltr\">\n";
- $html .= htmlspecialchars( $content->getNativeData() );
+ $html .= $this->getHighlightHtml( $content );
$html .= "\n</pre>\n";
return $html;
protected function getHtml( Content $content ) {
$html = "";
$html .= "<pre class=\"mw-code mw-css\" dir=\"ltr\">\n";
- $html .= htmlspecialchars( $content->getNativeData() );
+ $html .= $this->getHighlightHtml( $content );
$html .= "\n</pre>\n";
return $html;
*
* @param $text String: Text with possible redirect
* @return Title: The corresponding Title
+ * @deprecated since 1.WD, use Content::getRedirectTarget instead.
*/
- public static function newFromRedirect( $text ) { #TODO: move to Content class, deprecate here.
- return self::newFromRedirectInternal( $text );
+ public static function newFromRedirect( $text ) {
+ $content = ContentHandler::makeContent( $text, null, CONTENT_MODEL_WIKITEXT );
+ return $content->getRedirectTarget();
}
/**
*
* @param $text String Text with possible redirect
* @return Title
+ * @deprecated since 1.WD, use Content::getUltimateRedirectTarget instead.
*/
public static function newFromRedirectRecurse( $text ) {
- $titles = self::newFromRedirectArray( $text );
- return $titles ? array_pop( $titles ) : null;
+ $content = ContentHandler::makeContent( $text, null, CONTENT_MODEL_WIKITEXT );
+ return $content->getUltimateRedirectTarget();
}
/**
*
* @param $text String Text with possible redirect
* @return Array of Titles, with the destination last
+ * @deprecated since 1.WD, use Content::getRedirectChain instead.
* @todo: migrate this logic into WikitextContent!
*/
public static function newFromRedirectArray( $text ) {
- global $wgMaxRedirects;
- $title = self::newFromRedirectInternal( $text );
- if ( is_null( $title ) ) {
- return null;
- }
- // recursive check to follow double redirects
- $recurse = $wgMaxRedirects;
- $titles = array( $title );
- while ( --$recurse > 0 ) {
- if ( $title->isRedirect() ) {
- $page = WikiPage::factory( $title );
- $newtitle = $page->getRedirectTarget();
- } else {
- break;
- }
- // Redirects to some special pages are not permitted
- if ( $newtitle instanceOf Title && $newtitle->isValidRedirectTarget() ) {
- // the new title passes the checks, so make that our current title so that further recursion can be checked
- $title = $newtitle;
- $titles[] = $newtitle;
- } else {
- break;
- }
- }
- return $titles;
- }
-
- /**
- * Really extract the redirect destination
- * Do not call this function directly, use one of the newFromRedirect* functions above
- *
- * @param $text String Text with possible redirect
- * @return Title
- */
- protected static function newFromRedirectInternal( $text ) {
- global $wgMaxRedirects;
- if ( $wgMaxRedirects < 1 ) {
- //redirects are disabled, so quit early
- return null;
- }
- $redir = MagicWord::get( 'redirect' );
- $text = trim( $text );
- if ( $redir->matchStartAndRemove( $text ) ) {
- // Extract the first link and see if it's usable
- // Ensure that it really does come directly after #REDIRECT
- // Some older redirects included a colon, so don't freak about that!
- $m = array();
- if ( preg_match( '!^\s*:?\s*\[{2}(.*?)(?:\|.*?)?\]{2}!', $text, $m ) ) {
- // Strip preceding colon used to "escape" categories, etc.
- // and URL-decode links
- if ( strpos( $m[1], '%' ) !== false ) {
- // Match behavior of inline link parsing here;
- $m[1] = rawurldecode( ltrim( $m[1], ':' ) );
- }
- $title = Title::newFromText( $m[1] );
- // If the title is a redirect to bad special pages or is invalid, return null
- if ( !$title instanceof Title || !$title->isValidRedirectTarget() ) {
- return null;
- }
- return $title;
- }
- }
- return null;
+ $content = ContentHandler::makeContent( $text, null, CONTENT_MODEL_WIKITEXT );
+ return $content->getRedirectChain();
}
/**
if ( $titleObj->isRedirect() ) {
$oldTitle = $titleObj;
- $titles = Title::newFromRedirectArray( Revision::newFromTitle( $oldTitle )->getText( Revision::FOR_THIS_USER ) );
+ $titles = Revision::newFromTitle( $oldTitle )->getContent( Revision::FOR_THIS_USER )->getRedirectChain();
// array_shift( $titles );
$redirValues = array();
// MediaWiki: pages, though
if ( $articleObj->getID() == 0 && $titleObj->getNamespace() != NS_MEDIAWIKI ) {
$content = null;
- $text = '';
+ $text = '';
} else {
- $content = $articleObj->getContentObject();
- $text = ContentHandler::getContentText( $content ); #FIXME: serialize?! get format from params?...
+ $content = $articleObj->getContentObject();
+ $text = ContentHandler::getContentText( $content ); #FIXME: serialize?! get format from params?...
}
if ( !is_null( $params['section'] ) ) {
wfDebug( __METHOD__.": target redirect already deleted, ignoring\n" );
return true;
}
- $text = $targetRev->getText();
- $currentDest = Title::newFromRedirect( $text );
+ $content = $targetRev->getContent();
+ $currentDest = $content->getRedirectTarget();
if ( !$currentDest || !$currentDest->equals( $this->redirTitle ) ) {
wfDebug( __METHOD__.": Redirect has changed since the job was queued\n" );
return true;
}
# Check for a suppression tag (used e.g. in periodically archived discussions)
+ $text = ContentHandler::getContentText( $content );
$mw = MagicWord::get( 'staticredirect' );
- if ( $mw->match( $text ) ) {
+ if ( $mw->match( $text ) ) { #FIXME: add support for this to ContentHandler/Content
wfDebug( __METHOD__.": skipping: suppressed with __STATICREDIRECT__\n" );
return true;
}
break;
}
$text = $message->plain();
+ $content = ContentHandler::makeContent( $text, $title ); #TODO: use Message::content() instead, once that exists
} else {
break;
}
- if ( $text === false ) {
+ if ( !$content ) {
break;
}
# Redirect?
$finalTitle = $title;
- $title = Title::newFromRedirect( $text );
+ $title = $content->getRedirectTarget();
}
return array(
'text' => $text,
$title = Title::makeTitle( $row->page_namespace, $row->page_title );
$rev = Revision::newFromId( $row->page_latest );
if ( $rev ) {
- $target = Title::newFromRedirect( $rev->getText() );
+ $target = $rev->getContent()->getRedirectTarget();
if ( !$target ) {
$this->output( $title->getPrefixedText() . "\n" );
}