50 parent::__construct(
"The content model '$modelId' is not registered on this wiki.\n" .
51 'See https://www.mediawiki.org/wiki/Content_handlers to find out which extensions ' .
52 'handle this content model.' );
81 abstract class ContentHandler {
89 protected static $enableDeprecationWarnings =
false;
120 public static function getContentText( Content $content = null ) {
123 if ( is_null( $content ) ) {
127 if ( $content instanceof TextContent ) {
131 wfDebugLog(
'ContentHandler',
'Accessing ' . $content->
getModel() .
' content as text!' );
133 if ( $wgContentHandlerTextFallback ==
'fail' ) {
135 "Attempt to get text from Content with model " .
140 if ( $wgContentHandlerTextFallback ==
'serialize' ) {
170 public static function makeContent( $text,
Title $title = null,
171 $modelId = null, $format = null ) {
172 if ( is_null( $modelId ) ) {
173 if ( is_null( $title ) ) {
174 throw new MWException(
"Must provide a Title object or a content model ID." );
180 $handler = ContentHandler::getForModelID( $modelId );
182 return $handler->unserializeContent( $text, $format );
219 public static function getDefaultModelFor(
Title $title ) {
230 if ( !
Hooks::run(
'ContentHandlerDefaultModelFor', [ $title, &$model ] ) ) {
231 if ( !is_null( $model ) ) {
237 $isCodePage =
NS_MEDIAWIKI == $ns && preg_match(
'!\.(css|js|json)$!u', $title->
getText(), $m );
243 Hooks::run(
'TitleIsCssOrJsPage', [ $title, &$isCodePage ],
'1.25' );
246 $isCodeSubpage =
NS_USER == $ns
248 && preg_match(
"/\\/.*\\.(js|css|json)$/", $title->
getText(), $m );
249 if ( $isCodeSubpage ) {
255 $isWikitext = $isWikitext && !$isCodePage && !$isCodeSubpage;
258 Hooks::run(
'TitleIsWikitextPage', [ $title, &$isWikitext ],
'1.25' );
260 if ( !$isWikitext ) {
287 public static function getForTitle(
Title $title ) {
290 return ContentHandler::getForModelID( $modelId );
303 public static function getForContent( Content $content ) {
306 return ContentHandler::getForModelID( $modelId );
312 protected static $handlers;
340 public static function getForModelID( $modelId ) {
343 if ( isset( ContentHandler::$handlers[$modelId] ) ) {
344 return ContentHandler::$handlers[$modelId];
347 if ( empty( $wgContentHandlers[$modelId] ) ) {
350 Hooks::run(
'ContentHandlerForModelID', [ $modelId, &$handler ] );
352 if ( $handler === null ) {
356 if ( !( $handler instanceof ContentHandler ) ) {
357 throw new MWException(
"ContentHandlerForModelID must supply a ContentHandler instance" );
360 $classOrCallback = $wgContentHandlers[$modelId];
362 if ( is_callable( $classOrCallback ) ) {
363 $handler = call_user_func( $classOrCallback, $modelId );
365 $handler =
new $classOrCallback( $modelId );
368 if ( !( $handler instanceof ContentHandler ) ) {
369 throw new MWException(
"$classOrCallback from \$wgContentHandlers is not " .
370 "compatible with ContentHandler" );
374 wfDebugLog(
'ContentHandler',
'Created handler for ' . $modelId
375 .
': ' . get_class( $handler ) );
377 ContentHandler::$handlers[$modelId] =
$handler;
379 return ContentHandler::$handlers[$modelId];
398 $key =
"content-model-$name";
402 $msg->inLanguage(
$lang );
405 return $msg->exists() ? $msg->plain() :
$name;
408 public static function getContentModels() {
411 return array_keys( $wgContentHandlers );
414 public static function getAllContentFormats() {
419 foreach ( $wgContentHandlers
as $model => $class ) {
420 $handler = ContentHandler::getForModelID( $model );
421 $formats = array_merge( $formats, $handler->getSupportedFormats() );
424 $formats = array_unique( $formats );
439 protected $mSupportedFormats;
450 public function __construct( $modelId, $formats ) {
451 $this->mModelID = $modelId;
452 $this->mSupportedFormats = $formats;
454 $this->mModelName = preg_replace(
'/(Content)?Handler$/',
'', get_class( $this ) );
455 $this->mModelName = preg_replace(
'/[_\\\\]/',
'', $this->mModelName );
456 $this->mModelName = strtolower( $this->mModelName );
469 abstract public function serializeContent( Content $content, $format = null );
481 public function exportTransform(
$blob, $format = null ) {
495 abstract public function unserializeContent(
$blob, $format = null );
508 public function importTransform(
$blob, $format = null ) {
520 abstract public function makeEmptyContent();
539 public function makeRedirectContent(
Title $destination, $text =
'' ) {
551 public function getModelID() {
552 return $this->mModelID;
563 protected function checkModelID( $model_id ) {
564 if ( $model_id !== $this->mModelID ) {
566 "expected {$this->mModelID} " .
567 "but got $model_id." );
580 public function getSupportedFormats() {
581 return $this->mSupportedFormats;
595 public function getDefaultFormat() {
596 return $this->mSupportedFormats[0];
612 public function isSupportedFormat( $format ) {
617 return in_array( $format, $this->mSupportedFormats );
627 protected function checkFormat( $format ) {
628 if ( !$this->isSupportedFormat( $format ) ) {
630 "Format $format is not supported for content model "
631 . $this->getModelID()
651 public function getActionOverrides() {
669 public function createDifferenceEngine( IContextSource $context, $old = 0, $new = 0,
680 $diffEngineClass = $this->getDiffEngineClass();
703 public function getPageLanguage(
Title $title, Content $content = null ) {
713 Hooks::run(
'PageContentLanguage', [ $title, &$pageLang, $wgLang ] );
738 public function getPageViewLanguage(
Title $title, Content $content = null ) {
739 $pageLang = $this->getPageLanguage( $title, $content );
744 $variant = $pageLang->getPreferredVariant();
745 if ( $pageLang->getCode() !== $variant ) {
769 public function canBeUsedOn(
Title $title ) {
772 Hooks::run(
'ContentModelCanBeUsedOn', [ $this->getModelID(), $title, &$ok ] );
784 protected function getDiffEngineClass() {
802 public function merge3( Content $oldContent, Content $myContent, Content $yourContent ) {
817 public function getAutosummary( Content $oldContent = null, Content $newContent = null,
828 $ot = !is_null( $oldContent ) ? $oldContent->getRedirectTarget() : null;
829 $rt = !is_null( $newContent ) ? $newContent->getRedirectTarget() : null;
831 if ( is_object( $rt ) ) {
832 if ( !is_object( $ot )
833 || !$rt->equals( $ot )
834 || $ot->getFragment() != $rt->getFragment()
836 $truncatedtext = $newContent->getTextForSummary(
838 - strlen(
wfMessage(
'autoredircomment' )->inContentLanguage()->
text() )
839 - strlen( $rt->getFullText() ) );
841 return wfMessage(
'autoredircomment', $rt->getFullText() )
842 ->rawParams( $truncatedtext )->inContentLanguage()->text();
851 $truncatedtext = $newContent->getTextForSummary(
852 200 - strlen(
wfMessage(
'autosumm-new' )->inContentLanguage()->
text() ) );
854 return wfMessage(
'autosumm-new' )->rawParams( $truncatedtext )
855 ->inContentLanguage()->text();
859 if ( !empty( $oldContent ) && $oldContent->getSize() > 0 && $newContent->getSize() == 0 ) {
860 return wfMessage(
'autosumm-blank' )->inContentLanguage()->text();
861 } elseif ( !empty( $oldContent )
862 && $oldContent->getSize() > 10 * $newContent->getSize()
863 && $newContent->getSize() < 500
867 $truncatedtext = $newContent->getTextForSummary(
868 200 - strlen(
wfMessage(
'autosumm-replace' )->inContentLanguage()->
text() ) );
870 return wfMessage(
'autosumm-replace' )->rawParams( $truncatedtext )
871 ->inContentLanguage()->text();
876 return wfMessage(
'autosumm-newblank' )->inContentLanguage()->text();
899 public function getAutoDeleteReason(
Title $title, &$hasHistory ) {
905 if ( is_null(
$rev ) ) {
910 $content =
$rev->getContent();
916 if ( !$content || $content->
isEmpty() ) {
917 $prev =
$rev->getPrevious();
921 $content =
$rev->getContent();
926 $this->checkModelID(
$rev->getContentModel() );
930 $res =
$dbr->select(
'revision',
'rev_user_text',
939 if ( $res ===
false ) {
944 $hasHistory = ( $res->numRows() > 1 );
945 $row =
$dbr->fetchObject( $res );
948 $onlyAuthor = $row->rev_user_text;
950 foreach ( $res
as $row ) {
951 if ( $row->rev_user_text != $onlyAuthor ) {
964 $reason =
wfMessage(
'exbeforeblank',
'$1' )->inContentLanguage()->text();
971 )->inContentLanguage()->text();
973 $reason =
wfMessage(
'excontent',
'$1' )->inContentLanguage()->text();
977 if ( $reason ==
'-' ) {
983 $text = $content ? $content->
getTextForSummary( 255 - ( strlen( $reason ) - 2 ) ) :
'';
986 $reason = str_replace(
'$1', $text, $reason );
1007 if ( empty( $cur_content ) ) {
1012 $undoafter_content = $undoafter->
getContent();
1014 if ( !$undo_content || !$undoafter_content ) {
1018 $this->checkModelID( $cur_content->getModel() );
1019 $this->checkModelID( $undo_content->getModel() );
1020 $this->checkModelID( $undoafter_content->getModel() );
1022 if ( $cur_content->equals( $undo_content ) ) {
1024 return $undoafter_content;
1027 $undone_content = $this->merge3( $undo_content, $undoafter_content, $cur_content );
1029 return $undone_content;
1046 public function makeParserOptions( $context ) {
1049 if ( $context instanceof IContextSource ) {
1051 } elseif ( $context instanceof
User ) {
1053 } elseif ( $context ===
'canonical' ) {
1056 throw new MWException(
"Bad context for parser options: $context" );
1059 $options->enableLimitReport( $wgEnableParserLimitReporting );
1073 public function isParserCacheSupported() {
1086 public function supportsSections() {
1096 public function supportsCategories() {
1109 public function supportsRedirects() {
1118 public function supportsDirectEditing() {
1127 public function supportsDirectApiEditing() {
1128 return $this->supportsDirectEditing();
1144 public static function deprecated( $func,
$version, $component =
false ) {
1145 if ( self::$enableDeprecationWarnings ) {
1167 public static function runLegacyHooks( $event,
$args = [],
1171 if ( $warn === null ) {
1172 $warn = self::$enableDeprecationWarnings;
1186 MediaWiki\suppressWarnings();
1188 foreach ( $handlers
as $handler ) {
1189 if ( is_array( $handler ) ) {
1190 if ( is_object( $handler[0] ) ) {
1191 $info = get_class( $handler[0] );
1193 $info = $handler[0];
1196 if ( isset( $handler[1] ) ) {
1197 $info .=
'::' . $handler[1];
1199 } elseif ( is_object( $handler ) ) {
1200 $info = get_class( $handler[0] );
1201 $info .=
'::on' . $event;
1206 $handlerInfo[] = $info;
1209 MediaWiki\restoreWarnings();
1211 wfWarn(
"Using obsolete hook $event via ContentHandler::runLegacyHooks()! Handlers: " .
1212 implode(
', ', $handlerInfo ), 2 );
1216 $contentObjects = [];
1219 foreach (
$args as $k => $v ) {
1220 if ( $v instanceof Content ) {
1223 $contentObjects[$k] = $v;
1225 $v = $v->serialize();
1226 $contentTexts[$k] = $v;
1235 foreach ( $contentTexts
as $k => $orig ) {
1238 $modified =
$args[$k];
1239 $content = $contentObjects[$k];
1241 if ( $modified !== $orig ) {
1258 public function getFieldsForSearchIndex(
SearchEngine $engine ) {
static newFromContext(IContextSource $context)
Get a ParserOptions object from a IContextSource object.
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
wfGetDB($db, $groups=[], $wiki=false)
Get a Database object.
const CONTENT_MODEL_WIKITEXT
getContentHandler()
Convenience method that returns the ContentHandler singleton for handling the content model that this...
serialize($format=null)
Convenience method for serializing this Content object.
getArticleID($flags=0)
Get the article ID for this Title from the link cache, adding it if necessary.
getText()
Get the text form (spaces not underscores) of the main part.
null for the local wiki Added should default to null in handler for backwards compatibility add a value to it if you want to add a cookie that have to vary cache options can modify prev or next refreshes the diff cache $unhide
if(!isset($args[0])) $lang
static isRegistered($name)
Returns true if a hook has a function registered to it.
static newFromUserAndLang(User $user, Language $lang)
Get a ParserOptions object from a given user and language.
$wgEnableParserLimitReporting
Whether to include the NewPP limit report as a HTML comment.
it s the revision text itself In either if gzip is the revision text is gzipped $flags
static getHandlers($name)
Returns an array of all the event functions attached to a hook This combines functions registered via...
getTextForSummary($maxLength=250)
Returns a textual representation of the content suitable for use in edit summaries and log messages...
Represents a title within MediaWiki.
when a variable name is used in a it is silently declared as a new local masking the global
static newFromUser($user)
Get a ParserOptions object from a given user.
static newFromTitle(LinkTarget $linkTarget, $id=0, $flags=0)
Load either the current, or a specified, revision that's attached to a given link target...
$wgContentHandlerTextFallback
How to react if a plain text version of a non-text Content object is requested using ContentHandler::...
this class mediates it Skin Encapsulates a look and feel for the wiki All of the functions that render HTML and make choices about how to render it are here and are called from various other places when and is meant to be subclassed with other skins that may override some of its functions The User object contains a reference to a and so rather than having a global skin object we just rely on the global User and get the skin with $wgUser and also has some character encoding functions and other locale stuff The current user interface language is instantiated as $wgLang
static getNamespaceContentModel($index)
Get the default content model for a namespace This does not mean that all pages in that namespace hav...
The User object encapsulates all of the user-specific settings (user_id, name, rights, email address, options, last login time).
getContentModel($flags=0)
Get the page's content model id, see the CONTENT_MODEL_XXX constants.
wfDebugLog($logGroup, $text, $dest= 'all', array $context=[])
Send a line to a supplementary debug log file, if configured, or main debug log if not...
null for the local wiki Added should default to null in handler for backwards compatibility add a value to it if you want to add a cookie that have to vary cache options can modify prev or next $refreshCache
wfWarn($msg, $callerOffset=1, $level=E_USER_NOTICE)
Send a warning either to the debug log or in a PHP error depending on $wgDevelopmentWarnings.
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context $options
string $modelId
The name of the unknown content model.
isEmpty()
Returns true if this Content object represents empty content.
Internationalisation code.
wfDeprecated($function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned after processing after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock()-offset Set to overwrite offset parameter in $wgRequest set to ''to unsetoffset-wrap String Wrap the message in html(usually something like"<
static run($event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
getNamespace()
Get the namespace index, i.e.
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at etc Handles the details of getting and saving to the user table of the and dealing with sessions and cookies OutputPage Encapsulates the entire HTML page that will be sent in response to any server request It is used by calling its functions to add text
presenting them properly to the user as errors is done by the caller return true use this to change the list i e etc $rev
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
CONTENT_MODEL_JAVASCRIPT
Uploads have to be specially set up to be secure.
getNativeData()
Returns native representation of the data.
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Exception thrown when an unregistered content model is requested.
you have access to all of the normal MediaWiki so you can get a DB use the etc For full docs on the Maintenance class
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content $content
$wgContentHandlers
Plugins for page content model handling.
Contain a class for special pages.
getContent($audience=self::FOR_PUBLIC, User $user=null)
Fetch revision content if it's available to the specified audience.
this class mediates it Skin Encapsulates a look and feel for the wiki All of the functions that render HTML and make choices about how to render it are here and are called from various other places when and is meant to be subclassed with other skins that may override some of its functions The User object contains a reference to a and so rather than having a global skin object we just rely on the global User and get the skin with $wgUser and also has some character encoding functions and other locale stuff The current user interface language is instantiated as and the local content language as $wgContLang
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output modifiable modifiable after all normalizations have been except for the $wgMaxImageArea check set to true or false to override the $wgMaxImageArea check result gives extension the possibility to transform it themselves $handler
getModel()
Returns the ID of the content model used by this Content object.
static factory($code)
Get a cached or new language object for a given language code.
null for the local wiki Added should default to null in handler for backwards compatibility add a value to it if you want to add a cookie that have to vary cache options can modify prev or next refreshes the diff cache allow viewing deleted revs & $differenceEngine
static singleton()
Get the signleton instance of this class.
Exception representing a failure to serialize or unserialize a content object.
wfGetLangObj($langcode=false)
Return a Language object from $langcode.
Allows to change the fields on the form that will be generated $name