29 use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
36 use Wikimedia\Assert\Assert;
60 use ProtectedHookAccessorTrait;
102 wfDebugLog(
'ContentHandler',
'Accessing ' .
$content->getModel() .
' content as text!' );
106 "Attempt to get text from Content with model " .
143 $modelId =
null, $format =
null ) {
144 if ( $modelId ===
null ) {
146 throw new MWException(
"Must provide a Title object or a content model ID." );
149 $modelId =
$title->getContentModel();
152 return MediaWikiServices::getInstance()
153 ->getContentHandlerFactory()
154 ->getContentHandler( $modelId )
155 ->unserializeContent( $text, $format );
195 $slotRoleregistry = MediaWikiServices::getInstance()->getSlotRoleRegistry();
196 $mainSlotHandler = $slotRoleregistry->getRoleHandler(
'main' );
197 return $mainSlotHandler->getDefaultModel(
$title );
214 return MediaWikiServices::getInstance()
215 ->getContentHandlerFactory()
216 ->getContentHandler(
$title->getContentModel() );
235 return MediaWikiServices::getInstance()
236 ->getContentHandlerFactory()
237 ->getContentHandler(
$content->getModel() );
270 return MediaWikiServices::getInstance()
271 ->getContentHandlerFactory()
272 ->getContentHandler( $modelId );
302 $key =
"content-model-$name";
306 $msg->inLanguage(
$lang );
309 return $msg->exists() ? $msg->plain() : $name;
321 return MediaWikiServices::getInstance()->getContentHandlerFactory()->getContentModels();
333 return MediaWikiServices::getInstance()->getContentHandlerFactory()->getAllContentFormats();
360 $this->mModelID = $modelId;
361 $this->mSupportedFormats = $formats;
478 if ( $model_id !== $this->mModelID ) {
480 "expected {$this->mModelID} " .
481 "but got $model_id." );
512 return $this->mSupportedFormats[0];
534 return in_array( $format, $this->mSupportedFormats );
547 "Format $format is not supported for content model "
602 $refreshCache =
false, $unhide =
false
605 $differenceEngine =
new $diffEngineClass( $context, $old, $new, $rcid, $refreshCache, $unhide );
606 $this->getHookRunner()->onGetDifferenceEngine(
607 $context, $old, $new, $refreshCache, $unhide, $differenceEngine );
608 return $differenceEngine;
623 if ( get_class( $slotDiffRenderer ) === TextSlotDiffRenderer::class ) {
627 if ( get_class( $differenceEngine ) !== DifferenceEngine::class ) {
629 LoggerFactory::getInstance(
'diff' )->info(
630 'Falling back to DifferenceEngineSlotDiffRenderer', [
632 'DifferenceEngine' => get_class( $differenceEngine ),
637 $this->getHookRunner()->onGetSlotDiffRenderer( $this, $slotDiffRenderer, $context );
638 return $slotDiffRenderer;
664 if ( $internalRenderer !==
null ) {
665 return $internalRenderer;
668 $contentLanguage = MediaWikiServices::getInstance()->getContentLanguage();
669 $statsdDataFactory = MediaWikiServices::getInstance()->getStatsdDataFactory();
671 $slotDiffRenderer->setStatsdDataFactory( $statsdDataFactory );
673 $slotDiffRenderer->setLanguage( $contentLanguage );
675 $inline = ( $options[
'diff-type'] ??
'' ) ===
'inline';
676 $engine =
'wikidiff2';
679 if ( $engine ===
'php' ) {
681 } elseif ( $engine ===
'wikidiff2' ) {
691 return $slotDiffRenderer;
716 $services = MediaWikiServices::getInstance();
717 $pageLang = $services->getContentLanguage();
721 list( ,
$lang ) = $services->getMessageCache()->figureMessage(
$title->getText() );
722 $pageLang = $services->getLanguageFactory()->getLanguage(
$lang );
729 $this->getHookRunner()->onPageContentLanguage(
$title, $pageLang,
$wgLang );
762 if ( $pageLang->getCode() !== $variant ) {
763 $pageLang = MediaWikiServices::getInstance()->getLanguageFactory()
764 ->getLanguage( $variant );
794 $this->getHookRunner()->onContentModelCanBeUsedOn( $this->
getModelID(), $title, $ok );
808 return DifferenceEngine::class;
836 return MediaWikiServices::getInstance()->getLanguageConverterFactory()
837 ->getLanguageConverter( $language );
857 $oldTarget = $oldContent !==
null ? $oldContent->getRedirectTarget() :
null;
858 $newTarget = $newContent !==
null ? $newContent->getRedirectTarget() :
null;
863 if ( $oldContent && $oldContent->getSize() > 0 &&
864 $newContent && $newContent->getSize() === 0
873 return 'new-redirect';
874 } elseif ( !$newTarget->equals( $oldTarget ) ||
875 $oldTarget->getFragment() !== $newTarget->getFragment()
878 return 'changed-redirect-target';
880 } elseif ( $oldTarget ) {
882 return 'removed-redirect';
886 if ( $flags &
EDIT_NEW && $newContent ) {
887 if ( $newContent->getSize() === 0 ) {
896 if ( $oldContent && $newContent && $oldContent->getSize() > 10 * $newContent->getSize() ) {
901 if ( $oldContent && $newContent && $oldContent->getModel() !== $newContent->getModel() ) {
902 return 'contentmodelchange';
925 $changeType = $this->
getChangeType( $oldContent, $newContent, $flags );
928 if ( !$changeType ) {
933 switch ( $changeType ) {
935 $newTarget = $newContent->getRedirectTarget();
936 $truncatedtext = $newContent->getTextForSummary(
938 - strlen(
wfMessage(
'autoredircomment' )->inContentLanguage()->text() )
939 - strlen( $newTarget->getFullText() )
942 return wfMessage(
'autoredircomment', $newTarget->getFullText() )
943 ->plaintextParams( $truncatedtext )->inContentLanguage()->text();
944 case 'changed-redirect-target':
945 $oldTarget = $oldContent->getRedirectTarget();
946 $newTarget = $newContent->getRedirectTarget();
948 $truncatedtext = $newContent->getTextForSummary(
950 - strlen(
wfMessage(
'autosumm-changed-redirect-target' )
951 ->inContentLanguage()->text() )
952 - strlen( $oldTarget->getFullText() )
953 - strlen( $newTarget->getFullText() )
956 return wfMessage(
'autosumm-changed-redirect-target',
957 $oldTarget->getFullText(),
958 $newTarget->getFullText() )
959 ->rawParams( $truncatedtext )->inContentLanguage()->text();
960 case 'removed-redirect':
961 $oldTarget = $oldContent->getRedirectTarget();
962 $truncatedtext = $newContent->getTextForSummary(
964 - strlen(
wfMessage(
'autosumm-removed-redirect' )
965 ->inContentLanguage()->text() )
966 - strlen( $oldTarget->getFullText() ) );
968 return wfMessage(
'autosumm-removed-redirect', $oldTarget->getFullText() )
969 ->rawParams( $truncatedtext )->inContentLanguage()->text();
972 $truncatedtext = $newContent->getTextForSummary(
973 200 - strlen(
wfMessage(
'autosumm-new' )->inContentLanguage()->text() ) );
975 return wfMessage(
'autosumm-new' )->rawParams( $truncatedtext )
976 ->inContentLanguage()->text();
978 return wfMessage(
'autosumm-blank' )->inContentLanguage()->text();
980 $truncatedtext = $newContent->getTextForSummary(
981 200 - strlen(
wfMessage(
'autosumm-replace' )->inContentLanguage()->text() ) );
983 return wfMessage(
'autosumm-replace' )->rawParams( $truncatedtext )
984 ->inContentLanguage()->text();
986 return wfMessage(
'autosumm-newblank' )->inContentLanguage()->text();
1009 $changeType = $this->
getChangeType( $oldContent, $newContent, $flags );
1012 if ( !$changeType ) {
1019 $tag =
'mw-' . $changeType;
1047 $revStore = MediaWikiServices::getInstance()->getRevisionStore();
1052 if ( $revRecord ===
null ) {
1057 $content = $revRecord->getContent( SlotRecord::MAIN );
1064 $prev =
$revStore->getPreviousRevision( $revRecord );
1068 $content = $prev->getContent( SlotRecord::MAIN );
1073 $this->
checkModelID( $revRecord->getSlot( SlotRecord::MAIN )->getModel() );
1080 [
'rev_user_text' =>
$revQuery[
'fields'][
'rev_user_text'] ],
1082 'rev_page' =>
$title->getArticleID(),
1083 $dbr->bitAnd(
'rev_deleted', RevisionRecord::DELETED_USER ) .
' = 0'
1090 if (
$res ===
false ) {
1095 $hasHistory = (
$res->numRows() > 1 );
1099 $onlyAuthor = $row->rev_user_text;
1101 foreach (
$res as $row ) {
1102 if ( $row->rev_user_text != $onlyAuthor ) {
1103 $onlyAuthor =
false;
1108 $onlyAuthor =
false;
1115 $reason =
wfMessage(
'exbeforeblank',
'$1' )->inContentLanguage()->text();
1117 if ( $onlyAuthor ) {
1122 )->inContentLanguage()->text();
1124 $reason =
wfMessage(
'excontent',
'$1' )->inContentLanguage()->text();
1128 if ( $reason ==
'-' ) {
1138 $reason = str_replace(
'$1', $text, $reason );
1163 public function getUndoContent( $current, $undo, $undoafter, $undoIsLatest =
false ) {
1164 Assert::parameterType( Revision::class .
'|' . Content::class, $current,
'$current' );
1165 if ( $current instanceof
Content ) {
1166 Assert::parameter( $undo instanceof
Content,
'$undo',
1167 'Must be Content when $current is Content' );
1168 Assert::parameter( $undoafter instanceof
Content,
'$undoafter',
1169 'Must be Content when $current is Content' );
1170 $cur_content = $current;
1171 $undo_content = $undo;
1172 $undoafter_content = $undoafter;
1174 Assert::parameter( $undo instanceof
Revision,
'$undo',
1175 'Must be Revision when $current is Revision' );
1176 Assert::parameter( $undoafter instanceof
Revision,
'$undoafter',
1177 'Must be Revision when $current is Revision' );
1179 wfDeprecated( __METHOD__ .
' with Revision objects',
'1.32' );
1181 $cur_content = $current->getContent();
1183 if ( empty( $cur_content ) ) {
1187 $undo_content = $undo->getContent();
1188 $undoafter_content = $undoafter->getContent();
1190 if ( !$undo_content || !$undoafter_content ) {
1194 $undoIsLatest = $current->getId() === $undo->getId();
1200 if ( !$undoIsLatest ) {
1213 if ( $cur_content->equals( $undo_content ) ) {
1215 return $undoafter_content;
1218 $undone_content = $this->
merge3( $undo_content, $undoafter_content, $cur_content );
1220 return $undone_content;
1392 $fieldData[
'category'] = $searchDataExtractor->getCategories( $output );
1393 $fieldData[
'external_link'] = $searchDataExtractor->getExternalLinks( $output );
1394 $fieldData[
'outgoing_link'] = $searchDataExtractor->getOutgoingLinks( $output );
1395 $fieldData[
'template'] = $searchDataExtractor->getTemplates( $output );
1397 $text =
$content->getTextForSearchIndex();
1399 $fieldData[
'text'] = $text;
1400 $fieldData[
'source_text'] = $text;
1401 $fieldData[
'text_bytes'] =
$content->getSize();
1402 $fieldData[
'content_model'] =
$content->getModel();
1405 $this->getHookRunner()->onSearchDataForIndex( $fieldData, $this, $page, $output, $engine );
1431 $parserOutput =
$cache->get( $page, $parserOptions );
1434 if ( empty( $parserOutput ) ) {
1435 $renderer = MediaWikiServices::getInstance()->getRevisionRenderer();
1438 $renderer->getRenderedRevision(
1441 )->getRevisionParserOutput( [
1446 $cache->save( $parserOutput, $page, $parserOptions );
1449 return $parserOutput;
1462 if ( $revRecord ==
null ) {
1467 if ( $revRecord ==
null ) {
1468 $text = $page->
getTitle()->getPrefixedText();
1470 "No revision could be loaded for page: $text" );