MediaWiki  master
ContentHandler.php
Go to the documentation of this file.
1 <?php
2 
4 
49 abstract class ContentHandler {
79  public static function getContentText( Content $content = null ) {
80  global $wgContentHandlerTextFallback;
81 
82  if ( is_null( $content ) ) {
83  return '';
84  }
85 
86  if ( $content instanceof TextContent ) {
87  return $content->getNativeData();
88  }
89 
90  wfDebugLog( 'ContentHandler', 'Accessing ' . $content->getModel() . ' content as text!' );
91 
92  if ( $wgContentHandlerTextFallback == 'fail' ) {
93  throw new MWException(
94  "Attempt to get text from Content with model " .
95  $content->getModel()
96  );
97  }
98 
99  if ( $wgContentHandlerTextFallback == 'serialize' ) {
100  return $content->serialize();
101  }
102 
103  return null;
104  }
105 
129  public static function makeContent( $text, Title $title = null,
130  $modelId = null, $format = null ) {
131  if ( is_null( $modelId ) ) {
132  if ( is_null( $title ) ) {
133  throw new MWException( "Must provide a Title object or a content model ID." );
134  }
135 
136  $modelId = $title->getContentModel();
137  }
138 
139  $handler = self::getForModelID( $modelId );
140 
141  return $handler->unserializeContent( $text, $format );
142  }
143 
178  public static function getDefaultModelFor( Title $title ) {
179  // NOTE: this method must not rely on $title->getContentModel() directly or indirectly,
180  // because it is used to initialize the mContentModel member.
181 
182  $ns = $title->getNamespace();
183 
184  $ext = false;
185  $m = null;
187 
188  // Hook can determine default model
189  if ( !Hooks::run( 'ContentHandlerDefaultModelFor', [ $title, &$model ] ) ) {
190  if ( !is_null( $model ) ) {
191  return $model;
192  }
193  }
194 
195  // Could this page contain code based on the title?
196  $isCodePage = NS_MEDIAWIKI == $ns && preg_match( '!\.(css|js|json)$!u', $title->getText(), $m );
197  if ( $isCodePage ) {
198  $ext = $m[1];
199  }
200 
201  // Is this a user subpage containing code?
202  $isCodeSubpage = NS_USER == $ns
203  && !$isCodePage
204  && preg_match( "/\\/.*\\.(js|css|json)$/", $title->getText(), $m );
205  if ( $isCodeSubpage ) {
206  $ext = $m[1];
207  }
208 
209  // Is this wikitext, according to $wgNamespaceContentModels or the DefaultModelFor hook?
210  $isWikitext = is_null( $model ) || $model == CONTENT_MODEL_WIKITEXT;
211  $isWikitext = $isWikitext && !$isCodePage && !$isCodeSubpage;
212 
213  if ( !$isWikitext ) {
214  switch ( $ext ) {
215  case 'js':
217  case 'css':
218  return CONTENT_MODEL_CSS;
219  case 'json':
220  return CONTENT_MODEL_JSON;
221  default:
222  return is_null( $model ) ? CONTENT_MODEL_TEXT : $model;
223  }
224  }
225 
226  // We established that it must be wikitext
227 
228  return CONTENT_MODEL_WIKITEXT;
229  }
230 
240  public static function getForTitle( Title $title ) {
241  $modelId = $title->getContentModel();
242 
243  return self::getForModelID( $modelId );
244  }
245 
256  public static function getForContent( Content $content ) {
257  $modelId = $content->getModel();
258 
259  return self::getForModelID( $modelId );
260  }
261 
265  protected static $handlers;
266 
293  public static function getForModelID( $modelId ) {
295 
296  if ( isset( self::$handlers[$modelId] ) ) {
297  return self::$handlers[$modelId];
298  }
299 
300  if ( empty( $wgContentHandlers[$modelId] ) ) {
301  $handler = null;
302 
303  Hooks::run( 'ContentHandlerForModelID', [ $modelId, &$handler ] );
304 
305  if ( $handler === null ) {
306  throw new MWUnknownContentModelException( $modelId );
307  }
308 
309  if ( !( $handler instanceof ContentHandler ) ) {
310  throw new MWException( "ContentHandlerForModelID must supply a ContentHandler instance" );
311  }
312  } else {
313  $classOrCallback = $wgContentHandlers[$modelId];
314 
315  if ( is_callable( $classOrCallback ) ) {
316  $handler = call_user_func( $classOrCallback, $modelId );
317  } else {
318  $handler = new $classOrCallback( $modelId );
319  }
320 
321  if ( !( $handler instanceof ContentHandler ) ) {
322  throw new MWException( "$classOrCallback from \$wgContentHandlers is not " .
323  "compatible with ContentHandler" );
324  }
325  }
326 
327  wfDebugLog( 'ContentHandler', 'Created handler for ' . $modelId
328  . ': ' . get_class( $handler ) );
329 
330  self::$handlers[$modelId] = $handler;
331 
332  return self::$handlers[$modelId];
333  }
334 
338  public static function cleanupHandlersCache() {
339  self::$handlers = [];
340  }
341 
355  public static function getLocalizedName( $name, Language $lang = null ) {
356  // Messages: content-model-wikitext, content-model-text,
357  // content-model-javascript, content-model-css
358  $key = "content-model-$name";
359 
360  $msg = wfMessage( $key );
361  if ( $lang ) {
362  $msg->inLanguage( $lang );
363  }
364 
365  return $msg->exists() ? $msg->plain() : $name;
366  }
367 
368  public static function getContentModels() {
370 
371  $models = array_keys( $wgContentHandlers );
372  Hooks::run( 'GetContentModels', [ &$models ] );
373  return $models;
374  }
375 
376  public static function getAllContentFormats() {
378 
379  $formats = [];
380 
381  foreach ( $wgContentHandlers as $model => $class ) {
382  $handler = self::getForModelID( $model );
383  $formats = array_merge( $formats, $handler->getSupportedFormats() );
384  }
385 
386  $formats = array_unique( $formats );
387 
388  return $formats;
389  }
390 
391  // ------------------------------------------------------------------------
392 
396  protected $mModelID;
397 
402 
412  public function __construct( $modelId, $formats ) {
413  $this->mModelID = $modelId;
414  $this->mSupportedFormats = $formats;
415  }
416 
427  abstract public function serializeContent( Content $content, $format = null );
428 
439  public function exportTransform( $blob, $format = null ) {
440  return $blob;
441  }
442 
453  abstract public function unserializeContent( $blob, $format = null );
454 
466  public function importTransform( $blob, $format = null ) {
467  return $blob;
468  }
469 
478  abstract public function makeEmptyContent();
479 
497  public function makeRedirectContent( Title $destination, $text = '' ) {
498  return null;
499  }
500 
509  public function getModelID() {
510  return $this->mModelID;
511  }
512 
521  protected function checkModelID( $model_id ) {
522  if ( $model_id !== $this->mModelID ) {
523  throw new MWException( "Bad content model: " .
524  "expected {$this->mModelID} " .
525  "but got $model_id." );
526  }
527  }
528 
538  public function getSupportedFormats() {
540  }
541 
553  public function getDefaultFormat() {
554  return $this->mSupportedFormats[0];
555  }
556 
570  public function isSupportedFormat( $format ) {
571  if ( !$format ) {
572  return true; // this means "use the default"
573  }
574 
575  return in_array( $format, $this->mSupportedFormats );
576  }
577 
585  protected function checkFormat( $format ) {
586  if ( !$this->isSupportedFormat( $format ) ) {
587  throw new MWException(
588  "Format $format is not supported for content model "
589  . $this->getModelID()
590  );
591  }
592  }
593 
609  public function getActionOverrides() {
610  return [];
611  }
612 
627  public function createDifferenceEngine( IContextSource $context, $old = 0, $new = 0,
628  $rcid = 0, // FIXME: Deprecated, no longer used
629  $refreshCache = false, $unhide = false
630  ) {
631  // hook: get difference engine
632  $differenceEngine = null;
633  if ( !Hooks::run( 'GetDifferenceEngine',
634  [ $context, $old, $new, $refreshCache, $unhide, &$differenceEngine ]
635  ) ) {
636  return $differenceEngine;
637  }
638  $diffEngineClass = $this->getDiffEngineClass();
639  return new $diffEngineClass( $context, $old, $new, $rcid, $refreshCache, $unhide );
640  }
641 
661  public function getPageLanguage( Title $title, Content $content = null ) {
663  $pageLang = $wgContLang;
664 
665  if ( $title->getNamespace() == NS_MEDIAWIKI ) {
666  // Parse mediawiki messages with correct target language
667  list( /* $unused */, $lang ) = MessageCache::singleton()->figureMessage( $title->getText() );
668  $pageLang = Language::factory( $lang );
669  }
670 
671  Hooks::run( 'PageContentLanguage', [ $title, &$pageLang, $wgLang ] );
672 
673  return wfGetLangObj( $pageLang );
674  }
675 
696  public function getPageViewLanguage( Title $title, Content $content = null ) {
697  $pageLang = $this->getPageLanguage( $title, $content );
698 
699  if ( $title->getNamespace() !== NS_MEDIAWIKI ) {
700  // If the user chooses a variant, the content is actually
701  // in a language whose code is the variant code.
702  $variant = $pageLang->getPreferredVariant();
703  if ( $pageLang->getCode() !== $variant ) {
704  $pageLang = Language::factory( $variant );
705  }
706  }
707 
708  return $pageLang;
709  }
710 
727  public function canBeUsedOn( Title $title ) {
728  $ok = true;
729 
730  Hooks::run( 'ContentModelCanBeUsedOn', [ $this->getModelID(), $title, &$ok ] );
731 
732  return $ok;
733  }
734 
742  protected function getDiffEngineClass() {
744  }
745 
760  public function merge3( Content $oldContent, Content $myContent, Content $yourContent ) {
761  return false;
762  }
763 
775  private function getChangeType(
776  Content $oldContent = null,
777  Content $newContent = null,
778  $flags = 0
779  ) {
780  $oldTarget = $oldContent !== null ? $oldContent->getRedirectTarget() : null;
781  $newTarget = $newContent !== null ? $newContent->getRedirectTarget() : null;
782 
783  // We check for the type of change in the given edit, and return string key accordingly
784 
785  // Blanking of a page
786  if ( $oldContent && $oldContent->getSize() > 0 &&
787  $newContent && $newContent->getSize() === 0
788  ) {
789  return 'blank';
790  }
791 
792  // Redirects
793  if ( $newTarget ) {
794  if ( !$oldTarget ) {
795  // New redirect page (by creating new page or by changing content page)
796  return 'new-redirect';
797  } elseif ( !$newTarget->equals( $oldTarget ) ||
798  $oldTarget->getFragment() !== $newTarget->getFragment()
799  ) {
800  // Redirect target changed
801  return 'changed-redirect-target';
802  }
803  } elseif ( $oldTarget ) {
804  // Changing an existing redirect into a non-redirect
805  return 'removed-redirect';
806  }
807 
808  // New page created
809  if ( $flags & EDIT_NEW && $newContent ) {
810  if ( $newContent->getSize() === 0 ) {
811  // New blank page
812  return 'newblank';
813  } else {
814  return 'newpage';
815  }
816  }
817 
818  // Removing more than 90% of the page
819  if ( $oldContent && $newContent && $oldContent->getSize() > 10 * $newContent->getSize() ) {
820  return 'replace';
821  }
822 
823  // Content model changed
824  if ( $oldContent && $newContent && $oldContent->getModel() !== $newContent->getModel() ) {
825  return 'contentmodelchange';
826  }
827 
828  return null;
829  }
830 
842  public function getAutosummary(
843  Content $oldContent = null,
844  Content $newContent = null,
845  $flags = 0
846  ) {
847  $changeType = $this->getChangeType( $oldContent, $newContent, $flags );
848 
849  // There's no applicable auto-summary for our case, so our auto-summary is empty.
850  if ( !$changeType ) {
851  return '';
852  }
853 
854  // Decide what kind of auto-summary is needed.
855  switch ( $changeType ) {
856  case 'new-redirect':
857  $newTarget = $newContent->getRedirectTarget();
858  $truncatedtext = $newContent->getTextForSummary(
859  250
860  - strlen( wfMessage( 'autoredircomment' )->inContentLanguage()->text() )
861  - strlen( $newTarget->getFullText() )
862  );
863 
864  return wfMessage( 'autoredircomment', $newTarget->getFullText() )
865  ->plaintextParams( $truncatedtext )->inContentLanguage()->text();
866  case 'changed-redirect-target':
867  $oldTarget = $oldContent->getRedirectTarget();
868  $newTarget = $newContent->getRedirectTarget();
869 
870  $truncatedtext = $newContent->getTextForSummary(
871  250
872  - strlen( wfMessage( 'autosumm-changed-redirect-target' )
873  ->inContentLanguage()->text() )
874  - strlen( $oldTarget->getFullText() )
875  - strlen( $newTarget->getFullText() )
876  );
877 
878  return wfMessage( 'autosumm-changed-redirect-target',
879  $oldTarget->getFullText(),
880  $newTarget->getFullText() )
881  ->rawParams( $truncatedtext )->inContentLanguage()->text();
882  case 'removed-redirect':
883  $oldTarget = $oldContent->getRedirectTarget();
884  $truncatedtext = $newContent->getTextForSummary(
885  250
886  - strlen( wfMessage( 'autosumm-removed-redirect' )
887  ->inContentLanguage()->text() )
888  - strlen( $oldTarget->getFullText() ) );
889 
890  return wfMessage( 'autosumm-removed-redirect', $oldTarget->getFullText() )
891  ->rawParams( $truncatedtext )->inContentLanguage()->text();
892  case 'newpage':
893  // If they're making a new article, give its text, truncated, in the summary.
894  $truncatedtext = $newContent->getTextForSummary(
895  200 - strlen( wfMessage( 'autosumm-new' )->inContentLanguage()->text() ) );
896 
897  return wfMessage( 'autosumm-new' )->rawParams( $truncatedtext )
898  ->inContentLanguage()->text();
899  case 'blank':
900  return wfMessage( 'autosumm-blank' )->inContentLanguage()->text();
901  case 'replace':
902  $truncatedtext = $newContent->getTextForSummary(
903  200 - strlen( wfMessage( 'autosumm-replace' )->inContentLanguage()->text() ) );
904 
905  return wfMessage( 'autosumm-replace' )->rawParams( $truncatedtext )
906  ->inContentLanguage()->text();
907  case 'newblank':
908  return wfMessage( 'autosumm-newblank' )->inContentLanguage()->text();
909  default:
910  return '';
911  }
912  }
913 
925  public function getChangeTag(
926  Content $oldContent = null,
927  Content $newContent = null,
928  $flags = 0
929  ) {
930  $changeType = $this->getChangeType( $oldContent, $newContent, $flags );
931 
932  // There's no applicable tag for this change.
933  if ( !$changeType ) {
934  return null;
935  }
936 
937  // Core tags use the same keys as ones returned from $this->getChangeType()
938  // but prefixed with pseudo namespace 'mw-', so we add the prefix before checking
939  // if this type of change should be tagged
940  $tag = 'mw-' . $changeType;
941 
942  // Not all change types are tagged, so we check against the list of defined tags.
943  if ( in_array( $tag, ChangeTags::getSoftwareTags() ) ) {
944  return $tag;
945  }
946 
947  return null;
948  }
949 
965  public function getAutoDeleteReason( Title $title, &$hasHistory ) {
966  $dbr = wfGetDB( DB_REPLICA );
967 
968  // Get the last revision
969  $rev = Revision::newFromTitle( $title );
970 
971  if ( is_null( $rev ) ) {
972  return false;
973  }
974 
975  // Get the article's contents
976  $content = $rev->getContent();
977  $blank = false;
978 
979  // If the page is blank, use the text from the previous revision,
980  // which can only be blank if there's a move/import/protect dummy
981  // revision involved
982  if ( !$content || $content->isEmpty() ) {
983  $prev = $rev->getPrevious();
984 
985  if ( $prev ) {
986  $rev = $prev;
987  $content = $rev->getContent();
988  $blank = true;
989  }
990  }
991 
992  $this->checkModelID( $rev->getContentModel() );
993 
994  // Find out if there was only one contributor
995  // Only scan the last 20 revisions
997  $res = $dbr->select(
998  $revQuery['tables'],
999  [ 'rev_user_text' => $revQuery['fields']['rev_user_text'] ],
1000  [
1001  'rev_page' => $title->getArticleID(),
1002  $dbr->bitAnd( 'rev_deleted', Revision::DELETED_USER ) . ' = 0'
1003  ],
1004  __METHOD__,
1005  [ 'LIMIT' => 20 ],
1006  $revQuery['joins']
1007  );
1008 
1009  if ( $res === false ) {
1010  // This page has no revisions, which is very weird
1011  return false;
1012  }
1013 
1014  $hasHistory = ( $res->numRows() > 1 );
1015  $row = $dbr->fetchObject( $res );
1016 
1017  if ( $row ) { // $row is false if the only contributor is hidden
1018  $onlyAuthor = $row->rev_user_text;
1019  // Try to find a second contributor
1020  foreach ( $res as $row ) {
1021  if ( $row->rev_user_text != $onlyAuthor ) { // T24999
1022  $onlyAuthor = false;
1023  break;
1024  }
1025  }
1026  } else {
1027  $onlyAuthor = false;
1028  }
1029 
1030  // Generate the summary with a '$1' placeholder
1031  if ( $blank ) {
1032  // The current revision is blank and the one before is also
1033  // blank. It's just not our lucky day
1034  $reason = wfMessage( 'exbeforeblank', '$1' )->inContentLanguage()->text();
1035  } else {
1036  if ( $onlyAuthor ) {
1037  $reason = wfMessage(
1038  'excontentauthor',
1039  '$1',
1040  $onlyAuthor
1041  )->inContentLanguage()->text();
1042  } else {
1043  $reason = wfMessage( 'excontent', '$1' )->inContentLanguage()->text();
1044  }
1045  }
1046 
1047  if ( $reason == '-' ) {
1048  // Allow these UI messages to be blanked out cleanly
1049  return '';
1050  }
1051 
1052  // Max content length = max comment length - length of the comment (excl. $1)
1053  $text = $content ? $content->getTextForSummary( 255 - ( strlen( $reason ) - 2 ) ) : '';
1054 
1055  // Now replace the '$1' placeholder
1056  $reason = str_replace( '$1', $text, $reason );
1057 
1058  return $reason;
1059  }
1060 
1074  public function getUndoContent( Revision $current, Revision $undo, Revision $undoafter ) {
1075  $cur_content = $current->getContent();
1076 
1077  if ( empty( $cur_content ) ) {
1078  return false; // no page
1079  }
1080 
1081  $undo_content = $undo->getContent();
1082  $undoafter_content = $undoafter->getContent();
1083 
1084  if ( !$undo_content || !$undoafter_content ) {
1085  return false; // no content to undo
1086  }
1087 
1088  try {
1089  $this->checkModelID( $cur_content->getModel() );
1090  $this->checkModelID( $undo_content->getModel() );
1091  if ( $current->getId() !== $undo->getId() ) {
1092  // If we are undoing the most recent revision,
1093  // its ok to revert content model changes. However
1094  // if we are undoing a revision in the middle, then
1095  // doing that will be confusing.
1096  $this->checkModelID( $undoafter_content->getModel() );
1097  }
1098  } catch ( MWException $e ) {
1099  // If the revisions have different content models
1100  // just return false
1101  return false;
1102  }
1103 
1104  if ( $cur_content->equals( $undo_content ) ) {
1105  // No use doing a merge if it's just a straight revert.
1106  return $undoafter_content;
1107  }
1108 
1109  $undone_content = $this->merge3( $undo_content, $undoafter_content, $cur_content );
1110 
1111  return $undone_content;
1112  }
1113 
1128  public function makeParserOptions( $context ) {
1130 
1131  if ( $context instanceof IContextSource ) {
1132  $user = $context->getUser();
1133  $lang = $context->getLanguage();
1134  } elseif ( $context instanceof User ) { // settings per user (even anons)
1135  $user = $context;
1136  $lang = null;
1137  } elseif ( $context === 'canonical' ) { // canonical settings
1138  $user = new User;
1139  $lang = $wgContLang;
1140  } else {
1141  throw new MWException( "Bad context for parser options: $context" );
1142  }
1143 
1145  }
1146 
1155  public function isParserCacheSupported() {
1156  return false;
1157  }
1158 
1168  public function supportsSections() {
1169  return false;
1170  }
1171 
1178  public function supportsCategories() {
1179  return true;
1180  }
1181 
1191  public function supportsRedirects() {
1192  return false;
1193  }
1194 
1200  public function supportsDirectEditing() {
1201  return false;
1202  }
1203 
1209  public function supportsDirectApiEditing() {
1210  return $this->supportsDirectEditing();
1211  }
1212 
1224  $fields['category'] = $engine->makeSearchFieldMapping(
1225  'category',
1227  );
1228  $fields['category']->setFlag( SearchIndexField::FLAG_CASEFOLD );
1229 
1230  $fields['external_link'] = $engine->makeSearchFieldMapping(
1231  'external_link',
1233  );
1234 
1235  $fields['outgoing_link'] = $engine->makeSearchFieldMapping(
1236  'outgoing_link',
1238  );
1239 
1240  $fields['template'] = $engine->makeSearchFieldMapping(
1241  'template',
1243  );
1244  $fields['template']->setFlag( SearchIndexField::FLAG_CASEFOLD );
1245 
1246  $fields['content_model'] = $engine->makeSearchFieldMapping(
1247  'content_model',
1249  );
1250 
1251  return $fields;
1252  }
1253 
1263  protected function addSearchField( &$fields, SearchEngine $engine, $name, $type ) {
1264  $fields[$name] = $engine->makeSearchFieldMapping( $name, $type );
1265  return $fields;
1266  }
1267 
1279  public function getDataForSearchIndex(
1280  WikiPage $page,
1283  ) {
1284  $fieldData = [];
1285  $content = $page->getContent();
1286 
1287  if ( $content ) {
1288  $searchDataExtractor = new ParserOutputSearchDataExtractor();
1289 
1290  $fieldData['category'] = $searchDataExtractor->getCategories( $output );
1291  $fieldData['external_link'] = $searchDataExtractor->getExternalLinks( $output );
1292  $fieldData['outgoing_link'] = $searchDataExtractor->getOutgoingLinks( $output );
1293  $fieldData['template'] = $searchDataExtractor->getTemplates( $output );
1294 
1295  $text = $content->getTextForSearchIndex();
1296 
1297  $fieldData['text'] = $text;
1298  $fieldData['source_text'] = $text;
1299  $fieldData['text_bytes'] = $content->getSize();
1300  $fieldData['content_model'] = $content->getModel();
1301  }
1302 
1303  Hooks::run( 'SearchDataForIndex', [ &$fieldData, $this, $page, $output, $engine ] );
1304  return $fieldData;
1305  }
1306 
1316  public function getParserOutputForIndexing( WikiPage $page, ParserCache $cache = null ) {
1317  $parserOptions = $page->makeParserOptions( 'canonical' );
1318  $revId = $page->getRevision()->getId();
1319  if ( $cache ) {
1320  $parserOutput = $cache->get( $page, $parserOptions );
1321  }
1322  if ( empty( $parserOutput ) ) {
1323  $parserOutput =
1324  $page->getContent()->getParserOutput( $page->getTitle(), $revId, $parserOptions );
1325  if ( $cache ) {
1326  $cache->save( $parserOutput, $page, $parserOptions );
1327  }
1328  }
1329  return $parserOutput;
1330  }
1331 
1332 }
merge3(Content $oldContent, Content $myContent, Content $yourContent)
Attempts to merge differences between three versions.
getAutoDeleteReason(Title $title, &$hasHistory)
Auto-generates a deletion reason.
makeParserOptions($context)
Get parser options suitable for rendering the primary article wikitext.
Definition: WikiPage.php:2000
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
Definition: deferred.txt:11
wfGetDB($db, $groups=[], $wiki=false)
Get a Database object.
supportsSections()
Returns true if this content model supports sections.
const CONTENT_MODEL_WIKITEXT
Definition: Defines.php:236
magic word the default is to use $key to get the and $key value or $key value text $key value html to format the value $key
Definition: hooks.txt:2610
getChangeTag(Content $oldContent=null, Content $newContent=null, $flags=0)
Return an applicable tag if one exists for the given edit or return null.
getAutosummary(Content $oldContent=null, Content $newContent=null, $flags=0)
Return an applicable auto-summary if one exists for the given edit.
getArticleID($flags=0)
Get the article ID for this Title from the link cache, adding it if necessary.
Definition: Title.php:3433
getText()
Get the text form (spaces not underscores) of the main part.
Definition: Title.php:929
supportsRedirects()
Returns true if this content model supports redirects.
static getAllContentFormats()
static array $handlers
A Cache of ContentHandler instances by model id.
makeSearchFieldMapping($name, $type)
Create a search field definition.
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
static getForModelID($modelId)
Returns the ContentHandler singleton for the given model ID.
static cleanupHandlersCache()
Clean up handlers cache.
div flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException'returning false will NOT prevent logging $e
Definition: hooks.txt:2195
if(!isset($args[0])) $lang
static getContentModels()
static configuration should be added through ResourceLoaderGetConfigVars instead can be used to get the real title after the basic globals have been set but before ordinary actions take place $output
Definition: hooks.txt:2252
static getDefaultModelFor(Title $title)
Returns the name of the default content model to be used for the page with the given title...
static newCanonical(User $user=null, $lang=null)
Creates a "canonical" ParserOptions object.
unserializeContent($blob, $format=null)
Unserializes a Content object of the type supported by this ContentHandler.
getModelID()
Returns the model id that identifies the content model this ContentHandler can handle.
checkModelID($model_id)
const CONTENT_MODEL_TEXT
Definition: Defines.php:239
when a variable name is used in a it is silently declared as a new local masking the global
Definition: design.txt:93
getParserOutputForIndexing(WikiPage $page, ParserCache $cache=null)
Produce page output suitable for indexing.
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 as strings Extensions should add to this list prev or next refreshes the diff cache allow viewing deleted revs & $differenceEngine
Definition: hooks.txt:1623
getPageLanguage(Title $title, Content $content=null)
Get the language in which the content of the given page is written.
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:133
const CONTENT_MODEL_JSON
Definition: Defines.php:240
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
Definition: design.txt:56
static getNamespaceContentModel($index)
Get the default content model for a namespace This does not mean that all pages in that namespace hav...
static getQueryInfo($options=[])
Return the tables, fields, and join conditions to be selected to create a new revision object...
Definition: Revision.php:492
The User object encapsulates all of the user-specific settings (user_id, name, rights, email address, options, last login time).
Definition: User.php:46
static getLocalizedName($name, Language $lang=null)
Returns the localized name for a given content model.
static getSoftwareTags($all=false)
Loads defined core tags, checks for invalid types (if not array), and filters for supported and enabl...
Definition: ChangeTags.php:56
getRevision()
Get the latest revision.
Definition: WikiPage.php:697
getContentModel($flags=0)
Get the page's content model id, see the CONTENT_MODEL_XXX constants.
Definition: Title.php:980
wfDebugLog($logGroup, $text, $dest= 'all', array $context=[])
Send a line to a supplementary debug log file, if configured, or main debug log if not...
getContent($audience=Revision::FOR_PUBLIC, User $user=null)
Get the content of the current revision.
Definition: WikiPage.php:718
const INDEX_TYPE_TEXT
Field types.
makeRedirectContent(Title $destination, $text= '')
Creates a new Content object that acts as a redirect to the given page, or null if redirects are not ...
isSupportedFormat($format)
Returns true if $format is a serialization format supported by this ContentHandler, and false otherwise.
either a unescaped string or a HtmlArmor object 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"&lt
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 as strings Extensions should add to this list prev or next $refreshCache
Definition: hooks.txt:1623
Extracts data from ParserOutput for indexing in the search engine.
getId()
Get revision ID.
Definition: Revision.php:617
getActionOverrides()
Returns overrides for action handlers.
static getForContent(Content $content)
Returns the appropriate ContentHandler singleton for the given Content object.
$res
Definition: database.txt:21
static getContentText(Content $content=null)
Convenience function for getting flat text from a Content object.
getDiffEngineClass()
Returns the name of the diff engine to use.
$cache
Definition: mcc.php:33
getTitle()
Get the title object of the article.
Definition: WikiPage.php:236
makeEmptyContent()
Creates an empty Content object of the type supported by this ContentHandler.
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:941
const FLAG_CASEFOLD
Generic field flags.
static run($event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:203
getNamespace()
Get the namespace index, i.e.
Definition: Title.php:970
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
Definition: design.txt:12
static makeContent($text, Title $title=null, $modelId=null, $format=null)
Convenience function for creating a Content object from a given textual representation.
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
Definition: hooks.txt:1799
static getForTitle(Title $title)
Returns the appropriate ContentHandler singleton for the given title.
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
Definition: distributors.txt:9
const NS_MEDIAWIKI
Definition: Defines.php:73
supportsDirectApiEditing()
Whether or not this content model supports direct editing via ApiEditPage.
the value to return A Title object or null for latest all implement SearchIndexField $engine
Definition: hooks.txt:2890
CONTENT_MODEL_JAVASCRIPT
Uploads have to be specially set up to be secure.
canBeUsedOn(Title $title)
Determines whether the content type handled by this ContentHandler can be used on the given page...
addSearchField(&$fields, SearchEngine $engine, $name, $type)
Add new field definition to array.
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 as strings Extensions should add to this list prev or next refreshes the diff cache $unhide
Definition: hooks.txt:1623
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
Definition: injection.txt:35
const DELETED_USER
Definition: Revision.php:49
string[] $mSupportedFormats
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
Definition: maintenance.txt:52
const EDIT_NEW
Definition: Defines.php:153
exportTransform($blob, $format=null)
Applies transformations on export (returns the blob unchanged per default).
$wgContentHandlers
Plugins for page content model handling.
$revQuery
serializeContent(Content $content, $format=null)
Serializes a Content object of the type supported by this ContentHandler.
getContent($audience=self::FOR_PUBLIC, User $user=null)
Fetch revision content if it's available to the specified audience.
Definition: Revision.php:895
isParserCacheSupported()
Returns true for content models that support caching using the ParserCache mechanism.
do that in ParserLimitReportFormat instead use this to modify the parameters of the image all existing parser cache entries will be invalid To avoid you ll need to handle that somehow(e.g.with the RejectParserCacheValue hook) because MediaWiki won't do it for you.&$defaults also a ContextSource after deleting those rows but within the same transaction you ll probably need to make sure the header is varied on and they can depend only on the ResourceLoaderContext $context
Definition: hooks.txt:2636
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
Definition: design.txt:56
const CONTENT_MODEL_CSS
Definition: Defines.php:238
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:302
checkFormat($format)
Convenient for checking whether a format provided as a parameter is actually supported.
const DB_REPLICA
Definition: defines.php:25
createDifferenceEngine(IContextSource $context, $old=0, $new=0, $rcid=0, $refreshCache=false, $unhide=false)
Factory for creating an appropriate DifferenceEngine for this content model.
__construct($modelId, $formats)
Constructor, initializing the ContentHandler instance with its model ID and a list of supported forma...
getSupportedFormats()
Returns a list of serialization formats supported by the serializeContent() and unserializeContent() ...
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
Definition: hooks.txt:790
getModel()
Returns the ID of the content model used by this Content object.
supportsDirectEditing()
Return true if this content model supports direct editing, such as via EditPage.
static factory($code)
Get a cached or new language object for a given language code.
Definition: Language.php:183
getDataForSearchIndex(WikiPage $page, ParserOutput $output, SearchEngine $engine)
Return fields to be indexed by search engine as representation of this document.
$ext
Definition: router.php:55
supportsCategories()
Returns true if this content model supports categories.
getChangeType(Content $oldContent=null, Content $newContent=null, $flags=0)
Return type of change if one exists for the given edit.
getFieldsForSearchIndex(SearchEngine $engine)
Get fields definition for search index.
getPageViewLanguage(Title $title, Content $content=null)
Get the language in which the content of this page is written when viewed by user.
makeParserOptions($context)
Get parser options suitable for rendering and caching the article.
getDefaultFormat()
The format used for serialization/deserialization by default by this ContentHandler.
static singleton()
Get the signleton instance of this class.
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a local account $user
Definition: hooks.txt:244
wfGetLangObj($langcode=false)
Return a Language object from $langcode.
getUndoContent(Revision $current, Revision $undo, Revision $undoafter)
Get the Content object that needs to be saved in order to undo all revisions between $undo and $undoa...
importTransform($blob, $format=null)
Apply import transformation (per default, returns $blob unchanged).