Go to the documentation of this file.
30 use Wikimedia\Assert\Assert;
96 wfDebugLog(
'ContentHandler',
'Accessing ' .
$content->getModel() .
' content as text!' );
100 "Attempt to get text from Content with model " .
136 $modelId =
null, $format =
null ) {
137 if ( is_null( $modelId ) ) {
138 if ( is_null(
$title ) ) {
139 throw new MWException(
"Must provide a Title object or a content model ID." );
142 $modelId =
$title->getContentModel();
147 return $handler->unserializeContent( $text, $format );
187 $slotRoleregistry = MediaWikiServices::getInstance()->getSlotRoleRegistry();
188 $mainSlotHandler = $slotRoleregistry->getRoleHandler(
'main' );
189 return $mainSlotHandler->getDefaultModel(
$title );
202 $modelId =
$title->getContentModel();
257 if ( isset( self::$handlers[$modelId] ) ) {
258 return self::$handlers[$modelId];
264 Hooks::run(
'ContentHandlerForModelID', [ $modelId, &$handler ] );
266 if ( $handler ===
null ) {
271 throw new MWException(
"ContentHandlerForModelID must supply a ContentHandler instance" );
276 if ( is_callable( $classOrCallback ) ) {
277 $handler = call_user_func( $classOrCallback, $modelId );
279 $handler =
new $classOrCallback( $modelId );
284 var_export( $classOrCallback,
true ) .
" from \$wgContentHandlers is not " .
285 "compatible with ContentHandler"
290 wfDebugLog(
'ContentHandler',
'Created handler for ' . $modelId
291 .
': ' . get_class( $handler ) );
293 self::$handlers[$modelId] = $handler;
295 return self::$handlers[$modelId];
302 self::$handlers = [];
321 $key =
"content-model-$name";
325 $msg->inLanguage(
$lang );
328 return $msg->exists() ? $msg->plain() : $name;
335 Hooks::run(
'GetContentModels', [ &$models ] );
346 $formats = array_merge( $formats, $handler->getSupportedFormats() );
349 $formats = array_unique( $formats );
376 $this->mModelID = $modelId;
377 $this->mSupportedFormats = $formats;
485 if ( $model_id !== $this->mModelID ) {
487 "expected {$this->mModelID} " .
488 "but got $model_id." );
517 return $this->mSupportedFormats[0];
538 return in_array( $format, $this->mSupportedFormats );
551 "Format $format is not supported for content model "
605 $refreshCache =
false, $unhide =
false
608 $differenceEngine =
new $diffEngineClass(
$context, $old, $new, $rcid, $refreshCache, $unhide );
610 &$differenceEngine ] );
611 return $differenceEngine;
622 if ( get_class( $slotDiffRenderer ) === TextSlotDiffRenderer::class ) {
626 if ( get_class( $differenceEngine ) !== DifferenceEngine::class ) {
628 LoggerFactory::getInstance(
'diff' )->info(
629 'Falling back to DifferenceEngineSlotDiffRenderer', [
631 'DifferenceEngine' => get_class( $differenceEngine ),
637 return $slotDiffRenderer;
646 $contentLanguage = MediaWikiServices::getInstance()->getContentLanguage();
647 $statsdDataFactory = MediaWikiServices::getInstance()->getStatsdDataFactory();
649 $slotDiffRenderer->setStatsdDataFactory( $statsdDataFactory );
651 $slotDiffRenderer->setLanguage( $contentLanguage );
654 if ( $engine ===
'php' ) {
656 } elseif ( $engine ===
'wikidiff2' ) {
662 return $slotDiffRenderer;
686 $pageLang = MediaWikiServices::getInstance()->getContentLanguage();
729 $variant = $pageLang->getPreferredVariant();
730 if ( $pageLang->getCode() !== $variant ) {
772 return DifferenceEngine::class;
809 $oldTarget = $oldContent !==
null ? $oldContent->getRedirectTarget() :
null;
810 $newTarget = $newContent !==
null ? $newContent->getRedirectTarget() :
null;
815 if ( $oldContent && $oldContent->getSize() > 0 &&
816 $newContent && $newContent->getSize() === 0
825 return 'new-redirect';
826 } elseif ( !$newTarget->equals( $oldTarget ) ||
827 $oldTarget->getFragment() !== $newTarget->getFragment()
830 return 'changed-redirect-target';
832 } elseif ( $oldTarget ) {
834 return 'removed-redirect';
838 if ( $flags &
EDIT_NEW && $newContent ) {
839 if ( $newContent->getSize() === 0 ) {
848 if ( $oldContent && $newContent && $oldContent->getSize() > 10 * $newContent->getSize() ) {
853 if ( $oldContent && $newContent && $oldContent->getModel() !== $newContent->getModel() ) {
854 return 'contentmodelchange';
876 $changeType = $this->
getChangeType( $oldContent, $newContent, $flags );
879 if ( !$changeType ) {
884 switch ( $changeType ) {
886 $newTarget = $newContent->getRedirectTarget();
887 $truncatedtext = $newContent->getTextForSummary(
889 - strlen(
wfMessage(
'autoredircomment' )->inContentLanguage()->text() )
890 - strlen( $newTarget->getFullText() )
893 return wfMessage(
'autoredircomment', $newTarget->getFullText() )
894 ->plaintextParams( $truncatedtext )->inContentLanguage()->text();
895 case 'changed-redirect-target':
896 $oldTarget = $oldContent->getRedirectTarget();
897 $newTarget = $newContent->getRedirectTarget();
899 $truncatedtext = $newContent->getTextForSummary(
901 - strlen(
wfMessage(
'autosumm-changed-redirect-target' )
902 ->inContentLanguage()->text() )
903 - strlen( $oldTarget->getFullText() )
904 - strlen( $newTarget->getFullText() )
907 return wfMessage(
'autosumm-changed-redirect-target',
908 $oldTarget->getFullText(),
909 $newTarget->getFullText() )
910 ->rawParams( $truncatedtext )->inContentLanguage()->text();
911 case 'removed-redirect':
912 $oldTarget = $oldContent->getRedirectTarget();
913 $truncatedtext = $newContent->getTextForSummary(
915 - strlen(
wfMessage(
'autosumm-removed-redirect' )
916 ->inContentLanguage()->text() )
917 - strlen( $oldTarget->getFullText() ) );
919 return wfMessage(
'autosumm-removed-redirect', $oldTarget->getFullText() )
920 ->rawParams( $truncatedtext )->inContentLanguage()->text();
923 $truncatedtext = $newContent->getTextForSummary(
924 200 - strlen(
wfMessage(
'autosumm-new' )->inContentLanguage()->text() ) );
926 return wfMessage(
'autosumm-new' )->rawParams( $truncatedtext )
927 ->inContentLanguage()->text();
929 return wfMessage(
'autosumm-blank' )->inContentLanguage()->text();
931 $truncatedtext = $newContent->getTextForSummary(
932 200 - strlen(
wfMessage(
'autosumm-replace' )->inContentLanguage()->text() ) );
934 return wfMessage(
'autosumm-replace' )->rawParams( $truncatedtext )
935 ->inContentLanguage()->text();
937 return wfMessage(
'autosumm-newblank' )->inContentLanguage()->text();
959 $changeType = $this->
getChangeType( $oldContent, $newContent, $flags );
962 if ( !$changeType ) {
969 $tag =
'mw-' . $changeType;
1000 if ( is_null( $rev ) ) {
1012 $prev = $rev->getPrevious();
1028 [
'rev_user_text' =>
$revQuery[
'fields'][
'rev_user_text'] ],
1030 'rev_page' =>
$title->getArticleID(),
1031 $dbr->bitAnd(
'rev_deleted', RevisionRecord::DELETED_USER ) .
' = 0'
1038 if (
$res ===
false ) {
1043 $hasHistory = (
$res->numRows() > 1 );
1047 $onlyAuthor = $row->rev_user_text;
1049 foreach (
$res as $row ) {
1050 if ( $row->rev_user_text != $onlyAuthor ) {
1051 $onlyAuthor =
false;
1056 $onlyAuthor =
false;
1063 $reason =
wfMessage(
'exbeforeblank',
'$1' )->inContentLanguage()->text();
1065 if ( $onlyAuthor ) {
1070 )->inContentLanguage()->text();
1072 $reason =
wfMessage(
'excontent',
'$1' )->inContentLanguage()->text();
1076 if ( $reason ==
'-' ) {
1086 $reason = str_replace(
'$1', $text, $reason );
1107 public function getUndoContent( $current, $undo, $undoafter, $undoIsLatest =
false ) {
1108 Assert::parameterType( Revision::class .
'|' . Content::class, $current,
'$current' );
1109 if ( $current instanceof
Content ) {
1110 Assert::parameter( $undo instanceof
Content,
'$undo',
1111 'Must be Content when $current is Content' );
1112 Assert::parameter( $undoafter instanceof
Content,
'$undoafter',
1113 'Must be Content when $current is Content' );
1114 $cur_content = $current;
1115 $undo_content = $undo;
1116 $undoafter_content = $undoafter;
1118 Assert::parameter( $undo instanceof
Revision,
'$undo',
1119 'Must be Revision when $current is Revision' );
1120 Assert::parameter( $undoafter instanceof
Revision,
'$undoafter',
1121 'Must be Revision when $current is Revision' );
1123 $cur_content = $current->getContent();
1125 if ( empty( $cur_content ) ) {
1129 $undo_content = $undo->getContent();
1130 $undoafter_content = $undoafter->getContent();
1132 if ( !$undo_content || !$undoafter_content ) {
1136 $undoIsLatest = $current->getId() === $undo->getId();
1142 if ( !$undoIsLatest ) {
1155 if ( $cur_content->equals( $undo_content ) ) {
1157 return $undoafter_content;
1160 $undone_content = $this->
merge3( $undo_content, $undoafter_content, $cur_content );
1162 return $undone_content;
1330 $fieldData[
'category'] = $searchDataExtractor->getCategories(
$output );
1331 $fieldData[
'external_link'] = $searchDataExtractor->getExternalLinks(
$output );
1332 $fieldData[
'outgoing_link'] = $searchDataExtractor->getOutgoingLinks(
$output );
1333 $fieldData[
'template'] = $searchDataExtractor->getTemplates(
$output );
1335 $text =
$content->getTextForSearchIndex();
1337 $fieldData[
'text'] = $text;
1338 $fieldData[
'source_text'] = $text;
1339 $fieldData[
'text_bytes'] =
$content->getSize();
1340 $fieldData[
'content_model'] =
$content->getModel();
1343 Hooks::run(
'SearchDataForIndex', [ &$fieldData, $this, $page,
$output, $engine ] );
1361 $parserOutput =
$cache->get( $page, $parserOptions );
1364 if ( empty( $parserOutput ) ) {
1365 $renderer = MediaWikiServices::getInstance()->getRevisionRenderer();
1367 $renderer->getRenderedRevision(
1370 )->getRevisionParserOutput();
1372 $cache->save( $parserOutput, $page, $parserOptions );
1375 return $parserOutput;
const INDEX_TYPE_KEYWORD
KEYWORD fields are indexed without any processing, so are appropriate for e.g.
getSecondaryDataUpdates(Title $title, Content $content, $role, SlotRenderingProvider $slotOutput)
Returns a list of DeferrableUpdate objects for recording information about the given Content in some ...
getSlotDiffRenderer(IContextSource $context)
Get an appropriate SlotDiffRenderer for this content model.
A content handler knows how do deal with a specific type of content on a wiki page.
static getForModelID( $modelId)
Returns the ContentHandler singleton for the given model ID.
static getAllContentFormats()
static getEngine()
Process DiffEngine config and get a sane, usable engine.
supportsDirectEditing()
Return true if this content model supports direct editing, such as via EditPage.
if(!isset( $args[0])) $lang
makeParserOptions( $context)
Get parser options suitable for rendering and caching the article.
getSlotDiffRendererInternal(IContextSource $context)
Return the SlotDiffRenderer appropriate for this content handler.
getActionOverrides()
Returns overrides for action handlers.
getAutoDeleteReason(Title $title, &$hasHistory)
Auto-generates a deletion reason.
unserializeContent( $blob, $format=null)
Unserializes a Content object of the type supported by this ContentHandler.
getPageViewLanguage(Title $title, Content $content=null)
Get the language in which the content of this page is written when viewed by user.
Class representing a MediaWiki article and history.
string[] $mSupportedFormats
makeParserOptions( $context)
Get parser options suitable for rendering the primary article wikitext.
getRevision()
Get the latest revision.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
getAutosummary(Content $oldContent=null, Content $newContent=null, $flags=0)
Return an applicable auto-summary if one exists for the given edit.
const ENGINE_EXTERNAL
Use an external executable.
getDeletionUpdates(Title $title, $role)
Returns a list of DeferrableUpdate objects for removing information about content in some secondary d...
static getForTitle(Title $title)
Returns the appropriate ContentHandler singleton for the given title.
const ENGINE_WIKIDIFF2
Use the wikidiff2 PHP module.
const FLAG_CASEFOLD
Generic field flags.
getChangeTag(Content $oldContent=null, Content $newContent=null, $flags=0)
Return an applicable tag if one exists for the given edit or return null.
serializeContent(Content $content, $format=null)
Serializes a Content object of the type supported by this ContentHandler.
wfDebugLog( $logGroup, $text, $dest='all', array $context=[])
Send a line to a supplementary debug log file, if configured, or main debug log if not.
supportsSections()
Returns true if this content model supports sections.
isSupportedFormat( $format)
Returns true if $format is a serialization format supported by this ContentHandler,...
createDifferenceEngine(IContextSource $context, $old=0, $new=0, $rcid=0, $refreshCache=false, $unhide=false)
Factory for creating an appropriate DifferenceEngine for this content model.
canBeUsedOn(Title $title)
Determines whether the content type handled by this ContentHandler can be used for the main slot of t...
importTransform( $blob, $format=null)
Apply import transformation (per default, returns $blob unchanged).
supportsRedirects()
Returns true if this content model supports redirects.
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::...
static getDefaultModelFor(Title $title)
Returns the name of the default content model to be used for the page with the given title.
static getQueryInfo( $options=[])
Return the tables, fields, and join conditions to be selected to create a new revision object.
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
$wgContentHandlers
Plugins for page content model handling.
static getContentModels()
supportsDirectApiEditing()
Whether or not this content model supports direct editing via ApiEditPage.
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
wfGetLangObj( $langcode=false)
Return a Language object from $langcode.
const ENGINE_PHP
Use the PHP diff implementation (DiffEngine).
merge3(Content $oldContent, Content $myContent, Content $yourContent)
Attempts to merge differences between three versions.
makeEmptyContent()
Creates an empty Content object of the type supported by this ContentHandler.
getDataForSearchIndex(WikiPage $page, ParserOutput $output, SearchEngine $engine)
Return fields to be indexed by search engine as representation of this document.
static singleton()
Get the singleton instance of this class.
static makeContent( $text, Title $title=null, $modelId=null, $format=null)
Convenience function for creating a Content object from a given textual representation.
getPageLanguage(Title $title, Content $content=null)
Get the language in which the content of the given page is written.
isParserCacheSupported()
Returns true for content models that support caching using the ParserCache mechanism.
getDefaultFormat()
The format used for serialization/deserialization by default by this ContentHandler.
getChangeType(Content $oldContent=null, Content $newContent=null, $flags=0)
Return type of change if one exists for the given edit.
static cleanupHandlersCache()
Clean up handlers cache.
static getLocalizedName( $name, Language $lang=null)
Returns the localized name for a given content model.
getDiffEngineClass()
Returns the name of the diff engine to use.
supportsCategories()
Returns true if this content model supports categories.
static newCanonical( $context=null, $userLang=null)
Creates a "canonical" ParserOptions object.
Content object implementation for representing flat text.
Contain a class for special pages.
Interface for objects which can provide a MediaWiki context on request.
exportTransform( $blob, $format=null)
Applies transformations on export (returns the blob unchanged per default).
Base interface for content objects.
getFieldsForSearchIndex(SearchEngine $engine)
Get fields definition for search index.
makeSearchFieldMapping( $name, $type)
Create a search field definition.
Represents a title within MediaWiki.
makeRedirectContent(Title $destination, $text='')
Creates a new Content object that acts as a redirect to the given page, or null if redirects are not ...
checkFormat( $format)
Convenient for checking whether a format provided as a parameter is actually supported.
static getContentText(Content $content=null)
Convenience function for getting flat text from a Content object.
static array $handlers
A Cache of ContentHandler instances by model id.
B/C adapter for turning a DifferenceEngine into a SlotDiffRenderer.
Exception thrown when an unregistered content model is requested.
addSearchField(&$fields, SearchEngine $engine, $name, $type)
Add new field definition to array.
static factory( $code)
Get a cached or new language object for a given language code.
__construct( $modelId, $formats)
Constructor, initializing the ContentHandler instance with its model ID and a list of supported forma...
static unstub(&$obj)
Unstubs an object, if it is a stub object.
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
getUndoContent( $current, $undo, $undoafter, $undoIsLatest=false)
Get the Content object that needs to be saved in order to undo all revisions between $undo and $undoa...
getSupportedFormats()
Returns a list of serialization formats supported by the serializeContent() and unserializeContent() ...
getContent( $audience=RevisionRecord::FOR_PUBLIC, User $user=null)
Get the content of the current revision.
Internationalisation code.
getModelID()
Returns the model id that identifies the content model this ContentHandler can handle.
static getForContent(Content $content)
Returns the appropriate ContentHandler singleton for the given Content object.
getParserOutputForIndexing(WikiPage $page, ParserCache $cache=null)
Produce page output suitable for indexing.
Renders a slot diff by doing a text diff on the native representation.
const INDEX_TYPE_TEXT
TEXT fields are suitable for natural language and may be subject to analysis such as stemming.