Merge "Lower timeout of upload stash -> image scaler requests"
[lhc/web/wiklou.git] / includes / api / ApiParse.php
1 <?php
2 /**
3 * Created on Dec 01, 2007
4 *
5 * Copyright © 2007 Yuri Astrakhan "<Firstname><Lastname>@gmail.com"
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * http://www.gnu.org/copyleft/gpl.html
21 *
22 * @file
23 */
24
25 /**
26 * @ingroup API
27 */
28 class ApiParse extends ApiBase {
29
30 /** @var string $section */
31 private $section = null;
32
33 /** @var Content $content */
34 private $content = null;
35
36 /** @var Content $pstContent */
37 private $pstContent = null;
38
39 public function execute() {
40 // The data is hot but user-dependent, like page views, so we set vary cookies
41 $this->getMain()->setCacheMode( 'anon-public-user-private' );
42
43 // Get parameters
44 $params = $this->extractRequestParams();
45 $text = $params['text'];
46 $title = $params['title'];
47 if ( $title === null ) {
48 $titleProvided = false;
49 // A title is needed for parsing, so arbitrarily choose one
50 $title = 'API';
51 } else {
52 $titleProvided = true;
53 }
54
55 $page = $params['page'];
56 $pageid = $params['pageid'];
57 $oldid = $params['oldid'];
58
59 $model = $params['contentmodel'];
60 $format = $params['contentformat'];
61
62 if ( !is_null( $page ) && ( !is_null( $text ) || $titleProvided ) ) {
63 $this->dieUsage(
64 'The page parameter cannot be used together with the text and title parameters',
65 'params'
66 );
67 }
68
69 $prop = array_flip( $params['prop'] );
70
71 if ( isset( $params['section'] ) ) {
72 $this->section = $params['section'];
73 if ( !preg_match( '/^((T-)?\d+|new)$/', $this->section ) ) {
74 $this->dieUsage( "The section parameter must be a valid section id or 'new'", "invalidsection" );
75 }
76 } else {
77 $this->section = false;
78 }
79
80 // The parser needs $wgTitle to be set, apparently the
81 // $title parameter in Parser::parse isn't enough *sigh*
82 // TODO: Does this still need $wgTitle?
83 global $wgParser, $wgTitle;
84
85 $redirValues = null;
86
87 // Return result
88 $result = $this->getResult();
89
90 if ( !is_null( $oldid ) || !is_null( $pageid ) || !is_null( $page ) ) {
91 if ( !is_null( $oldid ) ) {
92 // Don't use the parser cache
93 $rev = Revision::newFromId( $oldid );
94 if ( !$rev ) {
95 $this->dieUsage( "There is no revision ID $oldid", 'missingrev' );
96 }
97 if ( !$rev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) {
98 $this->dieUsage( "You don't have permission to view deleted revisions", 'permissiondenied' );
99 }
100
101 $titleObj = $rev->getTitle();
102 $wgTitle = $titleObj;
103 $pageObj = WikiPage::factory( $titleObj );
104 $popts = $this->makeParserOptions( $pageObj, $params );
105
106 // If for some reason the "oldid" is actually the current revision, it may be cached
107 if ( $rev->isCurrent() ) {
108 // May get from/save to parser cache
109 $p_result = $this->getParsedContent( $pageObj, $popts,
110 $pageid, isset( $prop['wikitext'] ) );
111 } else { // This is an old revision, so get the text differently
112 $this->content = $rev->getContent( Revision::FOR_THIS_USER, $this->getUser() );
113
114 if ( $this->section !== false ) {
115 $this->content = $this->getSectionContent( $this->content, 'r' . $rev->getId() );
116 }
117
118 // Should we save old revision parses to the parser cache?
119 $p_result = $this->content->getParserOutput( $titleObj, $rev->getId(), $popts );
120 }
121 } else { // Not $oldid, but $pageid or $page
122 if ( $params['redirects'] ) {
123 $reqParams = array(
124 'action' => 'query',
125 'redirects' => '',
126 );
127 if ( !is_null( $pageid ) ) {
128 $reqParams['pageids'] = $pageid;
129 } else { // $page
130 $reqParams['titles'] = $page;
131 }
132 $req = new FauxRequest( $reqParams );
133 $main = new ApiMain( $req );
134 $main->execute();
135 $data = $main->getResultData();
136 $redirValues = isset( $data['query']['redirects'] )
137 ? $data['query']['redirects']
138 : array();
139 $to = $page;
140 foreach ( (array)$redirValues as $r ) {
141 $to = $r['to'];
142 }
143 $pageParams = array( 'title' => $to );
144 } elseif ( !is_null( $pageid ) ) {
145 $pageParams = array( 'pageid' => $pageid );
146 } else { // $page
147 $pageParams = array( 'title' => $page );
148 }
149
150 $pageObj = $this->getTitleOrPageId( $pageParams, 'fromdb' );
151 $titleObj = $pageObj->getTitle();
152 if ( !$titleObj || !$titleObj->exists() ) {
153 $this->dieUsage( "The page you specified doesn't exist", 'missingtitle' );
154 }
155 $wgTitle = $titleObj;
156
157 if ( isset( $prop['revid'] ) ) {
158 $oldid = $pageObj->getLatest();
159 }
160
161 $popts = $this->makeParserOptions( $pageObj, $params );
162
163 // Potentially cached
164 $p_result = $this->getParsedContent( $pageObj, $popts, $pageid,
165 isset( $prop['wikitext'] ) );
166 }
167 } else { // Not $oldid, $pageid, $page. Hence based on $text
168 $titleObj = Title::newFromText( $title );
169 if ( !$titleObj || $titleObj->isExternal() ) {
170 $this->dieUsageMsg( array( 'invalidtitle', $title ) );
171 }
172 $wgTitle = $titleObj;
173 if ( $titleObj->canExist() ) {
174 $pageObj = WikiPage::factory( $titleObj );
175 } else {
176 // Do like MediaWiki::initializeArticle()
177 $article = Article::newFromTitle( $titleObj, $this->getContext() );
178 $pageObj = $article->getPage();
179 }
180
181 $popts = $this->makeParserOptions( $pageObj, $params );
182 $textProvided = !is_null( $text );
183
184 if ( !$textProvided ) {
185 if ( $titleProvided && ( $prop || $params['generatexml'] ) ) {
186 $this->setWarning(
187 "'title' used without 'text', and parsed page properties were requested " .
188 "(did you mean to use 'page' instead of 'title'?)"
189 );
190 }
191 // Prevent warning from ContentHandler::makeContent()
192 $text = '';
193 }
194
195 // If we are parsing text, do not use the content model of the default
196 // API title, but default to wikitext to keep BC.
197 if ( $textProvided && !$titleProvided && is_null( $model ) ) {
198 $model = CONTENT_MODEL_WIKITEXT;
199 $this->setWarning( "No 'title' or 'contentmodel' was given, assuming $model." );
200 }
201
202 try {
203 $this->content = ContentHandler::makeContent( $text, $titleObj, $model, $format );
204 } catch ( MWContentSerializationException $ex ) {
205 $this->dieUsage( $ex->getMessage(), 'parseerror' );
206 }
207
208 if ( $this->section !== false ) {
209 if ( $this->section === 'new' ) {
210 // Insert the section title above the content.
211 if ( !is_null( $params['sectiontitle'] ) && $params['sectiontitle'] !== '' ) {
212 $this->content = $this->content->addSectionHeader( $params['sectiontitle'] );
213 }
214 } else {
215 $this->content = $this->getSectionContent( $this->content, $titleObj->getPrefixedText() );
216 }
217 }
218
219 if ( $params['pst'] || $params['onlypst'] ) {
220 $this->pstContent = $this->content->preSaveTransform( $titleObj, $this->getUser(), $popts );
221 }
222 if ( $params['onlypst'] ) {
223 // Build a result and bail out
224 $result_array = array();
225 $result_array['text'] = array();
226 ApiResult::setContent( $result_array['text'], $this->pstContent->serialize( $format ) );
227 if ( isset( $prop['wikitext'] ) ) {
228 $result_array['wikitext'] = array();
229 ApiResult::setContent( $result_array['wikitext'], $this->content->serialize( $format ) );
230 }
231 if ( !is_null( $params['summary'] ) ) {
232 $result_array['parsedsummary'] = array();
233 ApiResult::setContent(
234 $result_array['parsedsummary'],
235 Linker::formatComment( $params['summary'], $titleObj )
236 );
237 }
238
239 $result->addValue( null, $this->getModuleName(), $result_array );
240
241 return;
242 }
243
244 // Not cached (save or load)
245 if ( $params['pst'] ) {
246 $p_result = $this->pstContent->getParserOutput( $titleObj, null, $popts );
247 } else {
248 $p_result = $this->content->getParserOutput( $titleObj, null, $popts );
249 }
250 }
251
252 $result_array = array();
253
254 $result_array['title'] = $titleObj->getPrefixedText();
255
256 if ( !is_null( $oldid ) ) {
257 $result_array['revid'] = intval( $oldid );
258 }
259
260 if ( $params['redirects'] && !is_null( $redirValues ) ) {
261 $result_array['redirects'] = $redirValues;
262 }
263
264 if ( $params['disabletoc'] ) {
265 $p_result->setTOCEnabled( false );
266 }
267
268 if ( isset( $prop['text'] ) ) {
269 $result_array['text'] = array();
270 ApiResult::setContent( $result_array['text'], $p_result->getText() );
271 }
272
273 if ( !is_null( $params['summary'] ) ) {
274 $result_array['parsedsummary'] = array();
275 ApiResult::setContent(
276 $result_array['parsedsummary'],
277 Linker::formatComment( $params['summary'], $titleObj )
278 );
279 }
280
281 if ( isset( $prop['langlinks'] ) ) {
282 $langlinks = $p_result->getLanguageLinks();
283
284 if ( $params['effectivelanglinks'] ) {
285 // Link flags are ignored for now, but may in the future be
286 // included in the result.
287 $linkFlags = array();
288 Hooks::run( 'LanguageLinks', array( $titleObj, &$langlinks, &$linkFlags ) );
289 }
290 } else {
291 $langlinks = false;
292 }
293
294 if ( isset( $prop['langlinks'] ) ) {
295 $result_array['langlinks'] = $this->formatLangLinks( $langlinks );
296 }
297 if ( isset( $prop['categories'] ) ) {
298 $result_array['categories'] = $this->formatCategoryLinks( $p_result->getCategories() );
299 }
300 if ( isset( $prop['categorieshtml'] ) ) {
301 $categoriesHtml = $this->categoriesHtml( $p_result->getCategories() );
302 $result_array['categorieshtml'] = array();
303 ApiResult::setContent( $result_array['categorieshtml'], $categoriesHtml );
304 }
305 if ( isset( $prop['links'] ) ) {
306 $result_array['links'] = $this->formatLinks( $p_result->getLinks() );
307 }
308 if ( isset( $prop['templates'] ) ) {
309 $result_array['templates'] = $this->formatLinks( $p_result->getTemplates() );
310 }
311 if ( isset( $prop['images'] ) ) {
312 $result_array['images'] = array_keys( $p_result->getImages() );
313 }
314 if ( isset( $prop['externallinks'] ) ) {
315 $result_array['externallinks'] = array_keys( $p_result->getExternalLinks() );
316 }
317 if ( isset( $prop['sections'] ) ) {
318 $result_array['sections'] = $p_result->getSections();
319 }
320
321 if ( isset( $prop['displaytitle'] ) ) {
322 $result_array['displaytitle'] = $p_result->getDisplayTitle() ?
323 $p_result->getDisplayTitle() :
324 $titleObj->getPrefixedText();
325 }
326
327 if ( isset( $prop['headitems'] ) || isset( $prop['headhtml'] ) ) {
328 $context = $this->getContext();
329 $context->setTitle( $titleObj );
330 $context->getOutput()->addParserOutputMetadata( $p_result );
331
332 if ( isset( $prop['headitems'] ) ) {
333 $headItems = $this->formatHeadItems( $p_result->getHeadItems() );
334
335 $css = $this->formatCss( $context->getOutput()->buildCssLinksArray() );
336
337 $scripts = array( $context->getOutput()->getHeadScripts() );
338
339 $result_array['headitems'] = array_merge( $headItems, $css, $scripts );
340 }
341
342 if ( isset( $prop['headhtml'] ) ) {
343 $result_array['headhtml'] = array();
344 ApiResult::setContent(
345 $result_array['headhtml'],
346 $context->getOutput()->headElement( $context->getSkin() )
347 );
348 }
349 }
350
351 if ( isset( $prop['modules'] ) ) {
352 $result_array['modules'] = array_values( array_unique( $p_result->getModules() ) );
353 $result_array['modulescripts'] = array_values( array_unique( $p_result->getModuleScripts() ) );
354 $result_array['modulestyles'] = array_values( array_unique( $p_result->getModuleStyles() ) );
355 $result_array['modulemessages'] = array_values( array_unique( $p_result->getModuleMessages() ) );
356 }
357
358 if ( isset( $prop['indicators'] ) ) {
359 foreach ( $p_result->getIndicators() as $name => $content ) {
360 $indicator = array( 'name' => $name );
361 ApiResult::setContent( $indicator, $content );
362 $result_array['indicators'][] = $indicator;
363 }
364 }
365
366 if ( isset( $prop['iwlinks'] ) ) {
367 $result_array['iwlinks'] = $this->formatIWLinks( $p_result->getInterwikiLinks() );
368 }
369
370 if ( isset( $prop['wikitext'] ) ) {
371 $result_array['wikitext'] = array();
372 ApiResult::setContent( $result_array['wikitext'], $this->content->serialize( $format ) );
373 if ( !is_null( $this->pstContent ) ) {
374 $result_array['psttext'] = array();
375 ApiResult::setContent( $result_array['psttext'], $this->pstContent->serialize( $format ) );
376 }
377 }
378 if ( isset( $prop['properties'] ) ) {
379 $result_array['properties'] = $this->formatProperties( $p_result->getProperties() );
380 }
381
382 if ( isset( $prop['limitreportdata'] ) ) {
383 $result_array['limitreportdata'] =
384 $this->formatLimitReportData( $p_result->getLimitReportData() );
385 }
386 if ( isset( $prop['limitreporthtml'] ) ) {
387 $limitreportHtml = EditPage::getPreviewLimitReport( $p_result );
388 $result_array['limitreporthtml'] = array();
389 ApiResult::setContent( $result_array['limitreporthtml'], $limitreportHtml );
390 }
391
392 if ( $params['generatexml'] ) {
393 if ( $this->content->getModel() != CONTENT_MODEL_WIKITEXT ) {
394 $this->dieUsage( "generatexml is only supported for wikitext content", "notwikitext" );
395 }
396
397 $wgParser->startExternalParse( $titleObj, $popts, Parser::OT_PREPROCESS );
398 $dom = $wgParser->preprocessToDom( $this->content->getNativeData() );
399 if ( is_callable( array( $dom, 'saveXML' ) ) ) {
400 $xml = $dom->saveXML();
401 } else {
402 $xml = $dom->__toString();
403 }
404 $result_array['parsetree'] = array();
405 ApiResult::setContent( $result_array['parsetree'], $xml );
406 }
407
408 $result_mapping = array(
409 'redirects' => 'r',
410 'langlinks' => 'll',
411 'categories' => 'cl',
412 'links' => 'pl',
413 'templates' => 'tl',
414 'images' => 'img',
415 'externallinks' => 'el',
416 'iwlinks' => 'iw',
417 'sections' => 's',
418 'headitems' => 'hi',
419 'modules' => 'm',
420 'indicators' => 'ind',
421 'modulescripts' => 'm',
422 'modulestyles' => 'm',
423 'modulemessages' => 'm',
424 'properties' => 'pp',
425 'limitreportdata' => 'lr',
426 );
427 $this->setIndexedTagNames( $result_array, $result_mapping );
428 $result->addValue( null, $this->getModuleName(), $result_array );
429 }
430
431 /**
432 * Constructs a ParserOptions object
433 *
434 * @param WikiPage $pageObj
435 * @param array $params
436 *
437 * @return ParserOptions
438 */
439 protected function makeParserOptions( WikiPage $pageObj, array $params ) {
440
441 $popts = $pageObj->makeParserOptions( $this->getContext() );
442 $popts->enableLimitReport( !$params['disablepp'] );
443 $popts->setIsPreview( $params['preview'] || $params['sectionpreview'] );
444 $popts->setIsSectionPreview( $params['sectionpreview'] );
445 $popts->setEditSection( !$params['disableeditsection'] );
446
447 return $popts;
448 }
449
450 /**
451 * @param WikiPage $page
452 * @param ParserOptions $popts
453 * @param int $pageId
454 * @param bool $getWikitext
455 * @return ParserOutput
456 */
457 private function getParsedContent( WikiPage $page, $popts, $pageId = null, $getWikitext = false ) {
458 $this->content = $page->getContent( Revision::RAW ); //XXX: really raw?
459
460 if ( $this->section !== false && $this->content !== null ) {
461 $this->content = $this->getSectionContent(
462 $this->content,
463 !is_null( $pageId ) ? 'page id ' . $pageId : $page->getTitle()->getPrefixedText()
464 );
465
466 // Not cached (save or load)
467 return $this->content->getParserOutput( $page->getTitle(), null, $popts );
468 }
469
470 // Try the parser cache first
471 // getParserOutput will save to Parser cache if able
472 $pout = $page->getParserOutput( $popts );
473 if ( !$pout ) {
474 $this->dieUsage( "There is no revision ID {$page->getLatest()}", 'missingrev' );
475 }
476 if ( $getWikitext ) {
477 $this->content = $page->getContent( Revision::RAW );
478 }
479
480 return $pout;
481 }
482
483 /**
484 * @param Content $content
485 * @param string $what Identifies the content in error messages, e.g. page title.
486 * @return Content|bool
487 */
488 private function getSectionContent( Content $content, $what ) {
489 // Not cached (save or load)
490 $section = $content->getSection( $this->section );
491 if ( $section === false ) {
492 $this->dieUsage( "There is no section {$this->section} in " . $what, 'nosuchsection' );
493 }
494 if ( $section === null ) {
495 $this->dieUsage( "Sections are not supported by " . $what, 'nosuchsection' );
496 $section = false;
497 }
498
499 return $section;
500 }
501
502 private function formatLangLinks( $links ) {
503 $result = array();
504 foreach ( $links as $link ) {
505 $entry = array();
506 $bits = explode( ':', $link, 2 );
507 $title = Title::newFromText( $link );
508
509 $entry['lang'] = $bits[0];
510 if ( $title ) {
511 $entry['url'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
512 // localised language name in 'uselang' language
513 $entry['langname'] = Language::fetchLanguageName(
514 $title->getInterwiki(),
515 $this->getLanguage()->getCode()
516 );
517
518 // native language name
519 $entry['autonym'] = Language::fetchLanguageName( $title->getInterwiki() );
520 }
521 ApiResult::setContent( $entry, $bits[1] );
522 $result[] = $entry;
523 }
524
525 return $result;
526 }
527
528 private function formatCategoryLinks( $links ) {
529 $result = array();
530
531 if ( !$links ) {
532 return $result;
533 }
534
535 // Fetch hiddencat property
536 $lb = new LinkBatch;
537 $lb->setArray( array( NS_CATEGORY => $links ) );
538 $db = $this->getDB();
539 $res = $db->select( array( 'page', 'page_props' ),
540 array( 'page_title', 'pp_propname' ),
541 $lb->constructSet( 'page', $db ),
542 __METHOD__,
543 array(),
544 array( 'page_props' => array(
545 'LEFT JOIN', array( 'pp_propname' => 'hiddencat', 'pp_page = page_id' )
546 ) )
547 );
548 $hiddencats = array();
549 foreach ( $res as $row ) {
550 $hiddencats[$row->page_title] = isset( $row->pp_propname );
551 }
552
553 foreach ( $links as $link => $sortkey ) {
554 $entry = array();
555 $entry['sortkey'] = $sortkey;
556 ApiResult::setContent( $entry, $link );
557 if ( !isset( $hiddencats[$link] ) ) {
558 $entry['missing'] = '';
559 } elseif ( $hiddencats[$link] ) {
560 $entry['hidden'] = '';
561 }
562 $result[] = $entry;
563 }
564
565 return $result;
566 }
567
568 private function categoriesHtml( $categories ) {
569 $context = $this->getContext();
570 $context->getOutput()->addCategoryLinks( $categories );
571
572 return $context->getSkin()->getCategories();
573 }
574
575 private function formatLinks( $links ) {
576 $result = array();
577 foreach ( $links as $ns => $nslinks ) {
578 foreach ( $nslinks as $title => $id ) {
579 $entry = array();
580 $entry['ns'] = $ns;
581 ApiResult::setContent( $entry, Title::makeTitle( $ns, $title )->getFullText() );
582 if ( $id != 0 ) {
583 $entry['exists'] = '';
584 }
585 $result[] = $entry;
586 }
587 }
588
589 return $result;
590 }
591
592 private function formatIWLinks( $iw ) {
593 $result = array();
594 foreach ( $iw as $prefix => $titles ) {
595 foreach ( array_keys( $titles ) as $title ) {
596 $entry = array();
597 $entry['prefix'] = $prefix;
598
599 $title = Title::newFromText( "{$prefix}:{$title}" );
600 if ( $title ) {
601 $entry['url'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
602 }
603
604 ApiResult::setContent( $entry, $title->getFullText() );
605 $result[] = $entry;
606 }
607 }
608
609 return $result;
610 }
611
612 private function formatHeadItems( $headItems ) {
613 $result = array();
614 foreach ( $headItems as $tag => $content ) {
615 $entry = array();
616 $entry['tag'] = $tag;
617 ApiResult::setContent( $entry, $content );
618 $result[] = $entry;
619 }
620
621 return $result;
622 }
623
624 private function formatProperties( $properties ) {
625 $result = array();
626 foreach ( $properties as $name => $value ) {
627 $entry = array();
628 $entry['name'] = $name;
629 ApiResult::setContent( $entry, $value );
630 $result[] = $entry;
631 }
632
633 return $result;
634 }
635
636 private function formatCss( $css ) {
637 $result = array();
638 foreach ( $css as $file => $link ) {
639 $entry = array();
640 $entry['file'] = $file;
641 ApiResult::setContent( $entry, $link );
642 $result[] = $entry;
643 }
644
645 return $result;
646 }
647
648 private function formatLimitReportData( $limitReportData ) {
649 $result = array();
650 $apiResult = $this->getResult();
651
652 foreach ( $limitReportData as $name => $value ) {
653 $entry = array();
654 $entry['name'] = $name;
655 if ( !is_array( $value ) ) {
656 $value = array( $value );
657 }
658 $apiResult->setIndexedTagName( $value, 'param' );
659 $apiResult->setIndexedTagName_recursive( $value, 'param' );
660 $entry = array_merge( $entry, $value );
661 $result[] = $entry;
662 }
663
664 return $result;
665 }
666
667 private function setIndexedTagNames( &$array, $mapping ) {
668 foreach ( $mapping as $key => $name ) {
669 if ( isset( $array[$key] ) ) {
670 $this->getResult()->setIndexedTagName( $array[$key], $name );
671 }
672 }
673 }
674
675 public function getAllowedParams() {
676 return array(
677 'title' => null,
678 'text' => null,
679 'summary' => null,
680 'page' => null,
681 'pageid' => array(
682 ApiBase::PARAM_TYPE => 'integer',
683 ),
684 'redirects' => false,
685 'oldid' => array(
686 ApiBase::PARAM_TYPE => 'integer',
687 ),
688 'prop' => array(
689 ApiBase::PARAM_DFLT => 'text|langlinks|categories|links|templates|' .
690 'images|externallinks|sections|revid|displaytitle|iwlinks|properties',
691 ApiBase::PARAM_ISMULTI => true,
692 ApiBase::PARAM_TYPE => array(
693 'text',
694 'langlinks',
695 'categories',
696 'categorieshtml',
697 'links',
698 'templates',
699 'images',
700 'externallinks',
701 'sections',
702 'revid',
703 'displaytitle',
704 'headitems',
705 'headhtml',
706 'modules',
707 'indicators',
708 'iwlinks',
709 'wikitext',
710 'properties',
711 'limitreportdata',
712 'limitreporthtml',
713 )
714 ),
715 'pst' => false,
716 'onlypst' => false,
717 'effectivelanglinks' => false,
718 'section' => null,
719 'sectiontitle' => array(
720 ApiBase::PARAM_TYPE => 'string',
721 ),
722 'disablepp' => false,
723 'disableeditsection' => false,
724 'generatexml' => array(
725 ApiBase::PARAM_DFLT => false,
726 ApiBase::PARAM_HELP_MSG => array(
727 'apihelp-parse-param-generatexml', CONTENT_MODEL_WIKITEXT
728 ),
729 ),
730 'preview' => false,
731 'sectionpreview' => false,
732 'disabletoc' => false,
733 'contentformat' => array(
734 ApiBase::PARAM_TYPE => ContentHandler::getAllContentFormats(),
735 ),
736 'contentmodel' => array(
737 ApiBase::PARAM_TYPE => ContentHandler::getContentModels(),
738 )
739 );
740 }
741
742 protected function getExamplesMessages() {
743 return array(
744 'action=parse&page=Project:Sandbox'
745 => 'apihelp-parse-example-page',
746 'action=parse&text={{Project:Sandbox}}&contentmodel=wikitext'
747 => 'apihelp-parse-example-text',
748 'action=parse&text={{PAGENAME}}&title=Test'
749 => 'apihelp-parse-example-texttitle',
750 'action=parse&summary=Some+[[link]]&prop='
751 => 'apihelp-parse-example-summary',
752 );
753 }
754
755 public function getHelpUrls() {
756 return 'https://www.mediawiki.org/wiki/API:Parsing_wikitext#parse';
757 }
758 }