MediaWiki  master
ContentHandler.php
Go to the documentation of this file.
1 <?php
2 
34 use Wikimedia\Assert\Assert;
35 
55 abstract class ContentHandler {
85  public static function getContentText( Content $content = null ) {
87 
88  if ( $content === null ) {
89  return '';
90  }
91 
92  if ( $content instanceof TextContent ) {
93  return $content->getText();
94  }
95 
96  wfDebugLog( 'ContentHandler', 'Accessing ' . $content->getModel() . ' content as text!' );
97 
98  if ( $wgContentHandlerTextFallback == 'fail' ) {
99  throw new MWException(
100  "Attempt to get text from Content with model " .
101  $content->getModel()
102  );
103  }
104 
105  if ( $wgContentHandlerTextFallback == 'serialize' ) {
106  return $content->serialize();
107  }
108 
109  return null;
110  }
111 
136  public static function makeContent( $text, Title $title = null,
137  $modelId = null, $format = null ) {
138  if ( $modelId === null ) {
139  if ( $title === null ) {
140  throw new MWException( "Must provide a Title object or a content model ID." );
141  }
142 
143  $modelId = $title->getContentModel();
144  }
145 
146  return MediaWikiServices::getInstance()
147  ->getContentHandlerFactory()
148  ->getContentHandler( $modelId )
149  ->unserializeContent( $text, $format );
150  }
151 
188  public static function getDefaultModelFor( Title $title ) {
189  $slotRoleregistry = MediaWikiServices::getInstance()->getSlotRoleRegistry();
190  $mainSlotHandler = $slotRoleregistry->getRoleHandler( 'main' );
191  return $mainSlotHandler->getDefaultModel( $title );
192  }
193 
207  public static function getForTitle( Title $title ) {
208  return MediaWikiServices::getInstance()
209  ->getContentHandlerFactory()
210  ->getContentHandler( $title->getContentModel() );
211  }
212 
228  public static function getForContent( Content $content ) {
229  return MediaWikiServices::getInstance()
230  ->getContentHandlerFactory()
231  ->getContentHandler( $content->getModel() );
232  }
233 
263  public static function getForModelID( $modelId ) {
264  return MediaWikiServices::getInstance()
265  ->getContentHandlerFactory()
266  ->getContentHandler( $modelId );
267  }
268 
275  public static function cleanupHandlersCache() {
276  // No-op: no longer needed, since the instance cache is in the
277  // ContentHandlerFactory service, and services get reset between tests
278  }
279 
293  public static function getLocalizedName( $name, Language $lang = null ) {
294  // Messages: content-model-wikitext, content-model-text,
295  // content-model-javascript, content-model-css
296  $key = "content-model-$name";
297 
298  $msg = wfMessage( $key );
299  if ( $lang ) {
300  $msg->inLanguage( $lang );
301  }
302 
303  return $msg->exists() ? $msg->plain() : $name;
304  }
305 
314  public static function getContentModels() {
315  return MediaWikiServices::getInstance()->getContentHandlerFactory()->getContentModels();
316  }
317 
326  public static function getAllContentFormats() {
327  return MediaWikiServices::getInstance()->getContentHandlerFactory()->getAllContentFormats();
328  }
329 
330  // ------------------------------------------------------------------------
331 
335  protected $mModelID;
336 
341 
351  public function __construct( $modelId, $formats ) {
352  $this->mModelID = $modelId;
353  $this->mSupportedFormats = $formats;
354  }
355 
366  abstract public function serializeContent( Content $content, $format = null );
367 
378  public function exportTransform( $blob, $format = null ) {
379  return $blob;
380  }
381 
393  abstract public function unserializeContent( $blob, $format = null );
394 
406  public function importTransform( $blob, $format = null ) {
407  return $blob;
408  }
409 
418  abstract public function makeEmptyContent();
419 
437  public function makeRedirectContent( Title $destination, $text = '' ) {
438  return null;
439  }
440 
449  public function getModelID() {
450  return $this->mModelID;
451  }
452 
461  protected function checkModelID( $model_id ) {
462  if ( $model_id !== $this->mModelID ) {
463  throw new MWException( "Bad content model: " .
464  "expected {$this->mModelID} " .
465  "but got $model_id." );
466  }
467  }
468 
478  public function getSupportedFormats() {
480  }
481 
493  public function getDefaultFormat() {
494  return $this->mSupportedFormats[0];
495  }
496 
510  public function isSupportedFormat( $format ) {
511  if ( !$format ) {
512  return true; // this means "use the default"
513  }
514 
515  return in_array( $format, $this->mSupportedFormats );
516  }
517 
525  protected function checkFormat( $format ) {
526  if ( !$this->isSupportedFormat( $format ) ) {
527  throw new MWException(
528  "Format $format is not supported for content model "
529  . $this->getModelID()
530  );
531  }
532  }
533 
549  public function getActionOverrides() {
550  return [];
551  }
552 
580  public function createDifferenceEngine( IContextSource $context, $old = 0, $new = 0,
581  $rcid = 0, // FIXME: Deprecated, no longer used
582  $refreshCache = false, $unhide = false
583  ) {
584  $diffEngineClass = $this->getDiffEngineClass();
585  $differenceEngine = new $diffEngineClass( $context, $old, $new, $rcid, $refreshCache, $unhide );
586  Hooks::run( 'GetDifferenceEngine', [ $context, $old, $new, $refreshCache, $unhide,
587  &$differenceEngine ] );
588  return $differenceEngine;
589  }
590 
598  final public function getSlotDiffRenderer( IContextSource $context, array $options = [] ) {
599  $slotDiffRenderer = $this->getSlotDiffRendererWithOptions( $context, $options );
600  if ( get_class( $slotDiffRenderer ) === TextSlotDiffRenderer::class ) {
601  // To keep B/C, when SlotDiffRenderer is not overridden for a given content type
602  // but DifferenceEngine is, use that instead.
603  $differenceEngine = $this->createDifferenceEngine( $context );
604  if ( get_class( $differenceEngine ) !== DifferenceEngine::class ) {
605  // TODO turn this into a deprecation warning in a later release
606  LoggerFactory::getInstance( 'diff' )->info(
607  'Falling back to DifferenceEngineSlotDiffRenderer', [
608  'modelID' => $this->getModelID(),
609  'DifferenceEngine' => get_class( $differenceEngine ),
610  ] );
611  $slotDiffRenderer = new DifferenceEngineSlotDiffRenderer( $differenceEngine );
612  }
613  }
614  Hooks::run( 'GetSlotDiffRenderer', [ $this, &$slotDiffRenderer, $context ] );
615  return $slotDiffRenderer;
616  }
617 
625  return null;
626  }
627 
634  protected function getSlotDiffRendererWithOptions( IContextSource $context, $options = [] ) {
635  $internalRenderer = $this->getSlotDiffRendererInternal( $context );
636  // `getSlotDiffRendererInternal` has been overriden by a class using the deprecated method.
637  // Options will not work so exit early!
638  if ( $internalRenderer !== null ) {
639  return $internalRenderer;
640  }
641 
642  $contentLanguage = MediaWikiServices::getInstance()->getContentLanguage();
643  $statsdDataFactory = MediaWikiServices::getInstance()->getStatsdDataFactory();
644  $slotDiffRenderer = new TextSlotDiffRenderer();
645  $slotDiffRenderer->setStatsdDataFactory( $statsdDataFactory );
646  // XXX using the page language would be better, but it's unclear how that should be injected
647  $slotDiffRenderer->setLanguage( $contentLanguage );
648 
649  $inline = ( $options['diff-type'] ?? '' ) === 'inline';
650  $engine = 'wikidiff2';
651  $engine = DifferenceEngine::getEngine();
652 
653  if ( $engine === 'php' ) {
654  $slotDiffRenderer->setEngine( TextSlotDiffRenderer::ENGINE_PHP );
655  } elseif ( $engine === 'wikidiff2' ) {
656  if ( $inline ) {
657  $slotDiffRenderer->setEngine( TextSlotDiffRenderer::ENGINE_WIKIDIFF2_INLINE );
658  } else {
659  $slotDiffRenderer->setEngine( TextSlotDiffRenderer::ENGINE_WIKIDIFF2 );
660  }
661  } else {
662  $slotDiffRenderer->setEngine( TextSlotDiffRenderer::ENGINE_EXTERNAL, $engine );
663  }
664 
665  return $slotDiffRenderer;
666  }
667 
687  public function getPageLanguage( Title $title, Content $content = null ) {
688  global $wgLang;
689  $pageLang = MediaWikiServices::getInstance()->getContentLanguage();
690 
691  if ( $title->inNamespace( NS_MEDIAWIKI ) ) {
692  // Parse mediawiki messages with correct target language
693  list( /* $unused */, $lang ) = MessageCache::singleton()->figureMessage( $title->getText() );
694  $pageLang = MediaWikiServices::getInstance()->getLanguageFactory()
695  ->getLanguage( $lang );
696  }
697 
698  // Simplify hook handlers by only passing objects of one type, in case nothing
699  // else has unstubbed the StubUserLang object by now.
701 
702  Hooks::run( 'PageContentLanguage', [ $title, &$pageLang, $wgLang ] );
703 
704  return wfGetLangObj( $pageLang );
705  }
706 
727  public function getPageViewLanguage( Title $title, Content $content = null ) {
728  $pageLang = $this->getPageLanguage( $title, $content );
729 
730  if ( $title->getNamespace() !== NS_MEDIAWIKI ) {
731  // If the user chooses a variant, the content is actually
732  // in a language whose code is the variant code.
733  $variant = $this->getLanguageConverter( $pageLang )->getPreferredVariant();
734  if ( $pageLang->getCode() !== $variant ) {
735  $pageLang = MediaWikiServices::getInstance()->getLanguageFactory()
736  ->getLanguage( $variant );
737  }
738  }
739 
740  return $pageLang;
741  }
742 
761  public function canBeUsedOn( Title $title ) {
762  $ok = true;
763 
764  Hooks::run( 'ContentModelCanBeUsedOn', [ $this->getModelID(), $title, &$ok ] );
765 
766  return $ok;
767  }
768 
776  protected function getDiffEngineClass() {
777  return DifferenceEngine::class;
778  }
779 
794  public function merge3( Content $oldContent, Content $myContent, Content $yourContent ) {
795  return false;
796  }
797 
803  private function getLanguageConverter( $language ) : ILanguageConverter {
804  return MediaWikiServices::getInstance()->getLanguageConverterFactory()
805  ->getLanguageConverter( $language );
806  }
807 
819  private function getChangeType(
820  Content $oldContent = null,
821  Content $newContent = null,
822  $flags = 0
823  ) {
824  $oldTarget = $oldContent !== null ? $oldContent->getRedirectTarget() : null;
825  $newTarget = $newContent !== null ? $newContent->getRedirectTarget() : null;
826 
827  // We check for the type of change in the given edit, and return string key accordingly
828 
829  // Blanking of a page
830  if ( $oldContent && $oldContent->getSize() > 0 &&
831  $newContent && $newContent->getSize() === 0
832  ) {
833  return 'blank';
834  }
835 
836  // Redirects
837  if ( $newTarget ) {
838  if ( !$oldTarget ) {
839  // New redirect page (by creating new page or by changing content page)
840  return 'new-redirect';
841  } elseif ( !$newTarget->equals( $oldTarget ) ||
842  $oldTarget->getFragment() !== $newTarget->getFragment()
843  ) {
844  // Redirect target changed
845  return 'changed-redirect-target';
846  }
847  } elseif ( $oldTarget ) {
848  // Changing an existing redirect into a non-redirect
849  return 'removed-redirect';
850  }
851 
852  // New page created
853  if ( $flags & EDIT_NEW && $newContent ) {
854  if ( $newContent->getSize() === 0 ) {
855  // New blank page
856  return 'newblank';
857  } else {
858  return 'newpage';
859  }
860  }
861 
862  // Removing more than 90% of the page
863  if ( $oldContent && $newContent && $oldContent->getSize() > 10 * $newContent->getSize() ) {
864  return 'replace';
865  }
866 
867  // Content model changed
868  if ( $oldContent && $newContent && $oldContent->getModel() !== $newContent->getModel() ) {
869  return 'contentmodelchange';
870  }
871 
872  return null;
873  }
874 
886  public function getAutosummary(
887  Content $oldContent = null,
888  Content $newContent = null,
889  $flags = 0
890  ) {
891  $changeType = $this->getChangeType( $oldContent, $newContent, $flags );
892 
893  // There's no applicable auto-summary for our case, so our auto-summary is empty.
894  if ( !$changeType ) {
895  return '';
896  }
897 
898  // Decide what kind of auto-summary is needed.
899  switch ( $changeType ) {
900  case 'new-redirect':
901  $newTarget = $newContent->getRedirectTarget();
902  $truncatedtext = $newContent->getTextForSummary(
903  250
904  - strlen( wfMessage( 'autoredircomment' )->inContentLanguage()->text() )
905  - strlen( $newTarget->getFullText() )
906  );
907 
908  return wfMessage( 'autoredircomment', $newTarget->getFullText() )
909  ->plaintextParams( $truncatedtext )->inContentLanguage()->text();
910  case 'changed-redirect-target':
911  $oldTarget = $oldContent->getRedirectTarget();
912  $newTarget = $newContent->getRedirectTarget();
913 
914  $truncatedtext = $newContent->getTextForSummary(
915  250
916  - strlen( wfMessage( 'autosumm-changed-redirect-target' )
917  ->inContentLanguage()->text() )
918  - strlen( $oldTarget->getFullText() )
919  - strlen( $newTarget->getFullText() )
920  );
921 
922  return wfMessage( 'autosumm-changed-redirect-target',
923  $oldTarget->getFullText(),
924  $newTarget->getFullText() )
925  ->rawParams( $truncatedtext )->inContentLanguage()->text();
926  case 'removed-redirect':
927  $oldTarget = $oldContent->getRedirectTarget();
928  $truncatedtext = $newContent->getTextForSummary(
929  250
930  - strlen( wfMessage( 'autosumm-removed-redirect' )
931  ->inContentLanguage()->text() )
932  - strlen( $oldTarget->getFullText() ) );
933 
934  return wfMessage( 'autosumm-removed-redirect', $oldTarget->getFullText() )
935  ->rawParams( $truncatedtext )->inContentLanguage()->text();
936  case 'newpage':
937  // If they're making a new article, give its text, truncated, in the summary.
938  $truncatedtext = $newContent->getTextForSummary(
939  200 - strlen( wfMessage( 'autosumm-new' )->inContentLanguage()->text() ) );
940 
941  return wfMessage( 'autosumm-new' )->rawParams( $truncatedtext )
942  ->inContentLanguage()->text();
943  case 'blank':
944  return wfMessage( 'autosumm-blank' )->inContentLanguage()->text();
945  case 'replace':
946  $truncatedtext = $newContent->getTextForSummary(
947  200 - strlen( wfMessage( 'autosumm-replace' )->inContentLanguage()->text() ) );
948 
949  return wfMessage( 'autosumm-replace' )->rawParams( $truncatedtext )
950  ->inContentLanguage()->text();
951  case 'newblank':
952  return wfMessage( 'autosumm-newblank' )->inContentLanguage()->text();
953  default:
954  return '';
955  }
956  }
957 
969  public function getChangeTag(
970  Content $oldContent = null,
971  Content $newContent = null,
972  $flags = 0
973  ) {
974  $changeType = $this->getChangeType( $oldContent, $newContent, $flags );
975 
976  // There's no applicable tag for this change.
977  if ( !$changeType ) {
978  return null;
979  }
980 
981  // Core tags use the same keys as ones returned from $this->getChangeType()
982  // but prefixed with pseudo namespace 'mw-', so we add the prefix before checking
983  // if this type of change should be tagged
984  $tag = 'mw-' . $changeType;
985 
986  // Not all change types are tagged, so we check against the list of defined tags.
987  if ( in_array( $tag, ChangeTags::getSoftwareTags() ) ) {
988  return $tag;
989  }
990 
991  return null;
992  }
993 
1009  public function getAutoDeleteReason( Title $title, &$hasHistory ) {
1010  $dbr = wfGetDB( DB_REPLICA );
1011 
1012  // Get the last revision
1013  $rev = Revision::newFromTitle( $title );
1014 
1015  if ( $rev === null ) {
1016  return false;
1017  }
1018 
1019  // Get the article's contents
1020  $content = $rev->getContent();
1021  $blank = false;
1022 
1023  // If the page is blank, use the text from the previous revision,
1024  // which can only be blank if there's a move/import/protect dummy
1025  // revision involved
1026  if ( !$content || $content->isEmpty() ) {
1027  $prev = $rev->getPrevious();
1028 
1029  if ( $prev ) {
1030  $rev = $prev;
1031  $content = $rev->getContent();
1032  $blank = true;
1033  }
1034  }
1035 
1036  $this->checkModelID( $rev->getContentModel() );
1037 
1038  // Find out if there was only one contributor
1039  // Only scan the last 20 revisions
1041  $res = $dbr->select(
1042  $revQuery['tables'],
1043  [ 'rev_user_text' => $revQuery['fields']['rev_user_text'] ],
1044  [
1045  'rev_page' => $title->getArticleID(),
1046  $dbr->bitAnd( 'rev_deleted', RevisionRecord::DELETED_USER ) . ' = 0'
1047  ],
1048  __METHOD__,
1049  [ 'LIMIT' => 20 ],
1050  $revQuery['joins']
1051  );
1052 
1053  if ( $res === false ) {
1054  // This page has no revisions, which is very weird
1055  return false;
1056  }
1057 
1058  $hasHistory = ( $res->numRows() > 1 );
1059  $row = $dbr->fetchObject( $res );
1060 
1061  if ( $row ) { // $row is false if the only contributor is hidden
1062  $onlyAuthor = $row->rev_user_text;
1063  // Try to find a second contributor
1064  foreach ( $res as $row ) {
1065  if ( $row->rev_user_text != $onlyAuthor ) { // T24999
1066  $onlyAuthor = false;
1067  break;
1068  }
1069  }
1070  } else {
1071  $onlyAuthor = false;
1072  }
1073 
1074  // Generate the summary with a '$1' placeholder
1075  if ( $blank ) {
1076  // The current revision is blank and the one before is also
1077  // blank. It's just not our lucky day
1078  $reason = wfMessage( 'exbeforeblank', '$1' )->inContentLanguage()->text();
1079  } else {
1080  if ( $onlyAuthor ) {
1081  $reason = wfMessage(
1082  'excontentauthor',
1083  '$1',
1084  $onlyAuthor
1085  )->inContentLanguage()->text();
1086  } else {
1087  $reason = wfMessage( 'excontent', '$1' )->inContentLanguage()->text();
1088  }
1089  }
1090 
1091  if ( $reason == '-' ) {
1092  // Allow these UI messages to be blanked out cleanly
1093  return '';
1094  }
1095 
1096  // Max content length = max comment length - length of the comment (excl. $1)
1097  $maxLength = CommentStore::COMMENT_CHARACTER_LIMIT - ( strlen( $reason ) - 2 );
1098  $text = $content ? $content->getTextForSummary( $maxLength ) : '';
1099 
1100  // Now replace the '$1' placeholder
1101  $reason = str_replace( '$1', $text, $reason );
1102 
1103  return $reason;
1104  }
1105 
1122  public function getUndoContent( $current, $undo, $undoafter, $undoIsLatest = false ) {
1123  Assert::parameterType( Revision::class . '|' . Content::class, $current, '$current' );
1124  if ( $current instanceof Content ) {
1125  Assert::parameter( $undo instanceof Content, '$undo',
1126  'Must be Content when $current is Content' );
1127  Assert::parameter( $undoafter instanceof Content, '$undoafter',
1128  'Must be Content when $current is Content' );
1129  $cur_content = $current;
1130  $undo_content = $undo;
1131  $undoafter_content = $undoafter;
1132  } else {
1133  Assert::parameter( $undo instanceof Revision, '$undo',
1134  'Must be Revision when $current is Revision' );
1135  Assert::parameter( $undoafter instanceof Revision, '$undoafter',
1136  'Must be Revision when $current is Revision' );
1137 
1138  $cur_content = $current->getContent();
1139 
1140  if ( empty( $cur_content ) ) {
1141  return false; // no page
1142  }
1143 
1144  $undo_content = $undo->getContent();
1145  $undoafter_content = $undoafter->getContent();
1146 
1147  if ( !$undo_content || !$undoafter_content ) {
1148  return false; // no content to undo
1149  }
1150 
1151  $undoIsLatest = $current->getId() === $undo->getId();
1152  }
1153 
1154  try {
1155  $this->checkModelID( $cur_content->getModel() );
1156  $this->checkModelID( $undo_content->getModel() );
1157  if ( !$undoIsLatest ) {
1158  // If we are undoing the most recent revision,
1159  // its ok to revert content model changes. However
1160  // if we are undoing a revision in the middle, then
1161  // doing that will be confusing.
1162  $this->checkModelID( $undoafter_content->getModel() );
1163  }
1164  } catch ( MWException $e ) {
1165  // If the revisions have different content models
1166  // just return false
1167  return false;
1168  }
1169 
1170  if ( $cur_content->equals( $undo_content ) ) {
1171  // No use doing a merge if it's just a straight revert.
1172  return $undoafter_content;
1173  }
1174 
1175  $undone_content = $this->merge3( $undo_content, $undoafter_content, $cur_content );
1176 
1177  return $undone_content;
1178  }
1179 
1188  public function isParserCacheSupported() {
1189  return false;
1190  }
1191 
1201  public function supportsSections() {
1202  return false;
1203  }
1204 
1211  public function supportsCategories() {
1212  return true;
1213  }
1214 
1224  public function supportsRedirects() {
1225  return false;
1226  }
1227 
1233  public function supportsDirectEditing() {
1234  return false;
1235  }
1236 
1242  public function supportsDirectApiEditing() {
1243  return $this->supportsDirectEditing();
1244  }
1245 
1256  public function getFieldsForSearchIndex( SearchEngine $engine ) {
1257  $fields = [];
1258  $fields['category'] = $engine->makeSearchFieldMapping(
1259  'category',
1261  );
1262  $fields['category']->setFlag( SearchIndexField::FLAG_CASEFOLD );
1263 
1264  $fields['external_link'] = $engine->makeSearchFieldMapping(
1265  'external_link',
1267  );
1268 
1269  $fields['outgoing_link'] = $engine->makeSearchFieldMapping(
1270  'outgoing_link',
1272  );
1273 
1274  $fields['template'] = $engine->makeSearchFieldMapping(
1275  'template',
1277  );
1278  $fields['template']->setFlag( SearchIndexField::FLAG_CASEFOLD );
1279 
1280  $fields['content_model'] = $engine->makeSearchFieldMapping(
1281  'content_model',
1283  );
1284 
1285  return $fields;
1286  }
1287 
1297  protected function addSearchField( &$fields, SearchEngine $engine, $name, $type ) {
1298  $fields[$name] = $engine->makeSearchFieldMapping( $name, $type );
1299  return $fields;
1300  }
1301 
1313  public function getDataForSearchIndex(
1314  WikiPage $page,
1315  ParserOutput $output,
1316  SearchEngine $engine
1317  ) {
1318  $fieldData = [];
1319  $content = $page->getContent();
1320 
1321  if ( $content ) {
1322  $searchDataExtractor = new ParserOutputSearchDataExtractor();
1323 
1324  $fieldData['category'] = $searchDataExtractor->getCategories( $output );
1325  $fieldData['external_link'] = $searchDataExtractor->getExternalLinks( $output );
1326  $fieldData['outgoing_link'] = $searchDataExtractor->getOutgoingLinks( $output );
1327  $fieldData['template'] = $searchDataExtractor->getTemplates( $output );
1328 
1329  $text = $content->getTextForSearchIndex();
1330 
1331  $fieldData['text'] = $text;
1332  $fieldData['source_text'] = $text;
1333  $fieldData['text_bytes'] = $content->getSize();
1334  $fieldData['content_model'] = $content->getModel();
1335  }
1336 
1337  Hooks::run( 'SearchDataForIndex', [ &$fieldData, $this, $page, $output, $engine ] );
1338  return $fieldData;
1339  }
1340 
1350  public function getParserOutputForIndexing( WikiPage $page, ParserCache $cache = null ) {
1351  // TODO: MCR: ContentHandler should be called per slot, not for the whole page.
1352  // See T190066.
1353  $parserOptions = $page->makeParserOptions( 'canonical' );
1354  if ( $cache ) {
1355  $parserOutput = $cache->get( $page, $parserOptions );
1356  }
1357 
1358  if ( empty( $parserOutput ) ) {
1359  $renderer = MediaWikiServices::getInstance()->getRevisionRenderer();
1360  $parserOutput =
1361  $renderer->getRenderedRevision(
1362  $page->getRevision()->getRevisionRecord(),
1363  $parserOptions
1364  )->getRevisionParserOutput();
1365  if ( $cache ) {
1366  $cache->save( $parserOutput, $page, $parserOptions );
1367  }
1368  }
1369  return $parserOutput;
1370  }
1371 
1402  public function getSecondaryDataUpdates(
1403  Title $title,
1404  Content $content,
1405  $role,
1406  SlotRenderingProvider $slotOutput
1407  ) {
1408  return [];
1409  }
1410 
1439  public function getDeletionUpdates( Title $title, $role ) {
1440  return [];
1441  }
1442 
1443 }
SearchIndexField\INDEX_TYPE_KEYWORD
const INDEX_TYPE_KEYWORD
KEYWORD fields are indexed without any processing, so are appropriate for e.g.
Definition: SearchIndexField.php:23
ContentHandler\getSecondaryDataUpdates
getSecondaryDataUpdates(Title $title, Content $content, $role, SlotRenderingProvider $slotOutput)
Returns a list of DeferrableUpdate objects for recording information about the given Content in some ...
Definition: ContentHandler.php:1402
ContentHandler
A content handler knows how do deal with a specific type of content on a wiki page.
Definition: ContentHandler.php:55
ContentHandler\getForModelID
static getForModelID( $modelId)
Returns the ContentHandler singleton for the given model ID.
Definition: ContentHandler.php:263
Revision\RevisionRecord
Page revision base class.
Definition: RevisionRecord.php:46
ContentHandler\getAllContentFormats
static getAllContentFormats()
Definition: ContentHandler.php:326
DifferenceEngine\getEngine
static getEngine()
Process DiffEngine config and get a sane, usable engine.
Definition: DifferenceEngine.php:1376
ParserOutput
Definition: ParserOutput.php:25
ContentHandler\supportsDirectEditing
supportsDirectEditing()
Return true if this content model supports direct editing, such as via EditPage.
Definition: ContentHandler.php:1233
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:134
$lang
if(!isset( $args[0])) $lang
Definition: testCompression.php:35
ContentHandler\getSlotDiffRendererInternal
getSlotDiffRendererInternal(IContextSource $context)
Return the SlotDiffRenderer appropriate for this content handler.
Definition: ContentHandler.php:624
ContentHandler\getActionOverrides
getActionOverrides()
Returns overrides for action handlers.
Definition: ContentHandler.php:549
ContentHandler\checkModelID
checkModelID( $model_id)
Definition: ContentHandler.php:461
ContentHandler\getAutoDeleteReason
getAutoDeleteReason(Title $title, &$hasHistory)
Auto-generates a deletion reason.
Definition: ContentHandler.php:1009
ContentHandler\unserializeContent
unserializeContent( $blob, $format=null)
Unserializes a Content object of the type supported by this ContentHandler.
ContentHandler\getPageViewLanguage
getPageViewLanguage(Title $title, Content $content=null)
Get the language in which the content of this page is written when viewed by user.
Definition: ContentHandler.php:727
WikiPage
Class representing a MediaWiki article and history.
Definition: WikiPage.php:48
ContentHandler\$mSupportedFormats
string[] $mSupportedFormats
Definition: ContentHandler.php:340
WikiPage\makeParserOptions
makeParserOptions( $context)
Get parser options suitable for rendering the primary article wikitext.
Definition: WikiPage.php:1972
WikiPage\getRevision
getRevision()
Get the latest revision.
Definition: WikiPage.php:796
wfMessage
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Definition: GlobalFunctions.php:1265
ContentHandler\getAutosummary
getAutosummary(Content $oldContent=null, Content $newContent=null, $flags=0)
Return an applicable auto-summary if one exists for the given edit.
Definition: ContentHandler.php:886
TextSlotDiffRenderer\ENGINE_EXTERNAL
const ENGINE_EXTERNAL
Use an external executable.
Definition: TextSlotDiffRenderer.php:50
ContentHandler\getDeletionUpdates
getDeletionUpdates(Title $title, $role)
Returns a list of DeferrableUpdate objects for removing information about content in some secondary d...
Definition: ContentHandler.php:1439
ContentHandler\getForTitle
static getForTitle(Title $title)
Returns the appropriate ContentHandler singleton for the given title.
Definition: ContentHandler.php:207
TextSlotDiffRenderer\ENGINE_WIKIDIFF2
const ENGINE_WIKIDIFF2
Use the wikidiff2 PHP module.
Definition: TextSlotDiffRenderer.php:44
SearchIndexField\FLAG_CASEFOLD
const FLAG_CASEFOLD
Generic field flags.
Definition: SearchIndexField.php:44
ContentHandler\getChangeTag
getChangeTag(Content $oldContent=null, Content $newContent=null, $flags=0)
Return an applicable tag if one exists for the given edit or return null.
Definition: ContentHandler.php:969
$res
$res
Definition: testCompression.php:54
ContentHandler\serializeContent
serializeContent(Content $content, $format=null)
Serializes a Content object of the type supported by this ContentHandler.
$revQuery
$revQuery
Definition: testCompression.php:53
wfDebugLog
wfDebugLog( $logGroup, $text, $dest='all', array $context=[])
Send a line to a supplementary debug log file, if configured, or main debug log if not.
Definition: GlobalFunctions.php:1007
ContentHandler\supportsSections
supportsSections()
Returns true if this content model supports sections.
Definition: ContentHandler.php:1201
Revision\SlotRenderingProvider
A lazy provider of ParserOutput objects for a revision's individual slots.
Definition: SlotRenderingProvider.php:17
ContentHandler\isSupportedFormat
isSupportedFormat( $format)
Returns true if $format is a serialization format supported by this ContentHandler,...
Definition: ContentHandler.php:510
$dbr
$dbr
Definition: testCompression.php:52
ContentHandler\createDifferenceEngine
createDifferenceEngine(IContextSource $context, $old=0, $new=0, $rcid=0, $refreshCache=false, $unhide=false)
Factory for creating an appropriate DifferenceEngine for this content model.
Definition: ContentHandler.php:580
ContentHandler\canBeUsedOn
canBeUsedOn(Title $title)
Determines whether the content type handled by this ContentHandler can be used for the main slot of t...
Definition: ContentHandler.php:761
Revision
Definition: Revision.php:40
MediaWiki\Search\ParserOutputSearchDataExtractor
Extracts data from ParserOutput for indexing in the search engine.
Definition: ParserOutputSearchDataExtractor.php:29
ContentHandler\importTransform
importTransform( $blob, $format=null)
Apply import transformation (per default, returns $blob unchanged).
Definition: ContentHandler.php:406
ContentHandler\supportsRedirects
supportsRedirects()
Returns true if this content model supports redirects.
Definition: ContentHandler.php:1224
Revision\newFromTitle
static newFromTitle(LinkTarget $linkTarget, $id=0, $flags=0)
Load either the current, or a specified, revision that's attached to a given link target.
Definition: Revision.php:138
$wgContentHandlerTextFallback
$wgContentHandlerTextFallback
How to react if a plain text version of a non-text Content object is requested using ContentHandler::...
Definition: DefaultSettings.php:8593
ContentHandler\getDefaultModelFor
static getDefaultModelFor(Title $title)
Returns the name of the default content model to be used for the page with the given title.
Definition: ContentHandler.php:188
Revision\getQueryInfo
static getQueryInfo( $options=[])
Return the tables, fields, and join conditions to be selected to create a new revision object.
Definition: Revision.php:315
MWException
MediaWiki exception.
Definition: MWException.php:26
MediaWiki\Logger\LoggerFactory
PSR-3 logger instance factory.
Definition: LoggerFactory.php:45
ContentHandler\getLanguageConverter
getLanguageConverter( $language)
Shorthand for getting a Language Converter for specific language.
Definition: ContentHandler.php:803
ContentHandler\getContentModels
static getContentModels()
Definition: ContentHandler.php:314
$blob
$blob
Definition: testCompression.php:67
ContentHandler\supportsDirectApiEditing
supportsDirectApiEditing()
Whether or not this content model supports direct editing via ApiEditPage.
Definition: ContentHandler.php:1242
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:2564
$wgLang
$wgLang
Definition: Setup.php:852
ContentHandler\getSlotDiffRendererWithOptions
getSlotDiffRendererWithOptions(IContextSource $context, $options=[])
Return the SlotDiffRenderer appropriate for this content handler.
Definition: ContentHandler.php:634
wfGetLangObj
wfGetLangObj( $langcode=false)
Return a Language object from $langcode.
Definition: GlobalFunctions.php:1215
TextSlotDiffRenderer\ENGINE_PHP
const ENGINE_PHP
Use the PHP diff implementation (DiffEngine).
Definition: TextSlotDiffRenderer.php:41
ContentHandler\merge3
merge3(Content $oldContent, Content $myContent, Content $yourContent)
Attempts to merge differences between three versions.
Definition: ContentHandler.php:794
ChangeTags\getSoftwareTags
static getSoftwareTags( $all=false)
Loads defined core tags, checks for invalid types (if not array), and filters for supported and enabl...
Definition: ChangeTags.php:63
ContentHandler\makeEmptyContent
makeEmptyContent()
Creates an empty Content object of the type supported by this ContentHandler.
$title
$title
Definition: testCompression.php:36
ContentHandler\getDataForSearchIndex
getDataForSearchIndex(WikiPage $page, ParserOutput $output, SearchEngine $engine)
Return fields to be indexed by search engine as representation of this document.
Definition: ContentHandler.php:1313
TextSlotDiffRenderer\ENGINE_WIKIDIFF2_INLINE
const ENGINE_WIKIDIFF2_INLINE
Use the wikidiff2 PHP module.
Definition: TextSlotDiffRenderer.php:47
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
ContentHandler\getSlotDiffRenderer
getSlotDiffRenderer(IContextSource $context, array $options=[])
Get an appropriate SlotDiffRenderer for this content model.
Definition: ContentHandler.php:598
MessageCache\singleton
static singleton()
Get the singleton instance of this class.
Definition: MessageCache.php:127
ContentHandler\makeContent
static makeContent( $text, Title $title=null, $modelId=null, $format=null)
Convenience function for creating a Content object from a given textual representation.
Definition: ContentHandler.php:136
ContentHandler\getPageLanguage
getPageLanguage(Title $title, Content $content=null)
Get the language in which the content of the given page is written.
Definition: ContentHandler.php:687
ContentHandler\isParserCacheSupported
isParserCacheSupported()
Returns true for content models that support caching using the ParserCache mechanism.
Definition: ContentHandler.php:1188
$content
$content
Definition: router.php:78
ContentHandler\getDefaultFormat
getDefaultFormat()
The format used for serialization/deserialization by default by this ContentHandler.
Definition: ContentHandler.php:493
ILanguageConverter
The shared interface for all language converters.
Definition: ILanguageConverter.php:28
ContentHandler\getChangeType
getChangeType(Content $oldContent=null, Content $newContent=null, $flags=0)
Return type of change if one exists for the given edit.
Definition: ContentHandler.php:819
ContentHandler\cleanupHandlersCache
static cleanupHandlersCache()
Definition: ContentHandler.php:275
ContentHandler\getLocalizedName
static getLocalizedName( $name, Language $lang=null)
Returns the localized name for a given content model.
Definition: ContentHandler.php:293
ContentHandler\getDiffEngineClass
getDiffEngineClass()
Returns the name of the diff engine to use.
Definition: ContentHandler.php:776
ContentHandler\supportsCategories
supportsCategories()
Returns true if this content model supports categories.
Definition: ContentHandler.php:1211
ContentHandler\$mModelID
string $mModelID
Definition: ContentHandler.php:335
TextContent
Content object implementation for representing flat text.
Definition: TextContent.php:37
SearchEngine
Contain a class for special pages.
Definition: SearchEngine.php:34
IContextSource
Interface for objects which can provide a MediaWiki context on request.
Definition: IContextSource.php:53
$context
$context
Definition: load.php:43
ContentHandler\exportTransform
exportTransform( $blob, $format=null)
Applies transformations on export (returns the blob unchanged per default).
Definition: ContentHandler.php:378
Content
Base interface for content objects.
Definition: Content.php:34
ContentHandler\getFieldsForSearchIndex
getFieldsForSearchIndex(SearchEngine $engine)
Get fields definition for search index.
Definition: ContentHandler.php:1256
CommentStore\COMMENT_CHARACTER_LIMIT
const COMMENT_CHARACTER_LIMIT
Maximum length of a comment in UTF-8 characters.
Definition: CommentStore.php:37
EDIT_NEW
const EDIT_NEW
Definition: Defines.php:141
SearchEngine\makeSearchFieldMapping
makeSearchFieldMapping( $name, $type)
Create a search field definition.
Definition: SearchEngine.php:744
Title
Represents a title within MediaWiki.
Definition: Title.php:42
ContentHandler\makeRedirectContent
makeRedirectContent(Title $destination, $text='')
Creates a new Content object that acts as a redirect to the given page, or null if redirects are not ...
Definition: ContentHandler.php:437
ContentHandler\checkFormat
checkFormat( $format)
Convenient for checking whether a format provided as a parameter is actually supported.
Definition: ContentHandler.php:525
ContentHandler\getContentText
static getContentText(Content $content=null)
Convenience function for getting flat text from a Content object.
Definition: ContentHandler.php:85
$cache
$cache
Definition: mcc.php:33
DifferenceEngineSlotDiffRenderer
B/C adapter for turning a DifferenceEngine into a SlotDiffRenderer.
Definition: DifferenceEngineSlotDiffRenderer.php:32
ParserCache
Definition: ParserCache.php:30
ContentHandler\addSearchField
addSearchField(&$fields, SearchEngine $engine, $name, $type)
Add new field definition to array.
Definition: ContentHandler.php:1297
NS_MEDIAWIKI
const NS_MEDIAWIKI
Definition: Defines.php:77
ContentHandler\__construct
__construct( $modelId, $formats)
Constructor, initializing the ContentHandler instance with its model ID and a list of supported forma...
Definition: ContentHandler.php:351
StubObject\unstub
static unstub(&$obj)
Unstubs an object, if it is a stub object.
Definition: StubObject.php:93
Hooks\run
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:200
ContentHandler\getUndoContent
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...
Definition: ContentHandler.php:1122
ContentHandler\getSupportedFormats
getSupportedFormats()
Returns a list of serialization formats supported by the serializeContent() and unserializeContent() ...
Definition: ContentHandler.php:478
WikiPage\getContent
getContent( $audience=RevisionRecord::FOR_PUBLIC, User $user=null)
Get the content of the current revision.
Definition: WikiPage.php:829
Language
Internationalisation code See https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation for more...
Definition: Language.php:39
ContentHandler\getModelID
getModelID()
Returns the model id that identifies the content model this ContentHandler can handle.
Definition: ContentHandler.php:449
ContentHandler\getForContent
static getForContent(Content $content)
Returns the appropriate ContentHandler singleton for the given Content object.
Definition: ContentHandler.php:228
ContentHandler\getParserOutputForIndexing
getParserOutputForIndexing(WikiPage $page, ParserCache $cache=null)
Produce page output suitable for indexing.
Definition: ContentHandler.php:1350
TextSlotDiffRenderer
Renders a slot diff by doing a text diff on the native representation.
Definition: TextSlotDiffRenderer.php:38
SearchIndexField\INDEX_TYPE_TEXT
const INDEX_TYPE_TEXT
TEXT fields are suitable for natural language and may be subject to analysis such as stemming.
Definition: SearchIndexField.php:18
$type
$type
Definition: testCompression.php:50