MediaWiki  master
ApiParse.php
Go to the documentation of this file.
1 <?php
27 
31 class ApiParse extends ApiBase {
32 
34  private $section = null;
35 
37  private $content = null;
38 
40  private $pstContent = null;
41 
43  private $contentIsDeleted = false, $contentIsSuppressed = false;
44 
45  private function getPoolKey(): string {
46  $poolKey = WikiMap::getCurrentWikiDbDomain() . ':ApiParse:';
47  if ( $this->getUser()->isAnon() ) {
48  $poolKey .= 'a:' . $this->getUser()->getName();
49  } else {
50  $poolKey .= 'u:' . $this->getUser()->getId();
51  }
52  return $poolKey;
53  }
54 
55  private function getContentParserOutput(
57  Title $title,
58  $revId,
59  ParserOptions $popts
60  ) {
61  $worker = new PoolCounterWorkViaCallback( 'ApiParser', $this->getPoolKey(),
62  [
63  'doWork' => function () use ( $content, $title, $revId, $popts ) {
64  return $content->getParserOutput( $title, $revId, $popts );
65  },
66  'error' => function () {
67  $this->dieWithError( 'apierror-concurrency-limit' );
68  },
69  ]
70  );
71  return $worker->execute();
72  }
73 
74  private function getPageParserOutput(
75  WikiPage $page,
76  $revId,
77  ParserOptions $popts,
78  bool $suppressCache
79  ) {
80  $worker = new PoolCounterWorkViaCallback( 'ApiParser', $this->getPoolKey(),
81  [
82  'doWork' => function () use ( $page, $revId, $popts, $suppressCache ) {
83  return $page->getParserOutput( $popts, $revId, $suppressCache );
84  },
85  'error' => function () {
86  $this->dieWithError( 'apierror-concurrency-limit' );
87  },
88  ]
89  );
90  return $worker->execute();
91  }
92 
93  public function execute() {
94  // The data is hot but user-dependent, like page views, so we set vary cookies
95  $this->getMain()->setCacheMode( 'anon-public-user-private' );
96 
97  // Get parameters
98  $params = $this->extractRequestParams();
99 
100  // No easy way to say that text and title or revid are allowed together
101  // while the rest aren't, so just do it in three calls.
102  $this->requireMaxOneParameter( $params, 'page', 'pageid', 'oldid', 'text' );
103  $this->requireMaxOneParameter( $params, 'page', 'pageid', 'oldid', 'title' );
104  $this->requireMaxOneParameter( $params, 'page', 'pageid', 'oldid', 'revid' );
105 
106  $text = $params['text'];
107  $title = $params['title'];
108  if ( $title === null ) {
109  $titleProvided = false;
110  // A title is needed for parsing, so arbitrarily choose one
111  $title = 'API';
112  } else {
113  $titleProvided = true;
114  }
115 
116  $page = $params['page'];
117  $pageid = $params['pageid'];
118  $oldid = $params['oldid'];
119 
120  $model = $params['contentmodel'];
121  $format = $params['contentformat'];
122 
123  $prop = array_flip( $params['prop'] );
124 
125  if ( isset( $params['section'] ) ) {
126  $this->section = $params['section'];
127  if ( !preg_match( '/^((T-)?\d+|new)$/', $this->section ) ) {
128  $this->dieWithError( 'apierror-invalidsection' );
129  }
130  } else {
131  $this->section = false;
132  }
133 
134  // The parser needs $wgTitle to be set, apparently the
135  // $title parameter in Parser::parse isn't enough *sigh*
136  // TODO: Does this still need $wgTitle?
137  global $wgTitle;
138 
139  $redirValues = null;
140 
141  $needContent = isset( $prop['wikitext'] ) ||
142  isset( $prop['parsetree'] ) || $params['generatexml'];
143 
144  // Return result
145  $result = $this->getResult();
146 
147  $revisionLookup = MediaWikiServices::getInstance()->getRevisionLookup();
148  if ( $oldid !== null || $pageid !== null || $page !== null ) {
149  if ( $this->section === 'new' ) {
150  $this->dieWithError( 'apierror-invalidparammix-parse-new-section', 'invalidparammix' );
151  }
152  if ( $oldid !== null ) {
153  // Don't use the parser cache
154  $rev = $revisionLookup->getRevisionById( $oldid );
155  if ( !$rev ) {
156  $this->dieWithError( [ 'apierror-nosuchrevid', $oldid ] );
157  }
158 
159  $revLinkTarget = $rev->getPageAsLinkTarget();
160  $this->checkTitleUserPermissions( $revLinkTarget, 'read' );
161 
162  if ( !$rev->audienceCan(
163  RevisionRecord::DELETED_TEXT,
164  RevisionRecord::FOR_THIS_USER,
165  $this->getUser()
166  ) ) {
167  $this->dieWithError(
168  [ 'apierror-permissiondenied', $this->msg( 'action-deletedtext' ) ]
169  );
170  }
171 
172  $titleObj = Title::newFromLinkTarget( $revLinkTarget );
173  $wgTitle = $titleObj;
174  $pageObj = WikiPage::factory( $titleObj );
175  list( $popts, $reset, $suppressCache ) = $this->makeParserOptions( $pageObj, $params );
176  $p_result = $this->getParsedContent(
177  $pageObj, $popts, $suppressCache, $pageid, $rev, $needContent
178  );
179  } else { // Not $oldid, but $pageid or $page
180  if ( $params['redirects'] ) {
181  $reqParams = [
182  'redirects' => '',
183  ];
184  $pageParams = [];
185  if ( $pageid !== null ) {
186  $reqParams['pageids'] = $pageid;
187  $pageParams['pageid'] = $pageid;
188  } else { // $page
189  $reqParams['titles'] = $page;
190  $pageParams['title'] = $page;
191  }
192  $req = new FauxRequest( $reqParams );
193  $main = new ApiMain( $req );
194  $pageSet = new ApiPageSet( $main );
195  $pageSet->execute();
196  $redirValues = $pageSet->getRedirectTitlesAsResult( $this->getResult() );
197 
198  foreach ( $pageSet->getRedirectTitles() as $title ) {
199  $pageParams = [ 'title' => $title->getFullText() ];
200  }
201  } elseif ( $pageid !== null ) {
202  $pageParams = [ 'pageid' => $pageid ];
203  } else { // $page
204  $pageParams = [ 'title' => $page ];
205  }
206 
207  $pageObj = $this->getTitleOrPageId( $pageParams, 'fromdb' );
208  $titleObj = $pageObj->getTitle();
209  if ( !$titleObj || !$titleObj->exists() ) {
210  $this->dieWithError( 'apierror-missingtitle' );
211  }
212 
213  $this->checkTitleUserPermissions( $titleObj, 'read' );
214  $wgTitle = $titleObj;
215 
216  if ( isset( $prop['revid'] ) ) {
217  $oldid = $pageObj->getLatest();
218  }
219 
220  list( $popts, $reset, $suppressCache ) = $this->makeParserOptions( $pageObj, $params );
221  $p_result = $this->getParsedContent(
222  $pageObj, $popts, $suppressCache, $pageid, null, $needContent
223  );
224  }
225  } else { // Not $oldid, $pageid, $page. Hence based on $text
226  $titleObj = Title::newFromText( $title );
227  if ( !$titleObj || $titleObj->isExternal() ) {
228  $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $title ) ] );
229  }
230  $revid = $params['revid'];
231  if ( $revid !== null ) {
232  $rev = $revisionLookup->getRevisionById( $revid );
233  if ( !$rev ) {
234  $this->dieWithError( [ 'apierror-nosuchrevid', $revid ] );
235  }
236  $pTitleObj = $titleObj;
237  $titleObj = Title::newFromLinkTarget( $rev->getPageAsLinkTarget() );
238  if ( $titleProvided ) {
239  if ( !$titleObj->equals( $pTitleObj ) ) {
240  $this->addWarning( [ 'apierror-revwrongpage', $rev->getId(),
241  wfEscapeWikiText( $pTitleObj->getPrefixedText() ) ] );
242  }
243  } else {
244  // Consider the title derived from the revid as having
245  // been provided.
246  $titleProvided = true;
247  }
248  }
249  $wgTitle = $titleObj;
250  if ( $titleObj->canExist() ) {
251  $pageObj = WikiPage::factory( $titleObj );
252  list( $popts, $reset ) = $this->makeParserOptions( $pageObj, $params );
253  } else { // A special page, presumably
254  // XXX: Why is this needed at all? Can't we just fail?
255  $pageObj = null;
256  $popts = ParserOptions::newCanonical( $this->getContext() );
257  list( $popts, $reset ) = $this->tweakParserOptions( $popts, $titleObj, $params );
258  }
259 
260  $textProvided = $text !== null;
261 
262  if ( !$textProvided ) {
263  if ( $titleProvided && ( $prop || $params['generatexml'] ) ) {
264  if ( $revid !== null ) {
265  $this->addWarning( 'apiwarn-parse-revidwithouttext' );
266  } else {
267  $this->addWarning( 'apiwarn-parse-titlewithouttext' );
268  }
269  }
270  // Prevent warning from ContentHandler::makeContent()
271  $text = '';
272  }
273 
274  // If we are parsing text, do not use the content model of the default
275  // API title, but default to wikitext to keep BC.
276  if ( $textProvided && !$titleProvided && $model === null ) {
277  $model = CONTENT_MODEL_WIKITEXT;
278  $this->addWarning( [ 'apiwarn-parse-nocontentmodel', $model ] );
279  }
280 
281  try {
282  $this->content = ContentHandler::makeContent( $text, $titleObj, $model, $format );
283  } catch ( MWContentSerializationException $ex ) {
284  $this->dieWithException( $ex, [
285  'wrap' => ApiMessage::create( 'apierror-contentserializationexception', 'parseerror' )
286  ] );
287  }
288 
289  if ( $this->section !== false ) {
290  if ( $this->section === 'new' ) {
291  // Insert the section title above the content.
292  if ( $params['sectiontitle'] !== null && $params['sectiontitle'] !== '' ) {
293  $this->content = $this->content->addSectionHeader( $params['sectiontitle'] );
294  }
295  } else {
296  $this->content = $this->getSectionContent( $this->content, $titleObj->getPrefixedText() );
297  }
298  }
299 
300  if ( $params['pst'] || $params['onlypst'] ) {
301  $this->pstContent = $this->content->preSaveTransform( $titleObj, $this->getUser(), $popts );
302  }
303  if ( $params['onlypst'] ) {
304  // Build a result and bail out
305  $result_array = [];
306  $result_array['text'] = $this->pstContent->serialize( $format );
307  $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'text';
308  if ( isset( $prop['wikitext'] ) ) {
309  $result_array['wikitext'] = $this->content->serialize( $format );
310  $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'wikitext';
311  }
312  if ( $params['summary'] !== null ||
313  ( $params['sectiontitle'] !== null && $this->section === 'new' )
314  ) {
315  $result_array['parsedsummary'] = $this->formatSummary( $titleObj, $params );
316  $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'parsedsummary';
317  }
318 
319  $result->addValue( null, $this->getModuleName(), $result_array );
320 
321  return;
322  }
323 
324  // Not cached (save or load)
325  if ( $params['pst'] ) {
326  $p_result = $this->getContentParserOutput( $this->pstContent, $titleObj, $revid, $popts );
327  } else {
328  $p_result = $this->getContentParserOutput( $this->content, $titleObj, $revid, $popts );
329  }
330  }
331 
332  $result_array = [];
333 
334  $result_array['title'] = $titleObj->getPrefixedText();
335  $result_array['pageid'] = $pageid ?: $titleObj->getArticleID();
336  if ( $this->contentIsDeleted ) {
337  $result_array['textdeleted'] = true;
338  }
339  if ( $this->contentIsSuppressed ) {
340  $result_array['textsuppressed'] = true;
341  }
342 
343  if ( isset( $params['useskin'] ) ) {
344  $factory = MediaWikiServices::getInstance()->getSkinFactory();
345  $skin = $factory->makeSkin( Skin::normalizeKey( $params['useskin'] ) );
346  } else {
347  $skin = null;
348  }
349 
350  $outputPage = null;
351  $context = null;
352  if ( $skin || isset( $prop['subtitle'] ) || isset( $prop['headhtml'] ) || isset( $prop['categorieshtml'] ) ) {
353  // Enabling the skin via 'useskin', 'subtitle', 'headhtml', or 'categorieshtml'
354  // gets OutputPage and Skin involved, which (among others) applies
355  // these hooks:
356  // - ParserOutputHooks
357  // - Hook: LanguageLinks
358  // - Hook: SkinSubPageSubtitle
359  // - Hook: OutputPageParserOutput
360  // - Hook: OutputPageMakeCategoryLinks
361  // - Hook: OutputPageBeforeHTML
362  $context = new DerivativeContext( $this->getContext() );
363  $context->setTitle( $titleObj );
364 
365  if ( $pageObj ) {
366  $context->setWikiPage( $pageObj );
367  }
368  // Some hooks only apply to pages when action=view, which this API
369  // call is simulating.
370  $context->setRequest( new FauxRequest( [ 'action' => 'view' ] ) );
371 
372  if ( $skin ) {
373  // Use the skin specified by 'useskin'
374  $context->setSkin( $skin );
375  // Context clones the skin, refetch to stay in sync. (T166022)
376  $skin = $context->getSkin();
377  } else {
378  // Make sure the context's skin refers to the context. Without this,
379  // $outputPage->getSkin()->getOutput() !== $outputPage which
380  // confuses some of the output.
381  $context->setSkin( $context->getSkin() );
382  }
383 
384  $outputPage = new OutputPage( $context );
385  // Required for subtitle to appear
386  $outputPage->setArticleFlag( true );
387 
388  $outputPage->addParserOutputMetadata( $p_result );
389  if ( $this->content ) {
390  $outputPage->addContentOverride( $titleObj, $this->content );
391  }
392  $context->setOutput( $outputPage );
393 
394  if ( $skin ) {
395  // Based on OutputPage::headElement()
396  $skin->doSetupSkinUserCss( $outputPage );
397 
398  // Based on OutputPage::output()
399  $outputPage->loadSkinModules( $skin );
400  }
401 
402  $this->getHookRunner()->onApiParseMakeOutputPage( $this, $outputPage );
403  }
404 
405  if ( $oldid !== null ) {
406  $result_array['revid'] = (int)$oldid;
407  }
408 
409  if ( $params['redirects'] && $redirValues !== null ) {
410  $result_array['redirects'] = $redirValues;
411  }
412 
413  if ( isset( $prop['text'] ) ) {
414  $result_array['text'] = $p_result->getText( [
415  'allowTOC' => !$params['disabletoc'],
416  'enableSectionEditLinks' => !$params['disableeditsection'],
417  'wrapperDivClass' => $params['wrapoutputclass'],
418  'deduplicateStyles' => !$params['disablestylededuplication'],
419  'skin' => $context ? $context->getSkin() : null,
420  ] );
421  $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'text';
422  if ( $context ) {
423  Hooks::run( 'OutputPageBeforeHTML', [ $context->getOutput(), &$result_array['text'] ] );
424  }
425  }
426 
427  if ( $params['summary'] !== null ||
428  ( $params['sectiontitle'] !== null && $this->section === 'new' )
429  ) {
430  $result_array['parsedsummary'] = $this->formatSummary( $titleObj, $params );
431  $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'parsedsummary';
432  }
433 
434  if ( isset( $prop['langlinks'] ) ) {
435  if ( $skin ) {
436  $langlinks = $outputPage->getLanguageLinks();
437  } else {
438  $langlinks = $p_result->getLanguageLinks();
439  // The deprecated 'effectivelanglinks' option depredates OutputPage
440  // support via 'useskin'. If not already applied, then run just this
441  // one hook of OutputPage::addParserOutputMetadata here.
442  if ( $params['effectivelanglinks'] ) {
443  $linkFlags = [];
444  $this->getHookRunner()->onLanguageLinks( $titleObj, $langlinks, $linkFlags );
445  }
446  }
447 
448  $result_array['langlinks'] = $this->formatLangLinks( $langlinks );
449  }
450  if ( isset( $prop['categories'] ) ) {
451  $result_array['categories'] = $this->formatCategoryLinks( $p_result->getCategories() );
452  }
453  if ( isset( $prop['categorieshtml'] ) ) {
454  $result_array['categorieshtml'] = $outputPage->getSkin()->getCategories();
455  $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'categorieshtml';
456  }
457  if ( isset( $prop['links'] ) ) {
458  $result_array['links'] = $this->formatLinks( $p_result->getLinks() );
459  }
460  if ( isset( $prop['templates'] ) ) {
461  $result_array['templates'] = $this->formatLinks( $p_result->getTemplates() );
462  }
463  if ( isset( $prop['images'] ) ) {
464  $result_array['images'] = array_keys( $p_result->getImages() );
465  }
466  if ( isset( $prop['externallinks'] ) ) {
467  $result_array['externallinks'] = array_keys( $p_result->getExternalLinks() );
468  }
469  if ( isset( $prop['sections'] ) ) {
470  $result_array['sections'] = $p_result->getSections();
471  }
472  if ( isset( $prop['parsewarnings'] ) ) {
473  $result_array['parsewarnings'] = $p_result->getWarnings();
474  }
475 
476  if ( isset( $prop['displaytitle'] ) ) {
477  $result_array['displaytitle'] = $p_result->getDisplayTitle() !== false
478  ? $p_result->getDisplayTitle() : $titleObj->getPrefixedText();
479  }
480 
481  if ( isset( $prop['subtitle'] ) ) {
482  $result_array['subtitle'] = $context->getSkin()->prepareSubtitle();
483  }
484 
485  if ( isset( $prop['headitems'] ) ) {
486  if ( $skin ) {
487  $result_array['headitems'] = $this->formatHeadItems( $outputPage->getHeadItemsArray() );
488  } else {
489  $result_array['headitems'] = $this->formatHeadItems( $p_result->getHeadItems() );
490  }
491  }
492 
493  if ( isset( $prop['headhtml'] ) ) {
494  $result_array['headhtml'] = $outputPage->headElement( $context->getSkin() );
495  $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'headhtml';
496  }
497 
498  if ( isset( $prop['modules'] ) ) {
499  if ( $skin ) {
500  $result_array['modules'] = $outputPage->getModules();
501  // Deprecated since 1.32 (T188689)
502  $result_array['modulescripts'] = [];
503  $result_array['modulestyles'] = $outputPage->getModuleStyles();
504  } else {
505  $result_array['modules'] = array_values( array_unique( $p_result->getModules() ) );
506  // Deprecated since 1.32 (T188689)
507  $result_array['modulescripts'] = [];
508  $result_array['modulestyles'] = array_values( array_unique( $p_result->getModuleStyles() ) );
509  }
510  }
511 
512  if ( isset( $prop['jsconfigvars'] ) ) {
513  $jsconfigvars = $skin ? $outputPage->getJsConfigVars() : $p_result->getJsConfigVars();
514  $result_array['jsconfigvars'] = ApiResult::addMetadataToResultVars( $jsconfigvars );
515  }
516 
517  if ( isset( $prop['encodedjsconfigvars'] ) ) {
518  $jsconfigvars = $skin ? $outputPage->getJsConfigVars() : $p_result->getJsConfigVars();
519  $result_array['encodedjsconfigvars'] = FormatJson::encode(
520  $jsconfigvars,
521  false,
523  );
524  $result_array[ApiResult::META_SUBELEMENTS][] = 'encodedjsconfigvars';
525  }
526 
527  if ( isset( $prop['modules'] ) &&
528  !isset( $prop['jsconfigvars'] ) && !isset( $prop['encodedjsconfigvars'] ) ) {
529  $this->addWarning( 'apiwarn-moduleswithoutvars' );
530  }
531 
532  if ( isset( $prop['indicators'] ) ) {
533  if ( $skin ) {
534  $result_array['indicators'] = (array)$outputPage->getIndicators();
535  } else {
536  $result_array['indicators'] = (array)$p_result->getIndicators();
537  }
538  ApiResult::setArrayType( $result_array['indicators'], 'BCkvp', 'name' );
539  }
540 
541  if ( isset( $prop['iwlinks'] ) ) {
542  $result_array['iwlinks'] = $this->formatIWLinks( $p_result->getInterwikiLinks() );
543  }
544 
545  if ( isset( $prop['wikitext'] ) ) {
546  $result_array['wikitext'] = $this->content->serialize( $format );
547  $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'wikitext';
548  if ( $this->pstContent !== null ) {
549  $result_array['psttext'] = $this->pstContent->serialize( $format );
550  $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'psttext';
551  }
552  }
553  if ( isset( $prop['properties'] ) ) {
554  $result_array['properties'] = (array)$p_result->getProperties();
555  ApiResult::setArrayType( $result_array['properties'], 'BCkvp', 'name' );
556  }
557 
558  if ( isset( $prop['limitreportdata'] ) ) {
559  $result_array['limitreportdata'] =
560  $this->formatLimitReportData( $p_result->getLimitReportData() );
561  }
562  if ( isset( $prop['limitreporthtml'] ) ) {
563  $result_array['limitreporthtml'] = EditPage::getPreviewLimitReport( $p_result );
564  $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'limitreporthtml';
565  }
566 
567  if ( isset( $prop['parsetree'] ) || $params['generatexml'] ) {
568  if ( $this->content->getModel() != CONTENT_MODEL_WIKITEXT ) {
569  $this->dieWithError( 'apierror-parsetree-notwikitext', 'notwikitext' );
570  }
571 
572  $parser = MediaWikiServices::getInstance()->getParser();
573  $parser->startExternalParse( $titleObj, $popts, Parser::OT_PREPROCESS );
574  // @phan-suppress-next-line PhanUndeclaredMethod
575  $xml = $parser->preprocessToDom( $this->content->getText() )->__toString();
576  $result_array['parsetree'] = $xml;
577  $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'parsetree';
578  }
579 
580  $result_mapping = [
581  'redirects' => 'r',
582  'langlinks' => 'll',
583  'categories' => 'cl',
584  'links' => 'pl',
585  'templates' => 'tl',
586  'images' => 'img',
587  'externallinks' => 'el',
588  'iwlinks' => 'iw',
589  'sections' => 's',
590  'headitems' => 'hi',
591  'modules' => 'm',
592  'indicators' => 'ind',
593  'modulescripts' => 'm',
594  'modulestyles' => 'm',
595  'properties' => 'pp',
596  'limitreportdata' => 'lr',
597  'parsewarnings' => 'pw'
598  ];
599  $this->setIndexedTagNames( $result_array, $result_mapping );
600  $result->addValue( null, $this->getModuleName(), $result_array );
601  }
602 
611  private function makeParserOptions( WikiPage $pageObj, array $params ) {
612  $popts = $pageObj->makeParserOptions( $this->getContext() );
613  return $this->tweakParserOptions( $popts, $pageObj->getTitle(), $params );
614  }
615 
625  private function tweakParserOptions( ParserOptions $popts, Title $title, array $params ) {
626  $popts->enableLimitReport( !$params['disablepp'] && !$params['disablelimitreport'] );
627  $popts->setIsPreview( $params['preview'] || $params['sectionpreview'] );
628  $popts->setIsSectionPreview( $params['sectionpreview'] );
629 
630  if ( $params['wrapoutputclass'] !== '' ) {
631  $popts->setWrapOutputClass( $params['wrapoutputclass'] );
632  }
633 
634  $reset = null;
635  $suppressCache = false;
636  $this->getHookRunner()->onApiMakeParserOptions( $popts, $title,
637  $params, $this, $reset, $suppressCache );
638 
639  return [ $popts, $reset, $suppressCache ];
640  }
641 
651  private function getParsedContent(
652  WikiPage $page, $popts, $suppressCache, $pageId, $rev, $getContent
653  ) {
654  $revId = $rev ? $rev->getId() : null;
655  $isDeleted = $rev && $rev->isDeleted( RevisionRecord::DELETED_TEXT );
656 
657  if ( $getContent || $this->section !== false || $isDeleted ) {
658  if ( $rev ) {
659  $this->content = $rev->getContent(
660  SlotRecord::MAIN, RevisionRecord::FOR_THIS_USER, $this->getUser()
661  );
662  if ( !$this->content ) {
663  $this->dieWithError( [ 'apierror-missingcontent-revid', $revId ] );
664  }
665  } else {
666  $this->content = $page->getContent( RevisionRecord::FOR_THIS_USER, $this->getUser() );
667  if ( !$this->content ) {
668  $this->dieWithError( [ 'apierror-missingcontent-pageid', $page->getId() ] );
669  }
670  }
671  $this->contentIsDeleted = $isDeleted;
672  $this->contentIsSuppressed = $rev &&
673  $rev->isDeleted( RevisionRecord::DELETED_TEXT | RevisionRecord::DELETED_RESTRICTED );
674  }
675 
676  if ( $this->section !== false ) {
677  $this->content = $this->getSectionContent(
678  $this->content,
679  $pageId === null ? $page->getTitle()->getPrefixedText() : $this->msg( 'pageid', $pageId )
680  );
681  return $this->getContentParserOutput( $this->content, $page->getTitle(), $revId, $popts );
682  }
683 
684  if ( $isDeleted ) {
685  // getParserOutput can't do revdeled revisions
686 
687  $pout = $this->getContentParserOutput( $this->content, $page->getTitle(), $revId, $popts );
688  } else {
689  // getParserOutput will save to Parser cache if able
690  $pout = $this->getPageParserOutput( $page, $revId, $popts, $suppressCache );
691  }
692  if ( !$pout ) {
693  // @codeCoverageIgnoreStart
694  $this->dieWithError( [ 'apierror-nosuchrevid', $revId ?: $page->getLatest() ] );
695  // @codeCoverageIgnoreEnd
696  }
697 
698  return $pout;
699  }
700 
708  private function getSectionContent( Content $content, $what ) {
709  // Not cached (save or load)
710  $section = $content->getSection( $this->section );
711  if ( $section === false ) {
712  $this->dieWithError( [ 'apierror-nosuchsection-what', $this->section, $what ], 'nosuchsection' );
713  }
714  if ( $section === null ) {
715  $this->dieWithError( [ 'apierror-sectionsnotsupported-what', $what ], 'nosuchsection' );
716  $section = false;
717  }
718 
719  return $section;
720  }
721 
729  private function formatSummary( $title, $params ) {
730  $summary = $params['summary'] ?? '';
731  $sectionTitle = $params['sectiontitle'] ?? '';
732 
733  if ( $this->section === 'new' && ( $sectionTitle === '' || $summary === '' ) ) {
734  if ( $sectionTitle !== '' ) {
735  $summary = $params['sectiontitle'];
736  }
737  if ( $summary !== '' ) {
738  $summary = wfMessage( 'newsectionsummary' )
739  ->rawParams( MediaWikiServices::getInstance()->getParser()
740  ->stripSectionName( $summary ) )
741  ->inContentLanguage()->text();
742  }
743  }
744  return Linker::formatComment( $summary, $title, $this->section === 'new' );
745  }
746 
747  private function formatLangLinks( $links ) {
748  $languageNameUtils = MediaWikiServices::getInstance()->getLanguageNameUtils();
749  $result = [];
750  foreach ( $links as $link ) {
751  $entry = [];
752  $bits = explode( ':', $link, 2 );
753  $title = Title::newFromText( $link );
754 
755  $entry['lang'] = $bits[0];
756  if ( $title ) {
757  $entry['url'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
758  // localised language name in 'uselang' language
759  $entry['langname'] = $languageNameUtils->getLanguageName(
760  $title->getInterwiki(),
761  $this->getLanguage()->getCode()
762  );
763 
764  // native language name
765  $entry['autonym'] = $languageNameUtils->getLanguageName( $title->getInterwiki() );
766  }
767  ApiResult::setContentValue( $entry, 'title', $bits[1] );
768  $result[] = $entry;
769  }
770 
771  return $result;
772  }
773 
774  private function formatCategoryLinks( $links ) {
775  $result = [];
776 
777  if ( !$links ) {
778  return $result;
779  }
780 
781  // Fetch hiddencat property
782  $linkBatchFactory = MediaWikiServices::getInstance()->getLinkBatchFactory();
783  $lb = $linkBatchFactory->newLinkBatch();
784  $lb->setArray( [ NS_CATEGORY => $links ] );
785  $db = $this->getDB();
786  $res = $db->select( [ 'page', 'page_props' ],
787  [ 'page_title', 'pp_propname' ],
788  $lb->constructSet( 'page', $db ),
789  __METHOD__,
790  [],
791  [ 'page_props' => [
792  'LEFT JOIN', [ 'pp_propname' => 'hiddencat', 'pp_page = page_id' ]
793  ] ]
794  );
795  $hiddencats = [];
796  foreach ( $res as $row ) {
797  $hiddencats[$row->page_title] = isset( $row->pp_propname );
798  }
799 
800  $linkCache = MediaWikiServices::getInstance()->getLinkCache();
801 
802  foreach ( $links as $link => $sortkey ) {
803  $entry = [];
804  $entry['sortkey'] = $sortkey;
805  // array keys will cast numeric category names to ints, so cast back to string
806  ApiResult::setContentValue( $entry, 'category', (string)$link );
807  if ( !isset( $hiddencats[$link] ) ) {
808  $entry['missing'] = true;
809 
810  // We already know the link doesn't exist in the database, so
811  // tell LinkCache that before calling $title->isKnown().
812  $title = Title::makeTitle( NS_CATEGORY, $link );
813  $linkCache->addBadLinkObj( $title );
814  if ( $title->isKnown() ) {
815  $entry['known'] = true;
816  }
817  } elseif ( $hiddencats[$link] ) {
818  $entry['hidden'] = true;
819  }
820  $result[] = $entry;
821  }
822 
823  return $result;
824  }
825 
826  private function formatLinks( $links ) {
827  $result = [];
828  foreach ( $links as $ns => $nslinks ) {
829  foreach ( $nslinks as $title => $id ) {
830  $entry = [];
831  $entry['ns'] = $ns;
832  ApiResult::setContentValue( $entry, 'title', Title::makeTitle( $ns, $title )->getFullText() );
833  $entry['exists'] = $id != 0;
834  $result[] = $entry;
835  }
836  }
837 
838  return $result;
839  }
840 
841  private function formatIWLinks( $iw ) {
842  $result = [];
843  foreach ( $iw as $prefix => $titles ) {
844  foreach ( array_keys( $titles ) as $title ) {
845  $entry = [];
846  $entry['prefix'] = $prefix;
847 
848  $title = Title::newFromText( "{$prefix}:{$title}" );
849  if ( $title ) {
850  $entry['url'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
851  }
852 
853  ApiResult::setContentValue( $entry, 'title', $title->getFullText() );
854  $result[] = $entry;
855  }
856  }
857 
858  return $result;
859  }
860 
861  private function formatHeadItems( $headItems ) {
862  $result = [];
863  foreach ( $headItems as $tag => $content ) {
864  $entry = [];
865  $entry['tag'] = $tag;
866  ApiResult::setContentValue( $entry, 'content', $content );
867  $result[] = $entry;
868  }
869 
870  return $result;
871  }
872 
873  private function formatLimitReportData( $limitReportData ) {
874  $result = [];
875 
876  foreach ( $limitReportData as $name => $value ) {
877  $entry = [];
878  $entry['name'] = $name;
879  if ( !is_array( $value ) ) {
880  $value = [ $value ];
881  }
882  ApiResult::setIndexedTagNameRecursive( $value, 'param' );
883  $entry = array_merge( $entry, $value );
884  $result[] = $entry;
885  }
886 
887  return $result;
888  }
889 
890  private function setIndexedTagNames( &$array, $mapping ) {
891  foreach ( $mapping as $key => $name ) {
892  if ( isset( $array[$key] ) ) {
893  ApiResult::setIndexedTagName( $array[$key], $name );
894  }
895  }
896  }
897 
898  public function getAllowedParams() {
899  $skinFactory = MediaWikiServices::getInstance()->getSkinFactory();
900 
901  return [
902  'title' => null,
903  'text' => [
904  ApiBase::PARAM_TYPE => 'text',
905  ],
906  'revid' => [
907  ApiBase::PARAM_TYPE => 'integer',
908  ],
909  'summary' => null,
910  'page' => null,
911  'pageid' => [
912  ApiBase::PARAM_TYPE => 'integer',
913  ],
914  'redirects' => false,
915  'oldid' => [
916  ApiBase::PARAM_TYPE => 'integer',
917  ],
918  'prop' => [
919  ApiBase::PARAM_DFLT => 'text|langlinks|categories|links|templates|' .
920  'images|externallinks|sections|revid|displaytitle|iwlinks|' .
921  'properties|parsewarnings',
922  ApiBase::PARAM_ISMULTI => true,
924  'text',
925  'langlinks',
926  'categories',
927  'categorieshtml',
928  'links',
929  'templates',
930  'images',
931  'externallinks',
932  'sections',
933  'revid',
934  'displaytitle',
935  'subtitle',
936  'headhtml',
937  'modules',
938  'jsconfigvars',
939  'encodedjsconfigvars',
940  'indicators',
941  'iwlinks',
942  'wikitext',
943  'properties',
944  'limitreportdata',
945  'limitreporthtml',
946  'parsetree',
947  'parsewarnings',
948  'headitems',
949  ],
951  'parsetree' => [ 'apihelp-parse-paramvalue-prop-parsetree', CONTENT_MODEL_WIKITEXT ],
952  ],
954  'headitems' => 'apiwarn-deprecation-parse-headitems',
955  ],
956  ],
957  'wrapoutputclass' => 'mw-parser-output',
958  'pst' => false,
959  'onlypst' => false,
960  'effectivelanglinks' => [
961  ApiBase::PARAM_DFLT => false,
963  ],
964  'section' => null,
965  'sectiontitle' => [
966  ApiBase::PARAM_TYPE => 'string',
967  ],
968  'disablepp' => [
969  ApiBase::PARAM_DFLT => false,
971  ],
972  'disablelimitreport' => false,
973  'disableeditsection' => false,
974  'disablestylededuplication' => false,
975  'generatexml' => [
976  ApiBase::PARAM_DFLT => false,
978  'apihelp-parse-param-generatexml', CONTENT_MODEL_WIKITEXT
979  ],
981  ],
982  'preview' => false,
983  'sectionpreview' => false,
984  'disabletoc' => false,
985  'useskin' => [
986  ApiBase::PARAM_TYPE => array_keys( $skinFactory->getAllowedSkins() ),
987  ],
988  'contentformat' => [
989  ApiBase::PARAM_TYPE => $this->getContentHandlerFactory()->getAllContentFormats(),
990  ],
991  'contentmodel' => [
992  ApiBase::PARAM_TYPE => $this->getContentHandlerFactory()->getContentModels(),
993  ],
994  ];
995  }
996 
997  protected function getExamplesMessages() {
998  return [
999  'action=parse&page=Project:Sandbox'
1000  => 'apihelp-parse-example-page',
1001  'action=parse&text={{Project:Sandbox}}&contentmodel=wikitext'
1002  => 'apihelp-parse-example-text',
1003  'action=parse&text={{PAGENAME}}&title=Test'
1004  => 'apihelp-parse-example-texttitle',
1005  'action=parse&summary=Some+[[link]]&prop='
1006  => 'apihelp-parse-example-summary',
1007  ];
1008  }
1009 
1010  public function getHelpUrls() {
1011  return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Parsing_wikitext#parse';
1012  }
1013 
1015  return MediaWikiServices::getInstance()->getContentHandlerFactory();
1016  }
1017 }
ParserOptions
Set options of the Parser.
Definition: ParserOptions.php:44
ApiMain
This is the main API class, used for both external and internal processing.
Definition: ApiMain.php:48
ContextSource\$context
IContextSource $context
Definition: ContextSource.php:38
ApiParse\formatIWLinks
formatIWLinks( $iw)
Definition: ApiParse.php:841
FauxRequest
WebRequest clone which takes values from a provided array.
Definition: FauxRequest.php:35
Title\newFromText
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:361
ContextSource\getContext
getContext()
Get the base IContextSource object.
Definition: ContextSource.php:46
ApiParse\getParsedContent
getParsedContent(WikiPage $page, $popts, $suppressCache, $pageId, $rev, $getContent)
Definition: ApiParse.php:651
Revision\RevisionRecord
Page revision base class.
Definition: RevisionRecord.php:45
ApiBase\addWarning
addWarning( $msg, $code=null, $data=null)
Add a warning for this module.
Definition: ApiBase.php:1289
WikiMap\getCurrentWikiDbDomain
static getCurrentWikiDbDomain()
Definition: WikiMap.php:293
IContextSource\getSkin
getSkin()
ApiParse\formatLangLinks
formatLangLinks( $links)
Definition: ApiParse.php:747
WikiPage\getParserOutput
getParserOutput(ParserOptions $parserOptions, $oldid=null, $noCache=false)
Get a ParserOutput for the given ParserOptions and revision ID.
Definition: WikiPage.php:1231
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:166
ApiBase\dieWithError
dieWithError( $msg, $code=null, $data=null, $httpCode=null)
Abort execution with an error.
Definition: ApiBase.php:1370
ApiBase\PARAM_HELP_MSG
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:102
ApiParse\tweakParserOptions
tweakParserOptions(ParserOptions $popts, Title $title, array $params)
Tweaks a ParserOptions object.
Definition: ApiParse.php:625
ApiResult\META_BC_SUBELEMENTS
const META_BC_SUBELEMENTS
Key for the 'BC subelements' metadata item.
Definition: ApiResult.php:143
ApiBase\getTitleOrPageId
getTitleOrPageId( $params, $load=false)
Get a WikiPage object from a title or pageid param, if possible.
Definition: ApiBase.php:975
ApiBase\PARAM_TYPE
const PARAM_TYPE
Definition: ApiBase.php:69
ApiParse\formatLinks
formatLinks( $links)
Definition: ApiParse.php:826
ParserOptions\setIsPreview
setIsPreview( $x)
Parsing the page for a "preview" operation?
Definition: ParserOptions.php:583
ApiBase\getResult
getResult()
Get the result object.
Definition: ApiBase.php:558
ParserOptions\setIsSectionPreview
setIsSectionPreview( $x)
Parsing the page for a "preview" operation on a single section?
Definition: ParserOptions.php:600
WikiPage
Class representing a MediaWiki article and history.
Definition: WikiPage.php:55
WikiPage\makeParserOptions
makeParserOptions( $context)
Get parser options suitable for rendering the primary article wikitext.
Definition: WikiPage.php:2106
ParserOptions\setWrapOutputClass
setWrapOutputClass( $className)
CSS class to use to wrap output from Parser::parse()
Definition: ParserOptions.php:787
wfMessage
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Definition: GlobalFunctions.php:1230
ApiBase\getDB
getDB()
Gets a default replica DB connection object Stable to override.
Definition: ApiBase.php:587
PoolCounterWorkViaCallback
Convenience class for dealing with PoolCounters using callbacks.
Definition: PoolCounterWorkViaCallback.php:31
ApiParse\$contentIsDeleted
bool $contentIsDeleted
Definition: ApiParse.php:43
$res
$res
Definition: testCompression.php:57
ContextSource\getUser
getUser()
Stable to override.
Definition: ContextSource.php:135
ApiBase\PARAM_DEPRECATED_VALUES
const PARAM_DEPRECATED_VALUES
Definition: ApiBase.php:81
FormatJson\ALL_OK
const ALL_OK
Skip escaping as many characters as reasonably possible.
Definition: FormatJson.php:55
ApiPageSet
This class contains a list of pages that the client has requested.
Definition: ApiPageSet.php:42
ApiBase
This abstract class implements many basic API functions, and is the base of all API classes.
Definition: ApiBase.php:52
ApiParse\getPageParserOutput
getPageParserOutput(WikiPage $page, $revId, ParserOptions $popts, bool $suppressCache)
Definition: ApiParse.php:74
ApiParse\getContentHandlerFactory
getContentHandlerFactory()
Definition: ApiParse.php:1014
ApiResult\setContentValue
static setContentValue(array &$arr, $name, $value, $flags=0)
Add an output value to the array by name and mark as META_CONTENT.
Definition: ApiResult.php:464
ApiBase\PARAM_DEPRECATED
const PARAM_DEPRECATED
Definition: ApiBase.php:74
DerivativeContext
An IContextSource implementation which will inherit context from another source but allow individual ...
Definition: DerivativeContext.php:32
ApiParse
Definition: ApiParse.php:31
FormatJson\encode
static encode( $value, $pretty=false, $escaping=0)
Returns the JSON representation of a value.
Definition: FormatJson.php:115
ApiParse\$pstContent
Content $pstContent
Definition: ApiParse.php:40
ApiResult\setArrayType
static setArrayType(array &$arr, $type, $kvpKeyName=null)
Set the array data type.
Definition: ApiResult.php:713
ApiParse\getHelpUrls
getHelpUrls()
Return links to more detailed help pages about the module.
Definition: ApiParse.php:1010
WikiPage\factory
static factory(Title $title)
Create a WikiPage object of the appropriate class for the given title.
Definition: WikiPage.php:170
Content\getSection
getSection( $sectionId)
Returns the section with the given ID.
ApiResult\addMetadataToResultVars
static addMetadataToResultVars( $vars, $forceHash=true)
Add the correct metadata to an array of vars we want to export through the API.
Definition: ApiResult.php:1134
Skin\normalizeKey
static normalizeKey( $key)
Normalize a skin preference value to a form that can be loaded.
Definition: Skin.php:115
ApiParse\getAllowedParams
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
Definition: ApiParse.php:898
PoolCounterWork\execute
execute( $skipcache=false)
Get the result of the work (whatever it is), or the result of the error() function.
Definition: PoolCounterWork.php:127
ApiResult\META_SUBELEMENTS
const META_SUBELEMENTS
Key for the 'subelements' metadata item.
Definition: ApiResult.php:78
WikiPage\getId
getId()
Definition: WikiPage.php:567
ApiParse\formatLimitReportData
formatLimitReportData( $limitReportData)
Definition: ApiParse.php:873
EditPage\getPreviewLimitReport
static getPreviewLimitReport(ParserOutput $output=null)
Get the Limit report for page previews.
Definition: EditPage.php:3845
WikiPage\getTitle
getTitle()
Get the title object of the article.
Definition: WikiPage.php:295
MWContentSerializationException
Exception representing a failure to serialize or unserialize a content object.
Definition: MWContentSerializationException.php:8
ApiParse\getContentParserOutput
getContentParserOutput(Content $content, Title $title, $revId, ParserOptions $popts)
Definition: ApiParse.php:55
ApiBase\extractRequestParams
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:706
$title
$title
Definition: testCompression.php:38
Title\makeTitle
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:624
WikiPage\getLatest
getLatest()
Get the page_latest field.
Definition: WikiPage.php:691
ApiMessage\create
static create( $msg, $code=null, array $data=null)
Create an IApiMessage for the message.
Definition: ApiMessage.php:43
ApiParse\formatSummary
formatSummary( $title, $params)
This mimicks the behavior of EditPage in formatting a summary.
Definition: ApiParse.php:729
OutputPage
This is one of the Core classes and should be read at least once by any new developers.
Definition: OutputPage.php:47
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:142
$wgTitle
$wgTitle
Definition: Setup.php:794
PROTO_CURRENT
const PROTO_CURRENT
Definition: Defines.php:205
ApiParse\formatCategoryLinks
formatCategoryLinks( $links)
Definition: ApiParse.php:774
ContextSource\msg
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
Definition: ContextSource.php:195
ApiResult\setIndexedTagName
static setIndexedTagName(array &$arr, $tag)
Set the tag name for numeric-keyed values in XML format.
Definition: ApiResult.php:601
ApiBase\requireMaxOneParameter
requireMaxOneParameter( $params,... $required)
Die if more than one of a certain set of parameters is set and not false.
Definition: ApiBase.php:878
MediaWiki\Content\IContentHandlerFactory
Definition: IContentHandlerFactory.php:10
ApiParse\setIndexedTagNames
setIndexedTagNames(&$array, $mapping)
Definition: ApiParse.php:890
ParserOptions\newCanonical
static newCanonical( $context=null, $userLang=null)
Creates a "canonical" ParserOptions object.
Definition: ParserOptions.php:1133
wfEscapeWikiText
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
Definition: GlobalFunctions.php:1504
CONTENT_MODEL_WIKITEXT
const CONTENT_MODEL_WIKITEXT
Definition: Defines.php:218
Title\newFromLinkTarget
static newFromLinkTarget(LinkTarget $linkTarget, $forceClone='')
Returns a Title given a LinkTarget.
Definition: Title.php:289
Parser\OT_PREPROCESS
const OT_PREPROCESS
Definition: Parser.php:125
Linker\formatComment
static formatComment( $comment, $title=null, $local=false, $wikiId=null)
This function is called by all recent changes variants, by the page history, and by the user contribu...
Definition: Linker.php:1198
Content
Base interface for content objects.
Definition: Content.php:35
ApiParse\$section
string false null $section
Definition: ApiParse.php:34
ParserOptions\enableLimitReport
enableLimitReport( $x=true)
Enable limit report in an HTML comment on output.
Definition: ParserOptions.php:462
Title
Represents a title within MediaWiki.
Definition: Title.php:46
ApiParse\getPoolKey
getPoolKey()
Definition: ApiParse.php:45
ApiBase\PARAM_DFLT
const PARAM_DFLT
Definition: ApiBase.php:67
ApiParse\getExamplesMessages
getExamplesMessages()
Returns usage examples for this module.
Definition: ApiParse.php:997
ApiBase\dieWithException
dieWithException(Throwable $exception, array $options=[])
Abort execution with an error derived from a throwable.
Definition: ApiBase.php:1382
ApiBase\getModuleName
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:437
ApiBase\PARAM_ISMULTI
const PARAM_ISMULTI
Definition: ApiBase.php:68
NS_CATEGORY
const NS_CATEGORY
Definition: Defines.php:77
ApiParse\getSectionContent
getSectionContent(Content $content, $what)
Extract the requested section from the given Content.
Definition: ApiParse.php:708
ApiBase\getMain
getMain()
Get the main module.
Definition: ApiBase.php:453
ApiBase\checkTitleUserPermissions
checkTitleUserPermissions(LinkTarget $linkTarget, $actions, array $options=[])
Helper function for permission-denied errors.
Definition: ApiBase.php:1497
Content\getParserOutput
getParserOutput(Title $title, $revId=null, ParserOptions $options=null, $generateHtml=true)
Parse the Content object and generate a ParserOutput from the result.
ApiParse\formatHeadItems
formatHeadItems( $headItems)
Definition: ApiParse.php:861
ApiResult\setIndexedTagNameRecursive
static setIndexedTagNameRecursive(array &$arr, $tag)
Set indexed tag name on $arr and all subarrays.
Definition: ApiResult.php:626
ApiBase\PARAM_HELP_MSG_PER_VALUE
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, this is an array mapping those values to $msg...
Definition: ApiBase.php:135
ApiBase\getHookRunner
getHookRunner()
Get an ApiHookRunner for running core API hooks.
Definition: ApiBase.php:652
Hooks\run
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:134
ApiParse\makeParserOptions
makeParserOptions(WikiPage $pageObj, array $params)
Constructs a ParserOptions object.
Definition: ApiParse.php:611
IContextSource\getOutput
getOutput()
WikiPage\getContent
getContent( $audience=RevisionRecord::FOR_PUBLIC, User $user=null)
Get the content of the current revision.
Definition: WikiPage.php:810
ApiParse\$content
Content $content
Definition: ApiParse.php:37
Revision\SlotRecord
Value object representing a content slot associated with a page revision.
Definition: SlotRecord.php:40
wfExpandUrl
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
Definition: GlobalFunctions.php:494
ApiParse\$contentIsSuppressed
bool $contentIsSuppressed
Definition: ApiParse.php:43
ApiParse\execute
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
Definition: ApiParse.php:93