}
/**
- * A content handler knows how do deal with a specific type of content on a wiki page.
- * Content is stored in the database in a serialized form (using a serialization format aka mime type)
- * and is be unserialized into it's native PHP representation (the content model), which is wrapped in
- * an instance of the appropriate subclass of Content.
+ * A content handler knows how do deal with a specific type of content on a wiki
+ * page. Content is stored in the database in a serialized form (using a
+ * serialization format a.k.a. MIME type) and is unserialized into its native
+ * PHP representation (the content model), which is wrapped in an instance of
+ * the appropriate subclass of Content.
*
- * ContentHandler instances are stateless singletons that serve, among other things, as a factory for
- * Content objects. Generally, there is one subclass of ContentHandler and one subclass of Content
- * for every type of content model.
+ * ContentHandler instances are stateless singletons that serve, among other
+ * things, as a factory for Content objects. Generally, there is one subclass
+ * of ContentHandler and one subclass of Content for every type of content model.
*
- * Some content types have a flat model, that is, their native representation is the
- * same as their serialized form. Examples would be JavaScript and CSS code. As of now,
- * this also applies to wikitext (mediawiki's default content type), but wikitext
- * content may be represented by a DOM or AST structure in the future.
+ * Some content types have a flat model, that is, their native representation
+ * is the same as their serialized form. Examples would be JavaScript and CSS
+ * code. As of now, this also applies to wikitext (MediaWiki's default content
+ * type), but wikitext content may be represented by a DOM or AST structure in
+ * the future.
*
* @since 1.WD
*/
abstract class ContentHandler {
/**
- * Convenience function for getting flat text from a Content object. This should only
- * be used in the context of backwards compatibility with code that is not yet able
- * to handle Content objects!
+ * Convenience function for getting flat text from a Content object. This
+ * should only be used in the context of backwards compatibility with code
+ * that is not yet able to handle Content objects!
*
* If $content is null, this method returns the empty string.
*
- * If $content is an instance of TextContent, this method returns the flat text as returned by $content->getNativeData().
+ * If $content is an instance of TextContent, this method returns the flat
+ * text as returned by $content->getNativeData().
*
- * If $content is not a TextContent object, the behavior of this method depends on the global $wgContentHandlerTextFallback:
- * * If $wgContentHandlerTextFallback is 'fail' and $content is not a TextContent object, an MWException is thrown.
- * * If $wgContentHandlerTextFallback is 'serialize' and $content is not a TextContent object, $content->serialize()
- * is called to get a string form of the content.
- * * If $wgContentHandlerTextFallback is 'ignore' and $content is not a TextContent object, this method returns null.
- * * otherwise, the behaviour is undefined.
+ * If $content is not a TextContent object, the behavior of this method
+ * depends on the global $wgContentHandlerTextFallback:
+ * - If $wgContentHandlerTextFallback is 'fail' and $content is not a
+ * TextContent object, an MWException is thrown.
+ * - If $wgContentHandlerTextFallback is 'serialize' and $content is not a
+ * TextContent object, $content->serialize() is called to get a string
+ * form of the content.
+ * - If $wgContentHandlerTextFallback is 'ignore' and $content is not a
+ * TextContent object, this method returns null.
+ * - otherwise, the behaviour is undefined.
*
* @since WD.1
+ * @deprecated since WD.1. Always try to use the content object.
*
* @static
- * @param Content|null $content
+ * @param $content Content|null
* @return null|string the textual form of $content, if available
- * @throws MWException if $content is not an instance of TextContent and $wgContentHandlerTextFallback was set to 'fail'.
+ * @throws MWException if $content is not an instance of TextContent and
+ * $wgContentHandlerTextFallback was set to 'fail'.
*/
public static function getContentText( Content $content = null ) {
global $wgContentHandlerTextFallback;
}
if ( $wgContentHandlerTextFallback == 'fail' ) {
- throw new MWException( "Attempt to get text from Content with model " . $content->getModel() );
+ throw new MWException(
+ "Attempt to get text from Content with model " .
+ $content->getModel()
+ );
}
if ( $wgContentHandlerTextFallback == 'serialize' ) {
}
/**
- * Convenience function for creating a Content object from a given textual representation.
+ * Convenience function for creating a Content object from a given textual
+ * representation.
*
- * $text will be deserialized into a Content object of the model specified by $modelId (or,
- * if that is not given, $title->getContentModel()) using the given format.
+ * $text will be deserialized into a Content object of the model specified
+ * by $modelId (or, if that is not given, $title->getContentModel()) using
+ * the given format.
*
* @since WD.1
*
* @static
*
- * @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 $text string the textual representation, will be
+ * unserialized to create the Content object
+ * @param $title null|Title the title of the page this text belongs to.
+ * Required if $modelId is not provided.
+ * @param $modelId null|string the model to deserialize to. If not provided,
+ * $title->getContentModel() is used.
+ * @param $format null|string 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.
+ * @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 = null, $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." );
}
/**
- * Returns the name of the default content model to be used for the page with the given title.
+ * Returns the name of the default content model to be used for the page
+ * with the given title.
*
* Note: There should rarely be need to call this method directly.
- * To determine the actual content model for a given page, use Title::getContentModel().
- *
- * Which model is to be used per default for the page is determined based on several factors:
- * * The global setting $wgNamespaceContentModels specifies a content model per namespace.
- * * The hook DefaultModelFor may be used to override the page's default model.
- * * Pages in NS_MEDIAWIKI and NS_USER default to the CSS or JavaScript model if they end in .js or .css, respectively.
- * * Pages in NS_MEDIAWIKI default to the wikitext model otherwise.
- * * The hook TitleIsCssOrJsPage may be used to force a page to use the CSS or JavaScript model if they end in .js or .css, respectively.
- * * The hook TitleIsWikitextPage may be used to force a page to use the wikitext model.
+ * To determine the actual content model for a given page, use
+ * Title::getContentModel().
+ *
+ * Which model is to be used by default for the page is determined based
+ * on several factors:
+ * - The global setting $wgNamespaceContentModels specifies a content model
+ * per namespace.
+ * - The hook DefaultModelFor may be used to override the page's default
+ * model.
+ * - Pages in NS_MEDIAWIKI and NS_USER default to the CSS or JavaScript
+ * model if they end in .js or .css, respectively.
+ * - Pages in NS_MEDIAWIKI default to the wikitext model otherwise.
+ * - The hook TitleIsCssOrJsPage may be used to force a page to use the CSS
+ * or JavaScript model if they end in .js or .css, respectively.
+ * - The hook TitleIsWikitextPage may be used to force a page to use the
+ * wikitext model.
*
* If none of the above applies, the wikitext model is used.
*
* @since WD.1
*
* @static
- * @param Title $title
+ * @param $title Title
* @return null|string default model name for the page given by $title
*/
public static function getDefaultModelFor( Title $title ) {
global $wgNamespaceContentModels;
// NOTE: this method must not rely on $title->getContentModel() directly or indirectly,
- // because it is used to initialized the mContentModel member.
+ // because it is used to initialize the mContentModel member.
$ns = $title->getNamespace();
$model = $wgNamespaceContentModels[ $ns ];
}
- // hook can determin default model
+ // Hook can determine default model
if ( !wfRunHooks( 'ContentHandlerDefaultModelFor', array( $title, &$model ) ) ) {
if ( !is_null( $model ) ) {
return $model;
$ext = $m[1];
}
- // hook can force js/css
+ // Hook can force JS/CSS
wfRunHooks( 'TitleIsCssOrJsPage', array( $title, &$isCssOrJsPage ) );
// Is this a .css subpage of a user page?
- $isJsCssSubpage = NS_USER == $ns && !$isCssOrJsPage && preg_match( "/\\/.*\\.(js|css)$/", $title->getText(), $m );
+ $isJsCssSubpage = NS_USER == $ns
+ && !$isCssOrJsPage
+ && preg_match( "/\\/.*\\.(js|css)$/", $title->getText(), $m );
if ( $isJsCssSubpage ) {
$ext = $m[1];
}
- // is this wikitext, according to $wgNamespaceContentModels or the DefaultModelFor hook?
+ // Is this wikitext, according to $wgNamespaceContentModels or the DefaultModelFor hook?
$isWikitext = is_null( $model ) || $model == CONTENT_MODEL_WIKITEXT;
$isWikitext = $isWikitext && !$isCssOrJsPage && !$isJsCssSubpage;
- // hook can override $isWikitext
+ // Hook can override $isWikitext
wfRunHooks( 'TitleIsWikitextPage', array( $title, &$isWikitext ) );
if ( !$isWikitext ) {
}
}
- // we established that is must be wikitext
+ // We established that it must be wikitext
return CONTENT_MODEL_WIKITEXT;
}
/**
- * returns the appropriate ContentHandler singleton for the given title
+ * Returns the appropriate ContentHandler singleton for the given title.
*
* @since WD.1
*
* @static
- * @param Title $title
+ * @param $title Title
* @return ContentHandler
*/
public static function getForTitle( Title $title ) {
}
/**
- * returns the appropriate ContentHandler singleton for the given Content object
+ * Returns the appropriate ContentHandler singleton for the given Content
+ * object.
*
* @since WD.1
*
* @static
- * @param Content $content
+ * @param $content Content
* @return ContentHandler
*/
public static function getForContent( Content $content ) {
}
/**
- * returns the ContentHandler singleton for the given model id. Use the CONTENT_MODEL_XXX constants to
- * identify the desired content model.
+ * @var Array A Cache of ContentHandler instances by model id
+ */
+ static $handlers;
+
+ /**
+ * Returns the ContentHandler singleton for the given model ID. Use the
+ * CONTENT_MODEL_XXX constants to identify the desired content model.
*
- * ContentHandler singletons are take from the global $wgContentHandlers array. Keys in that array are
- * model names, the values are either ContentHandler singleton objects, or strings specifying the appropriate
+ * ContentHandler singletons are taken from the global $wgContentHandlers
+ * array. Keys in that array are model names, the values are either
+ * ContentHandler singleton objects, or strings specifying the appropriate
* subclass of ContentHandler.
*
- * If a class name in encountered when looking up the singleton for a given model name, the class is
- * instantiated and the class name is replaced by te resulting singleton in $wgContentHandlers.
+ * If a class name is encountered when looking up the singleton for a given
+ * model name, the class is instantiated and the class name is replaced by
+ * the resulting singleton in $wgContentHandlers.
*
- * If no ContentHandler is defined for the desired $modelId, the ContentHandler may be provided by the
- * a ContentHandlerForModelID hook. if no ContentHandler can be determined, an MWException is raised.
+ * If no ContentHandler is defined for the desired $modelId, the
+ * ContentHandler may be provided by the ContentHandlerForModelID hook.
+ * If no ContentHandler can be determined, an MWException is raised.
*
* @since WD.1
*
* @static
- * @param $modelId int the id of the content model for which to get a handler. Use CONTENT_MODEL_XXX constants.
- * @return ContentHandler the ContentHandler singleton for handling the model given by $modelId
+ * @param $modelId String The ID of the content model for which to get a
+ * handler. Use CONTENT_MODEL_XXX constants.
+ * @return ContentHandler The ContentHandler singleton for handling the
+ * model given by $modelId
* @throws MWException if no handler is known for $modelId.
*/
public static function getForModelID( $modelId ) {
global $wgContentHandlers;
+ if ( isset( ContentHandler::$handlers[$modelId] ) ) {
+ return ContentHandler::$handlers[$modelId];
+ }
+
if ( empty( $wgContentHandlers[$modelId] ) ) {
$handler = null;
wfRunHooks( 'ContentHandlerForModelID', array( $modelId, &$handler ) );
- if ( $handler ) { // NOTE: may be a string or an object, either is fine!
- $wgContentHandlers[$modelId] = $handler;
- } else {
+ if ( $handler === null ) {
throw new MWException( "No handler for model #$modelId registered in \$wgContentHandlers" );
}
- }
- if ( is_string( $wgContentHandlers[$modelId] ) ) {
+ if ( !( $handler instanceof ContentHandler ) ) {
+ throw new MWException( "ContentHandlerForModelID must supply a ContentHandler instance" );
+ }
+ } else {
$class = $wgContentHandlers[$modelId];
- $wgContentHandlers[$modelId] = new $class( $modelId );
+ $handler = new $class( $modelId );
+
+ if ( !( $handler instanceof ContentHandler ) ) {
+ throw new MWException( "$class from \$wgContentHandlers is not compatible with ContentHandler" );
+ }
}
- return $wgContentHandlers[$modelId];
+ ContentHandler::$handlers[$modelId] = $handler;
+ return ContentHandler::$handlers[$modelId];
}
/**
- * Returns the appropriate mime type for a given content format,
- * or null if no mime type is known for this format.
+ * Returns the localized name for a given content model.
*
- * Mime types can be registered in the global array $wgContentFormatMimeTypes.
+ * Model names are localized using system messages. Message keys
+ * have the form content-model-$name, where $name is getContentModelName( $id ).
*
* @static
- * @param int $id the content format id, as given by a CONTENT_FORMAT_XXX constant
- * or returned by Revision::getContentFormat().
+ * @param $name String The content model ID, as given by a CONTENT_MODEL_XXX
+ * constant or returned by Revision::getContentModel().
*
- * @return String|null the content format's mime type.
+ * @return string The content format's localized name.
+ * @throws MWException if the model id isn't known.
*/
- public static function getContentFormatMimeType( $id ) {
- global $wgContentFormatMimeTypes;
-
- if ( !isset( $wgContentFormatMimeTypes[ $id ] ) ) {
- return null;
- }
+ public static function getLocalizedName( $name ) {
+ $key = "content-model-$name";
- return $wgContentFormatMimeTypes[ $id ];
+ if ( wfEmptyMsg( $key ) ) return $name;
+ else return wfMsg( $key );
}
- /**
- * Returns the content format if for a given mime type,
- * or null if no format id if known for this mime type.
- *
- * Mime types can be registered in the global array $wgContentFormatMimeTypes.
- *
- * @static
- * @param String $mime the mime type
- *
- * @return int|null the format id, as defined by a CONTENT_FORMAT_XXX constant
- */
- public static function getContentFormatID( $mime ) {
- global $wgContentFormatMimeTypes;
-
- static $format_ids = null;
+ public static function getContentModels() {
+ global $wgContentHandlers;
- if ( $format_ids === null ) {
- $format_ids = array_flip( $wgContentFormatMimeTypes );
- }
+ return array_keys( $wgContentHandlers );
+ }
- if ( !isset( $format_ids[ $mime ] ) ) {
- return null;
- }
+ public static function getAllContentFormats() {
+ global $wgContentHandlers;
- return $format_ids[ $mime ];
- }
+ $formats = array();
- /**
- * Returns the localized name for a given content model,
- * or null of no mime type is known.
- *
- * Model names are localized using system messages. Message keys
- * have the form content-model-$id.
- *
- * @static
- * @param int $id the content model id, as given by a CONTENT_MODEL_XXX constant
- * or returned by Revision::getContentModel().
- *
- * @return String|null the content format's mime type.
- */
- public static function getContentModelName( $id ) {
- $key = "content-model-$id";
+ foreach ( $wgContentHandlers as $model => $class ) {
+ $handler = ContentHandler::getForModelID( $model );
+ $formats = array_merge( $formats, $handler->getSupportedFormats() );
+ }
- if ( wfEmptyMsg( $key ) ) return null;
- else return wfMsg( $key );
+ $formats = array_unique( $formats );
+ return $formats;
}
- // ----------------------------------------------------------------------------------------------------------
+ // ------------------------------------------------------------------------
protected $mModelID;
protected $mSupportedFormats;
/**
- * Constructor, initializing the ContentHandler instance with it's model id and a list of supported formats.
- * Values for the parameters are typically provided as literals by subclasses' constructors.
+ * Constructor, initializing the ContentHandler instance with its model ID
+ * and a list of supported formats. Values for the parameters are typically
+ * provided as literals by subclass's constructors.
*
- * @param int $modelId (use CONTENT_MODEL_XXX constants).
- * @param array $formats list for supported serialization formats (typically as MIME types)
+ * @param $modelId String (use CONTENT_MODEL_XXX constants).
+ * @param $formats array List for supported serialization formats
+ * (typically as MIME types)
*/
public function __construct( $modelId, $formats ) {
$this->mModelID = $modelId;
$this->mSupportedFormats = $formats;
- }
+ $this->mModelName = preg_replace( '/(Content)?Handler$/', '', get_class( $this ) );
+ $this->mModelName = preg_replace( '/[_\\\\]/', '', $this->mModelName );
+ $this->mModelName = strtolower( $this->mModelName );
+ }
/**
- * Serializes Content object of the type supported by this ContentHandler.
+ * Serializes a Content object of the type supported by this ContentHandler.
*
* @since WD.1
*
* @abstract
- * @param Content $content the Content object to serialize
- * @param null $format the desired serialization format
- * @return String serialized form of the content
+ * @param $content Content The Content object to serialize
+ * @param $format null|String The desired serialization format
+ * @return string Serialized form of the content
*/
public abstract function serializeContent( Content $content, $format = null );
* @since WD.1
*
* @abstract
- * @param $blob String serialized form of the content
- * @param null $format the format used for serialization
+ * @param $blob string serialized form of the content
+ * @param $format null|String the format used for serialization
* @return Content the Content object created by deserializing $blob
*/
public abstract function unserializeContent( $blob, $format = null );
/**
- * Creates an empty Content object of the type supported by this ContentHandler.
+ * Creates an empty Content object of the type supported by this
+ * ContentHandler.
*
* @since WD.1
*
public abstract function makeEmptyContent();
/**
- * Returns the model id that identifies the content model this ContentHandler can handle.
- * Use with the CONTENT_MODEL_XXX constants.
+ * Returns the model id that identifies the content model this
+ * ContentHandler can handle. Use with the CONTENT_MODEL_XXX constants.
*
* @since WD.1
*
- * @return int the model id
+ * @return String The model ID
*/
public function getModelID() {
return $this->mModelID;
}
/**
- * Throws an MWException if $model_id is not the id of the content model
+ * Throws an MWException if $model_id is not the ID of the content model
* supported by this ContentHandler.
*
* @since WD.1
*
- * @param int $model_id the model to check
+ * @param String $model_id The model to check
*
* @throws MWException
*/
protected function checkModelID( $model_id ) {
if ( $model_id !== $this->mModelID ) {
- $model_name = ContentHandler::getContentModelName( $model_id );
- $own_model_name = ContentHandler::getContentModelName( $this->mModelID );
-
- throw new MWException( "Bad content model: expected {$this->mModelID} ($own_model_name) but got found $model_id ($model_name)." );
+ throw new MWException( "Bad content model: " .
+ "expected {$this->mModelID} " .
+ "but got $model_id." );
}
}
/**
- * Returns a list of serialization formats supported by the serializeContent() and unserializeContent() methods of
- * this ContentHandler.
+ * Returns a list of serialization formats supported by the
+ * serializeContent() and unserializeContent() methods of this
+ * ContentHandler.
*
* @since WD.1
*
}
/**
- * The format used for serialization/deserialization per default by this ContentHandler.
+ * The format used for serialization/deserialization by default by this
+ * ContentHandler.
*
- * This default implementation will return the first element of the array of formats
- * that was passed to the constructor.
+ * This default implementation will return the first element of the array
+ * of formats that was passed to the constructor.
*
* @since WD.1
*
- * @return String the name of the default serialization format as a MIME type
+ * @return string the name of the default serialization format as a MIME type
*/
public function getDefaultFormat() {
return $this->mSupportedFormats[0];
}
/**
- * Returns true if $format is a serialization format supported by this ContentHandler,
- * and false otherwise.
+ * Returns true if $format is a serialization format supported by this
+ * ContentHandler, and false otherwise.
*
- * Note that if $format is null, this method always returns true, because null
- * means "use the default format".
+ * Note that if $format is null, this method always returns true, because
+ * null means "use the default format".
*
* @since WD.1
*
- * @param String $format the serialization format to check
+ * @param $format string the serialization format to check
* @return bool
*/
public function isSupportedFormat( $format ) {
}
/**
- * Throws an MWException if isSupportedFormat( $format ) is not true. Convenient
- * for checking whether a format provided as a parameter is actually supported.
+ * Throws an MWException if isSupportedFormat( $format ) is not true.
+ * Convenient for checking whether a format provided as a parameter is
+ * actually supported.
*
- * @param String $format the serialization format to check
+ * @param $format string the serialization format to check
*
* @throws MWException
*/
protected function checkFormat( $format ) {
if ( !$this->isSupportedFormat( $format ) ) {
- throw new MWException( "Format $format is not supported for content model " . $this->getModelID() );
+ throw new MWException(
+ "Format $format is not supported for content model "
+ . $this->getModelID()
+ );
}
}
- /**
- * Returns if the content is consistent with the database, that is if saving it to the database would not violate any
- * global constraints.
- *
- * Content needs to be valid using this method before it can be saved.
- *
- * This default implementation always returns true.
- *
- * @since WD.1
- *
- * @param \Content $content
- *
- * @return boolean
- */
- public function isConsistentWithDatabase( Content $content ) {
- return true;
- }
-
/**
* Returns overrides for action handlers.
* Classes listed here will be used instead of the default one when
}
/**
- * Factory creating an appropriate DifferenceEngine for this content model.
+ * Factory for creating an appropriate DifferenceEngine for this content model.
*
* @since WD.1
*
- * @param $context IContextSource context to use, anything else will be ignored
- * @param $old Integer old ID we want to show and diff with.
- * @param int|String $new String either 'prev' or 'next'.
- * @param $rcid Integer ??? FIXME (default 0)
- * @param $refreshCache boolean If set, refreshes the diff cache
- * @param $unhide boolean If set, allow viewing deleted revs
+ * @param $context IContextSource context to use, anything else will be
+ * ignored
+ * @param $old Integer Old ID we want to show and diff with.
+ * @param $new int|string String either 'prev' or 'next'.
+ * @param $rcid Integer ??? FIXME (default 0)
+ * @param $refreshCache boolean If set, refreshes the diff cache
+ * @param $unhide boolean If set, allow viewing deleted revs
*
* @return DifferenceEngine
*/
- public function createDifferenceEngine( IContextSource $context, $old = 0, $new = 0, $rcid = 0, #FIMXE: use everywhere!
- $refreshCache = false, $unhide = false ) {
-
+ public function createDifferenceEngine( IContextSource $context,
+ $old = 0, $new = 0,
+ $rcid = 0, # FIXME: use everywhere!
+ $refreshCache = false, $unhide = false
+ ) {
$this->checkModelID( $context->getTitle()->getContentModel() );
$diffEngineClass = $this->getDiffEngineClass();
return new $diffEngineClass( $context, $old, $new, $rcid, $refreshCache, $unhide );
}
+ /**
+ * Get the language in which the content of the given page is written.
+ *
+ * This default implementation just returns $wgContLang (except for pages in the MediaWiki namespace)
+ *
+ * Note that a page's language must be permanent and cacheable, that is, it must not depend
+ * on user preferences, request parameters or session state. The only exception is pages in the
+ * MediaWiki namespace.
+ *
+ * Also note that the page language may or may not depend on the actual content of the page,
+ * that is, this method may load the content in order to determine the language.
+ *
+ * @since 1.WD
+ *
+ * @param Title $title the page to determine the language for.
+ * @param Content|null $content the page's content, if you have it handy, to avoid reloading it.
+ *
+ * @return Language the page's language code
+ */
+ public function getPageLanguage( Title $title, Content $content = null ) {
+ global $wgContLang;
+
+ if ( $title->getNamespace() == NS_MEDIAWIKI ) {
+ // Parse mediawiki messages with correct target language
+ list( /* $unused */, $lang ) = MessageCache::singleton()->figureMessage( $title->getText() );
+ return wfGetLangObj( $lang );
+ }
+
+ return $wgContLang;
+ }
+
+ /**
+ * Get the language in which the content of this page is written when
+ * viewed by user. Defaults to $this->getPageLanguage(), but if the user
+ * specified a preferred variant, the variant will be used.
+ *
+ * This default implementation just returns $this->getPageLanguage( $title, $content ) unless
+ * the user specified a preferred variant.
+ *
+ * Note that the pages view language is not cacheable, since it depends on user settings.
+ *
+ * Also note that the page language may or may not depend on the actual content of the page,
+ * that is, this method may load the content in order to determine the language.
+ *
+ * @since 1.WD
+ *
+ * @param Title $title the page to determine the language for.
+ * @param Content|null $content the page's content, if you have it handy, to avoid reloading it.
+ *
+ * @return Language the page's language code for viewing
+ */
+ public function getPageViewLanguage( Title $title, Content $content = null ) {
+ $pageLang = $this->getPageLanguage( $title, $content );
+
+ if ( $title->getNamespace() !== NS_MEDIAWIKI ) {
+ // If the user chooses a variant, the content is actually
+ // in a language whose code is the variant code.
+ $variant = $pageLang->getPreferredVariant();
+ if ( $pageLang->getCode() !== $variant ) {
+ $pageLang = Language::factory( $variant );
+ }
+ }
+
+ return $pageLang;
+ }
+
+ /**
+ * Determines whether the content type handled by this ContentHandler
+ * can be used on the given page.
+ *
+ * This default implementation always returns true.
+ * Subclasses may override this to restrict the use of this content model to specific locations,
+ * typically based on the namespace or some other aspect of the title, such as a special suffix
+ * (e.g. ".svg" for SVG content).
+ *
+ * @param Title $title the page's title.
+ *
+ * @return bool true if content of this kind can be used on the given page, false otherwise.
+ */
+ public function canBeUsedOn( Title $title ) {
+ return true;
+ }
+
/**
* Returns the name of the diff engine to use.
*
}
/**
- * attempts to merge differences between three versions.
- * Returns a new Content object for a clean merge and false for failure or a conflict.
+ * Attempts to merge differences between three versions.
+ * Returns a new Content object for a clean merge and false for failure or
+ * a conflict.
*
* This default implementation always returns false.
*
* @since WD.1
*
- * @param Content|String $oldContent String
- * @param Content|String $myContent String
- * @param Content|String $yourContent String
+ * @param $oldContent Content|string String
+ * @param $myContent Content|string String
+ * @param $yourContent Content|string String
*
* @return Content|Bool
*/
*
* @param $oldContent Content|null: the previous text of the page.
* @param $newContent Content|null: The submitted text of the page.
- * @param $flags Int bit mask: a bit mask of flags submitted for the edit.
+ * @param $flags int Bit mask: a bit mask of flags submitted for the edit.
*
* @return string An appropriate auto-summary, or an empty string.
*/
$ot = !is_null( $oldContent ) ? $oldContent->getRedirectTarget() : null;
$rt = !is_null( $newContent ) ? $newContent->getRedirectTarget() : null;
- if ( is_object( $rt ) && ( !is_object( $ot ) || !$rt->equals( $ot ) || $ot->getFragment() != $rt->getFragment() ) ) {
-
- $truncatedtext = $newContent->getTextForSummary(
- 250
- - strlen( wfMsgForContent( 'autoredircomment' ) )
- - strlen( $rt->getFullText() ) );
-
- return wfMsgForContent( 'autoredircomment', $rt->getFullText(), $truncatedtext );
+ if ( is_object( $rt ) ) {
+ if ( !is_object( $ot )
+ || !$rt->equals( $ot )
+ || $ot->getFragment() != $rt->getFragment() )
+ {
+ $truncatedtext = $newContent->getTextForSummary(
+ 250
+ - strlen( wfMessage( 'autoredircomment' )->inContentLanguage()->text() )
+ - strlen( $rt->getFullText() ) );
+
+ return wfMessage( 'autoredircomment', $rt->getFullText() )
+ ->rawParams( $truncatedtext )->inContentLanguage()->text();
+ }
}
// New page auto-summaries
if ( $flags & EDIT_NEW && $newContent->getSize() > 0 ) {
- // If they're making a new article, give its text, truncated, in the summary.
+ // If they're making a new article, give its text, truncated, in
+ // the summary.
$truncatedtext = $newContent->getTextForSummary(
- 200 - strlen( wfMsgForContent( 'autosumm-new' ) ) );
+ 200 - strlen( wfMessage( 'autosumm-new' )->inContentLanguage()->text() ) );
- return wfMsgForContent( 'autosumm-new', $truncatedtext );
+ return wfMessage( 'autosumm-new' )->rawParams( $truncatedtext )
+ ->inContentLanguage()->text();
}
// Blanking auto-summaries
if ( !empty( $oldContent ) && $oldContent->getSize() > 0 && $newContent->getSize() == 0 ) {
- return wfMsgForContent( 'autosumm-blank' );
- } elseif ( !empty( $oldContent ) && $oldContent->getSize() > 10 * $newContent->getSize() && $newContent->getSize() < 500 ) {
+ return wfMessage( 'autosumm-blank' )->inContentLanguage()->text();
+ } elseif ( !empty( $oldContent )
+ && $oldContent->getSize() > 10 * $newContent->getSize()
+ && $newContent->getSize() < 500 )
+ {
// Removing more than 90% of the article
$truncatedtext = $newContent->getTextForSummary(
- 200 - strlen( wfMsgForContent( 'autosumm-replace' ) ) );
+ 200 - strlen( wfMessage( 'autosumm-replace' )->inContentLanguage()->text() ) );
- return wfMsgForContent( 'autosumm-replace', $truncatedtext );
+ return wfMessage( 'autosumm-replace' )->rawParams( $truncatedtext )
+ ->inContentLanguage()->text();
}
- // If we reach this point, there's no applicable auto-summary for our case, so our
- // auto-summary is empty.
-
+ // If we reach this point, there's no applicable auto-summary for our
+ // case, so our auto-summary is empty.
return '';
}
*
* @param $title Title: the page's title
* @param &$hasHistory Boolean: whether the page has a history
- * @return mixed String containing deletion reason or empty string, or boolean false
- * if no revision occurred
+ * @return mixed String containing deletion reason or empty string, or
+ * boolean false if no revision occurred
*
- * @XXX &$hasHistory is extremely ugly, it's here because WikiPage::getAutoDeleteReason() and Article::getReason() have it / want it.
+ * @XXX &$hasHistory is extremely ugly, it's here because
+ * WikiPage::getAutoDeleteReason() and Article::getReason()
+ * have it / want it.
*/
public function getAutoDeleteReason( Title $title, &$hasHistory ) {
$dbw = wfGetDB( DB_MASTER );
$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
+ // which can only be blank if there's a move/import/protect dummy
+ // revision involved
if ( $content->getSize() == 0 ) {
$prev = $rev->getPrevious();
// Find out if there was only one contributor
// Only scan the last 20 revisions
$res = $dbw->select( 'revision', 'rev_user_text',
- array( 'rev_page' => $title->getArticleID(), $dbw->bitAnd( 'rev_deleted', Revision::DELETED_USER ) . ' = 0' ),
+ array(
+ 'rev_page' => $title->getArticleID(),
+ $dbw->bitAnd( 'rev_deleted', Revision::DELETED_USER ) . ' = 0'
+ ),
__METHOD__,
array( 'LIMIT' => 20 )
);
if ( $blank ) {
// The current revision is blank and the one before is also
// blank. It's just not our lucky day
- $reason = wfMsgForContent( 'exbeforeblank', '$1' );
+ $reason = wfMessage( 'exbeforeblank', '$1' )->inContentLanguage()->text();
} else {
if ( $onlyAuthor ) {
- $reason = wfMsgForContent( 'excontentauthor', '$1', $onlyAuthor );
+ $reason = wfMessage(
+ 'excontentauthor',
+ '$1',
+ $onlyAuthor
+ )->inContentLanguage()->text();
} else {
- $reason = wfMsgForContent( 'excontent', '$1' );
+ $reason = wfMessage( 'excontent', '$1' )->inContentLanguage()->text();
}
}
return $reason;
}
- /**
- * Parse the Content object and generate a ParserObject from the result. $result->getText() can
- * be used to obtain the generated HTML. If no HTML is needed, $generateHtml can be set to false;
- * in that case, $result->getText() may return null.
- *
- * @param Content $content the content to render
- * @param Title $title the page title to use as a context for rendering
- * @param null|int $revId the revision being rendered (optional)
- * @param null|ParserOptions $options any parser options
- * @param Boolean $generateHtml whether to generate Html (default: true). If false,
- * the result of calling getText() on the ParserOutput object returned by
- * this method is undefined.
- *
- * @since WD.1
- *
- * @return ParserOutput
- */
- public abstract function getParserOutput( Content $content, Title $title, $revId = null, ParserOptions $options = null, $generateHtml = true );
- #TODO: make RenderOutput and RenderOptions base classes
-
- /**
- * Returns a list of DataUpdate objects for recording information about this Content in some secondary
- * data store. If the optional second argument, $old, is given, the updates may model only the changes that
- * need to be made to replace information about the old content with information about the new content.
- *
- * This default implementation calls $this->getParserOutput( $content, $title, null, null, false ), and then
- * calls getSecondaryDataUpdates( $title, $recursive ) on the resulting ParserOutput object.
- *
- * Subclasses may implement this to determine the necessary updates more efficiently, or make use of information
- * about the old content.
- *
- * @param Content $content the content for determining the necessary updates
- * @param Title $title the context for determining the necessary updates
- * @param Content|null $old an optional Content object representing the previous content, i.e. the content being
- * replaced by this Content object.
- * @param boolean $recursive whether to include recursive updates (default: false).
- * @param ParserOutput|null $parserOutput optional ParserOutput object. Provide if you have one handy, to avoid re-parsing
- * of the content.
- *
- * @return Array. A list of DataUpdate objects for putting information about this content object somewhere.
- *
- * @since WD.1
- */
- public function getSecondaryDataUpdates( Content $content, Title $title, Content $old = null,
- $recursive = true, ParserOutput $parserOutput = null ) {
-
- if ( !$parserOutput ) {
- $parserOutput = $this->getParserOutput( $content, $title, null, null, false );
- }
-
- return $parserOutput->getSecondaryDataUpdates( $title, $recursive );
- }
-
-
/**
* Get the Content object that needs to be saved in order to undo all revisions
* between $undo and $undoafter. Revisions must belong to the same page,
- * must exist and must not be deleted
+ * must exist and must not be deleted.
*
* @since WD.1
*
- * @param $current Revision the current text
- * @param $undo Revision the revision to undo
+ * @param $current Revision The current text
+ * @param $undo Revision The revision to undo
* @param $undoafter Revision Must be an earlier revision than $undo
*
- * @return mixed string on success, false on failure
+ * @return mixed String on success, false on failure
*/
public function getUndoContent( Revision $current, Revision $undo, Revision $undoafter ) {
$cur_content = $current->getContent();
}
/**
- * Returns true for content models that support caching using the ParserCache mechanism.
- * See WikiPage::isParserCacheUser().
+ * Returns true for content models that support caching using the
+ * ParserCache mechanism. See WikiPage::isParserCacheUser().
*
* @since WD.1
*
}
/**
- * Returns a lost of updates to perform when the given content is deleted.
- * The necessary updates may be taken from the Content object, or depend on the current state of the database.
+ * Returns true if this content model supports sections.
*
- * @since WD.1
- *
- * @param \Content $content the Content object for deletion
- * @param \Title $title the title of the deleted page
- * @param null|\ParserOutput $parserOutput optional parser output object for efficient access to meta-information
- * about the content object. Provide if you have one handy.
+ * This default implementation returns false.
*
- * @return array a list of DataUpdate instances that will clean up the database ofter deletion.
+ * @return boolean whether sections are supported.
*/
- public function getDeletionUpdates( Content $content, Title $title, ParserOutput $parserOutput = null ) {
- return array(
- new LinksDeletionUpdate( $title ),
- );
+ public function supportsSections() {
+ return false;
}
/**
- * Returns true iff this content model supports sections.
- *
- * This default implementation returns false,
- *
- * @return boolean whether sections are supported.
+ * Call a legacy hook that uses text instead of Content objects.
+ * Will log a warning when a matching hook function is registered.
+ * If the textual representation of the content is changed by the
+ * hook function, a new Content object is constructed from the new
+ * text.
+ *
+ * @param $event String: event name
+ * @param $args Array: parameters passed to hook functions
+ * @param $warn bool: whether to log a warning (default: true). Should generally be true,
+ * may be set to false for testing.
+ *
+ * @return Boolean True if no handler aborted the hook
*/
- public function supportsSections() {
- return false;
+ public static function runLegacyHooks( $event, $args = array(), $warn = true ) {
+ if ( !Hooks::isRegistered( $event ) ) {
+ return true; // nothing to do here
+ }
+
+ if ( $warn ) {
+ wfWarn( "Using obsolete hook $event" );
+ }
+
+ // convert Content objects to text
+ $contentObjects = array();
+ $contentTexts = array();
+
+ foreach ( $args as $k => $v ) {
+ if ( $v instanceof Content ) {
+ /* @var Content $v */
+
+ $contentObjects[$k] = $v;
+
+ $v = $v->serialize();
+ $contentTexts[ $k ] = $v;
+ $args[ $k ] = $v;
+ }
+ }
+
+ // call the hook functions
+ $ok = wfRunHooks( $event, $args );
+
+ // see if the hook changed the text
+ foreach ( $contentTexts as $k => $orig ) {
+ /* @var Content $content */
+
+ $modified = $args[ $k ];
+ $content = $contentObjects[$k];
+
+ if ( $modified !== $orig ) {
+ // text was changed, create updated Content object
+ $content = $content->getContentHandler()->unserializeContent( $modified );
+ }
+
+ $args[ $k ] = $content;
+ }
+
+ return $ok;
}
}
/**
* Returns the content's text as-is.
*
- * @param Content $content
- * @param String|null $format
+ * @param $content Content
+ * @param $format string|null
* @return mixed
*/
public function serializeContent( Content $content, $format = null ) {
}
/**
- * attempts to merge differences between three versions.
- * Returns a new Content object for a clean merge and false for failure or a conflict.
+ * Attempts to merge differences between three versions. Returns a new
+ * Content object for a clean merge and false for failure or a conflict.
*
- * All three Content objects passed as parameters must have the same content model.
+ * All three Content objects passed as parameters must have the same
+ * content model.
*
* This text-based implementation uses wfMerge().
*
- * @param \Content|String $oldContent String
- * @param \Content|String $myContent String
- * @param \Content|String $yourContent String
+ * @param $oldContent \Content|string String
+ * @param $myContent \Content|string String
+ * @param $yourContent \Content|string String
*
* @return Content|Bool
*/
return $mergedContent;
}
- /**
- * Returns a generic ParserOutput object, wrapping the HTML returned by getHtml().
- *
- * @param Content $content the content to render
- * @param Title $title context title for parsing
- * @param int|null $revId revision id (the parser wants that for some reason)
- * @param ParserOptions|null $options parser options
- * @param bool $generateHtml whether or not to generate HTML
- *
- * @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 );
- else $html = '';
-
- $po = new ParserOutput( $html );
- return $po;
- }
-
- /**
- * Generates an HTML version of the content, for display.
- * 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 an HTML representation of the content
- */
- protected function getHtml( Content $content ) {
- $this->checkModelID( $content->getModel() );
-
- return $this->getHighlightHtml( $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: make Highlighter interface, use here highlighter, if available
- return htmlspecialchars( $content->getNativeData() );
- }
-
-
}
/**
return new WikitextContent( '' );
}
- /**
- * Returns a ParserOutput object resulting from parsing the content's text using $wgParser.
- *
- * @since WD.1
- *
- * @param Content $content the content to render
- * @param \Title $title
- * @param null $revId
- * @param null|ParserOptions $options
- * @param bool $generateHtml
- *
- * @internal param \IContextSource|null $context
- * @return ParserOutput representing the HTML form of the text
- */
- 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();
- }
-
- $po = $wgParser->parse( $content->getNativeData(), $title, $options, true, true, $revId );
- return $po;
- }
-
- protected function getHtml( Content $content ) {
- throw new MWException( "getHtml() not implemented for wikitext. Use getParserOutput()->getText()." );
- }
-
/**
* Returns true because wikitext supports sections.
*
}
}
-#XXX: make ScriptContentHandler base class, do highlighting stuff there?
+# XXX: make ScriptContentHandler base class, do highlighting stuff there?
/**
* @since WD.1
return new JavaScriptContent( '' );
}
- protected function getHtml( Content $content ) {
- $html = "";
- $html .= "<pre class=\"mw-code mw-js\" dir=\"ltr\">\n";
- $html .= $this->getHighlightHtml( $content );
- $html .= "\n</pre>\n";
+ /**
+ * Returns the english language, because JS is english, and should be handled as such.
+ *
+ * @return Language wfGetLangObj( 'en' )
+ *
+ * @see ContentHandler::getPageLanguage()
+ */
+ public function getPageLanguage( Title $title, Content $content = null ) {
+ return wfGetLangObj( 'en' );
+ }
- return $html;
+ /**
+ * Returns the english language, because CSS is english, and should be handled as such.
+ *
+ * @return Language wfGetLangObj( 'en' )
+ *
+ * @see ContentHandler::getPageViewLanguage()
+ */
+ public function getPageViewLanguage( Title $title, Content $content = null ) {
+ return wfGetLangObj( 'en' );
}
}
return new CssContent( '' );
}
+ /**
+ * Returns the english language, because CSS is english, and should be handled as such.
+ *
+ * @return Language wfGetLangObj( 'en' )
+ *
+ * @see ContentHandler::getPageLanguage()
+ */
+ public function getPageLanguage( Title $title, Content $content = null ) {
+ return wfGetLangObj( 'en' );
+ }
- protected function getHtml( Content $content ) {
- $html = "";
- $html .= "<pre class=\"mw-code mw-css\" dir=\"ltr\">\n";
- $html .= $this->getHighlightHtml( $content );
- $html .= "\n</pre>\n";
-
- return $html;
+ /**
+ * Returns the english language, because CSS is english, and should be handled as such.
+ *
+ * @return Language wfGetLangObj( 'en' )
+ *
+ * @see ContentHandler::getPageViewLanguage()
+ */
+ public function getPageViewLanguage( Title $title, Content $content = null ) {
+ return wfGetLangObj( 'en' );
}
}