Merge "Change error/warning messages to be parsed instead of escaped"
[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 ( $this->section === 'new' ) {
92 $this->dieUsage( 'section=new cannot be combined with oldid, pageid or page parameters. Please use text', 'params' );
93 }
94 if ( !is_null( $oldid ) ) {
95 // Don't use the parser cache
96 $rev = Revision::newFromId( $oldid );
97 if ( !$rev ) {
98 $this->dieUsage( "There is no revision ID $oldid", 'missingrev' );
99 }
100 if ( !$rev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) {
101 $this->dieUsage( "You don't have permission to view deleted revisions", 'permissiondenied' );
102 }
103
104 $titleObj = $rev->getTitle();
105 $wgTitle = $titleObj;
106 $pageObj = WikiPage::factory( $titleObj );
107 $popts = $this->makeParserOptions( $pageObj, $params );
108
109 // If for some reason the "oldid" is actually the current revision, it may be cached
110 // Deliberately comparing $pageObj->getLatest() with $rev->getId(), rather than
111 // checking $rev->isCurrent(), because $pageObj is what actually ends up being used,
112 // and if its ->getLatest() is outdated, $rev->isCurrent() won't tell us that.
113 if ( $rev->getId() == $pageObj->getLatest() ) {
114 // May get from/save to parser cache
115 $p_result = $this->getParsedContent( $pageObj, $popts,
116 $pageid, isset( $prop['wikitext'] ) );
117 } else { // This is an old revision, so get the text differently
118 $this->content = $rev->getContent( Revision::FOR_THIS_USER, $this->getUser() );
119
120 if ( $this->section !== false ) {
121 $this->content = $this->getSectionContent( $this->content, 'r' . $rev->getId() );
122 }
123
124 // Should we save old revision parses to the parser cache?
125 $p_result = $this->content->getParserOutput( $titleObj, $rev->getId(), $popts );
126 }
127 } else { // Not $oldid, but $pageid or $page
128 if ( $params['redirects'] ) {
129 $reqParams = array(
130 'redirects' => '',
131 );
132 if ( !is_null( $pageid ) ) {
133 $reqParams['pageids'] = $pageid;
134 } else { // $page
135 $reqParams['titles'] = $page;
136 }
137 $req = new FauxRequest( $reqParams );
138 $main = new ApiMain( $req );
139 $pageSet = new ApiPageSet( $main );
140 $pageSet->execute();
141
142 $to = $page;
143 foreach ( $pageSet->getRedirectTitles() as $title ) {
144 $to = $title->getFullText();
145 }
146 $pageParams = array( 'title' => $to );
147 } elseif ( !is_null( $pageid ) ) {
148 $pageParams = array( 'pageid' => $pageid );
149 } else { // $page
150 $pageParams = array( 'title' => $page );
151 }
152
153 $pageObj = $this->getTitleOrPageId( $pageParams, 'fromdb' );
154 $titleObj = $pageObj->getTitle();
155 if ( !$titleObj || !$titleObj->exists() ) {
156 $this->dieUsage( "The page you specified doesn't exist", 'missingtitle' );
157 }
158 $wgTitle = $titleObj;
159
160 if ( isset( $prop['revid'] ) ) {
161 $oldid = $pageObj->getLatest();
162 }
163
164 $popts = $this->makeParserOptions( $pageObj, $params );
165
166 // Potentially cached
167 $p_result = $this->getParsedContent( $pageObj, $popts, $pageid,
168 isset( $prop['wikitext'] ) );
169 }
170 } else { // Not $oldid, $pageid, $page. Hence based on $text
171 $titleObj = Title::newFromText( $title );
172 if ( !$titleObj || $titleObj->isExternal() ) {
173 $this->dieUsageMsg( array( 'invalidtitle', $title ) );
174 }
175 $wgTitle = $titleObj;
176 if ( $titleObj->canExist() ) {
177 $pageObj = WikiPage::factory( $titleObj );
178 } else {
179 // Do like MediaWiki::initializeArticle()
180 $article = Article::newFromTitle( $titleObj, $this->getContext() );
181 $pageObj = $article->getPage();
182 }
183
184 $popts = $this->makeParserOptions( $pageObj, $params );
185 $textProvided = !is_null( $text );
186
187 if ( !$textProvided ) {
188 if ( $titleProvided && ( $prop || $params['generatexml'] ) ) {
189 $this->setWarning(
190 "'title' used without 'text', and parsed page properties were requested " .
191 "(did you mean to use 'page' instead of 'title'?)"
192 );
193 }
194 // Prevent warning from ContentHandler::makeContent()
195 $text = '';
196 }
197
198 // If we are parsing text, do not use the content model of the default
199 // API title, but default to wikitext to keep BC.
200 if ( $textProvided && !$titleProvided && is_null( $model ) ) {
201 $model = CONTENT_MODEL_WIKITEXT;
202 $this->setWarning( "No 'title' or 'contentmodel' was given, assuming $model." );
203 }
204
205 try {
206 $this->content = ContentHandler::makeContent( $text, $titleObj, $model, $format );
207 } catch ( MWContentSerializationException $ex ) {
208 $this->dieUsage( $ex->getMessage(), 'parseerror' );
209 }
210
211 if ( $this->section !== false ) {
212 if ( $this->section === 'new' ) {
213 // Insert the section title above the content.
214 if ( !is_null( $params['sectiontitle'] ) && $params['sectiontitle'] !== '' ) {
215 $this->content = $this->content->addSectionHeader( $params['sectiontitle'] );
216 }
217 } else {
218 $this->content = $this->getSectionContent( $this->content, $titleObj->getPrefixedText() );
219 }
220 }
221
222 if ( $params['pst'] || $params['onlypst'] ) {
223 $this->pstContent = $this->content->preSaveTransform( $titleObj, $this->getUser(), $popts );
224 }
225 if ( $params['onlypst'] ) {
226 // Build a result and bail out
227 $result_array = array();
228 $result_array['text'] = $this->pstContent->serialize( $format );
229 $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'text';
230 if ( isset( $prop['wikitext'] ) ) {
231 $result_array['wikitext'] = $this->content->serialize( $format );
232 $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'wikitext';
233 }
234 if ( !is_null( $params['summary'] ) ||
235 ( !is_null( $params['sectiontitle'] ) && $this->section === 'new' )
236 ) {
237 $result_array['parsedsummary'] = $this->formatSummary( $titleObj, $params );
238 $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'parsedsummary';
239 }
240
241 $result->addValue( null, $this->getModuleName(), $result_array );
242
243 return;
244 }
245
246 // Not cached (save or load)
247 if ( $params['pst'] ) {
248 $p_result = $this->pstContent->getParserOutput( $titleObj, null, $popts );
249 } else {
250 $p_result = $this->content->getParserOutput( $titleObj, null, $popts );
251 }
252 }
253
254 $result_array = array();
255
256 $result_array['title'] = $titleObj->getPrefixedText();
257
258 if ( !is_null( $oldid ) ) {
259 $result_array['revid'] = intval( $oldid );
260 }
261
262 if ( $params['redirects'] && !is_null( $redirValues ) ) {
263 $result_array['redirects'] = $redirValues;
264 }
265
266 if ( $params['disabletoc'] ) {
267 $p_result->setTOCEnabled( false );
268 }
269
270 if ( isset( $prop['text'] ) ) {
271 $result_array['text'] = $p_result->getText();
272 $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'text';
273 }
274
275 if ( !is_null( $params['summary'] ) ||
276 ( !is_null( $params['sectiontitle'] ) && $this->section === 'new' )
277 ) {
278 $result_array['parsedsummary'] = $this->formatSummary( $titleObj, $params );
279 $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'parsedsummary';
280 }
281
282 if ( isset( $prop['langlinks'] ) ) {
283 $langlinks = $p_result->getLanguageLinks();
284
285 if ( $params['effectivelanglinks'] ) {
286 // Link flags are ignored for now, but may in the future be
287 // included in the result.
288 $linkFlags = array();
289 Hooks::run( 'LanguageLinks', array( $titleObj, &$langlinks, &$linkFlags ) );
290 }
291 } else {
292 $langlinks = false;
293 }
294
295 if ( isset( $prop['langlinks'] ) ) {
296 $result_array['langlinks'] = $this->formatLangLinks( $langlinks );
297 }
298 if ( isset( $prop['categories'] ) ) {
299 $result_array['categories'] = $this->formatCategoryLinks( $p_result->getCategories() );
300 }
301 if ( isset( $prop['categorieshtml'] ) ) {
302 $result_array['categorieshtml'] = $this->categoriesHtml( $p_result->getCategories() );
303 $result_array[ApiResult::META_BC_SUBELEMENTS][] = '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'] = $context->getOutput()->headElement( $context->getSkin() );
344 $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'headhtml';
345 }
346 }
347
348 if ( isset( $prop['modules'] ) ) {
349 $result_array['modules'] = array_values( array_unique( $p_result->getModules() ) );
350 $result_array['modulescripts'] = array_values( array_unique( $p_result->getModuleScripts() ) );
351 $result_array['modulestyles'] = array_values( array_unique( $p_result->getModuleStyles() ) );
352 $result_array['modulemessages'] = array_values( array_unique( $p_result->getModuleMessages() ) );
353 }
354
355 if ( isset( $prop['indicators'] ) ) {
356 $result_array['indicators'] = (array)$p_result->getIndicators();
357 ApiResult::setArrayType( $result_array['indicators'], 'BCkvp', 'name' );
358 }
359
360 if ( isset( $prop['iwlinks'] ) ) {
361 $result_array['iwlinks'] = $this->formatIWLinks( $p_result->getInterwikiLinks() );
362 }
363
364 if ( isset( $prop['wikitext'] ) ) {
365 $result_array['wikitext'] = $this->content->serialize( $format );
366 $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'wikitext';
367 if ( !is_null( $this->pstContent ) ) {
368 $result_array['psttext'] = $this->pstContent->serialize( $format );
369 $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'psttext';
370 }
371 }
372 if ( isset( $prop['properties'] ) ) {
373 $result_array['properties'] = (array)$p_result->getProperties();
374 ApiResult::setArrayType( $result_array['properties'], 'BCkvp', 'name' );
375 }
376
377 if ( isset( $prop['limitreportdata'] ) ) {
378 $result_array['limitreportdata'] =
379 $this->formatLimitReportData( $p_result->getLimitReportData() );
380 }
381 if ( isset( $prop['limitreporthtml'] ) ) {
382 $result_array['limitreporthtml'] = EditPage::getPreviewLimitReport( $p_result );
383 $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'limitreporthtml';
384 }
385
386 if ( $params['generatexml'] ) {
387 if ( $this->content->getModel() != CONTENT_MODEL_WIKITEXT ) {
388 $this->dieUsage( "generatexml is only supported for wikitext content", "notwikitext" );
389 }
390
391 $wgParser->startExternalParse( $titleObj, $popts, Parser::OT_PREPROCESS );
392 $dom = $wgParser->preprocessToDom( $this->content->getNativeData() );
393 if ( is_callable( array( $dom, 'saveXML' ) ) ) {
394 $xml = $dom->saveXML();
395 } else {
396 $xml = $dom->__toString();
397 }
398 $result_array['parsetree'] = $xml;
399 $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'parsetree';
400 }
401
402 $result_mapping = array(
403 'redirects' => 'r',
404 'langlinks' => 'll',
405 'categories' => 'cl',
406 'links' => 'pl',
407 'templates' => 'tl',
408 'images' => 'img',
409 'externallinks' => 'el',
410 'iwlinks' => 'iw',
411 'sections' => 's',
412 'headitems' => 'hi',
413 'modules' => 'm',
414 'indicators' => 'ind',
415 'modulescripts' => 'm',
416 'modulestyles' => 'm',
417 'modulemessages' => 'm',
418 'properties' => 'pp',
419 'limitreportdata' => 'lr',
420 );
421 $this->setIndexedTagNames( $result_array, $result_mapping );
422 $result->addValue( null, $this->getModuleName(), $result_array );
423 }
424
425 /**
426 * Constructs a ParserOptions object
427 *
428 * @param WikiPage $pageObj
429 * @param array $params
430 *
431 * @return ParserOptions
432 */
433 protected function makeParserOptions( WikiPage $pageObj, array $params ) {
434
435 $popts = $pageObj->makeParserOptions( $this->getContext() );
436 $popts->enableLimitReport( !$params['disablepp'] );
437 $popts->setIsPreview( $params['preview'] || $params['sectionpreview'] );
438 $popts->setIsSectionPreview( $params['sectionpreview'] );
439 $popts->setEditSection( !$params['disableeditsection'] );
440
441 return $popts;
442 }
443
444 /**
445 * @param WikiPage $page
446 * @param ParserOptions $popts
447 * @param int $pageId
448 * @param bool $getWikitext
449 * @return ParserOutput
450 */
451 private function getParsedContent( WikiPage $page, $popts, $pageId = null, $getWikitext = false ) {
452 $this->content = $page->getContent( Revision::RAW ); //XXX: really raw?
453
454 if ( $this->section !== false && $this->content !== null ) {
455 $this->content = $this->getSectionContent(
456 $this->content,
457 !is_null( $pageId ) ? 'page id ' . $pageId : $page->getTitle()->getPrefixedText()
458 );
459
460 // Not cached (save or load)
461 return $this->content->getParserOutput( $page->getTitle(), null, $popts );
462 }
463
464 // Try the parser cache first
465 // getParserOutput will save to Parser cache if able
466 $pout = $page->getParserOutput( $popts );
467 if ( !$pout ) {
468 $this->dieUsage( "There is no revision ID {$page->getLatest()}", 'missingrev' );
469 }
470 if ( $getWikitext ) {
471 $this->content = $page->getContent( Revision::RAW );
472 }
473
474 return $pout;
475 }
476
477 /**
478 * @param Content $content
479 * @param string $what Identifies the content in error messages, e.g. page title.
480 * @return Content|bool
481 */
482 private function getSectionContent( Content $content, $what ) {
483 // Not cached (save or load)
484 $section = $content->getSection( $this->section );
485 if ( $section === false ) {
486 $this->dieUsage( "There is no section {$this->section} in " . $what, 'nosuchsection' );
487 }
488 if ( $section === null ) {
489 $this->dieUsage( "Sections are not supported by " . $what, 'nosuchsection' );
490 $section = false;
491 }
492
493 return $section;
494 }
495
496 /**
497 * This mimicks the behavior of EditPage in formatting a summary
498 *
499 * @param Title $title of the page being parsed
500 * @param Array $params the API parameters of the request
501 * @return Content|bool
502 */
503 private function formatSummary( $title, $params ) {
504 global $wgParser;
505 $summary = !is_null( $params['summary'] ) ? $params['summary'] : '';
506 $sectionTitle = !is_null( $params['sectiontitle'] ) ? $params['sectiontitle'] : '';
507
508 if ( $this->section === 'new' && ( $sectionTitle === '' || $summary === '' ) ) {
509 if( $sectionTitle !== '' ) {
510 $summary = $params['sectiontitle'];
511 }
512 if ( $summary !== '' ) {
513 $summary = wfMessage( 'newsectionsummary' )->rawParams( $wgParser->stripSectionName( $summary ) )
514 ->inContentLanguage()->text();
515 }
516 }
517 return Linker::formatComment( $summary, $title, $this->section === 'new' );
518 }
519
520 private function formatLangLinks( $links ) {
521 $result = array();
522 foreach ( $links as $link ) {
523 $entry = array();
524 $bits = explode( ':', $link, 2 );
525 $title = Title::newFromText( $link );
526
527 $entry['lang'] = $bits[0];
528 if ( $title ) {
529 $entry['url'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
530 // localised language name in 'uselang' language
531 $entry['langname'] = Language::fetchLanguageName(
532 $title->getInterwiki(),
533 $this->getLanguage()->getCode()
534 );
535
536 // native language name
537 $entry['autonym'] = Language::fetchLanguageName( $title->getInterwiki() );
538 }
539 ApiResult::setContentValue( $entry, 'title', $bits[1] );
540 $result[] = $entry;
541 }
542
543 return $result;
544 }
545
546 private function formatCategoryLinks( $links ) {
547 $result = array();
548
549 if ( !$links ) {
550 return $result;
551 }
552
553 // Fetch hiddencat property
554 $lb = new LinkBatch;
555 $lb->setArray( array( NS_CATEGORY => $links ) );
556 $db = $this->getDB();
557 $res = $db->select( array( 'page', 'page_props' ),
558 array( 'page_title', 'pp_propname' ),
559 $lb->constructSet( 'page', $db ),
560 __METHOD__,
561 array(),
562 array( 'page_props' => array(
563 'LEFT JOIN', array( 'pp_propname' => 'hiddencat', 'pp_page = page_id' )
564 ) )
565 );
566 $hiddencats = array();
567 foreach ( $res as $row ) {
568 $hiddencats[$row->page_title] = isset( $row->pp_propname );
569 }
570
571 foreach ( $links as $link => $sortkey ) {
572 $entry = array();
573 $entry['sortkey'] = $sortkey;
574 ApiResult::setContentValue( $entry, 'category', $link );
575 if ( !isset( $hiddencats[$link] ) ) {
576 $entry['missing'] = true;
577 } elseif ( $hiddencats[$link] ) {
578 $entry['hidden'] = true;
579 }
580 $result[] = $entry;
581 }
582
583 return $result;
584 }
585
586 private function categoriesHtml( $categories ) {
587 $context = $this->getContext();
588 $context->getOutput()->addCategoryLinks( $categories );
589
590 return $context->getSkin()->getCategories();
591 }
592
593 private function formatLinks( $links ) {
594 $result = array();
595 foreach ( $links as $ns => $nslinks ) {
596 foreach ( $nslinks as $title => $id ) {
597 $entry = array();
598 $entry['ns'] = $ns;
599 ApiResult::setContentValue( $entry, 'title', Title::makeTitle( $ns, $title )->getFullText() );
600 $entry['exists'] = $id != 0;
601 $result[] = $entry;
602 }
603 }
604
605 return $result;
606 }
607
608 private function formatIWLinks( $iw ) {
609 $result = array();
610 foreach ( $iw as $prefix => $titles ) {
611 foreach ( array_keys( $titles ) as $title ) {
612 $entry = array();
613 $entry['prefix'] = $prefix;
614
615 $title = Title::newFromText( "{$prefix}:{$title}" );
616 if ( $title ) {
617 $entry['url'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
618 }
619
620 ApiResult::setContentValue( $entry, 'title', $title->getFullText() );
621 $result[] = $entry;
622 }
623 }
624
625 return $result;
626 }
627
628 private function formatHeadItems( $headItems ) {
629 $result = array();
630 foreach ( $headItems as $tag => $content ) {
631 $entry = array();
632 $entry['tag'] = $tag;
633 ApiResult::setContentValue( $entry, 'content', $content );
634 $result[] = $entry;
635 }
636
637 return $result;
638 }
639
640 private function formatCss( $css ) {
641 $result = array();
642 foreach ( $css as $file => $link ) {
643 $entry = array();
644 $entry['file'] = $file;
645 ApiResult::setContentValue( $entry, 'link', $link );
646 $result[] = $entry;
647 }
648
649 return $result;
650 }
651
652 private function formatLimitReportData( $limitReportData ) {
653 $result = array();
654 $apiResult = $this->getResult();
655
656 foreach ( $limitReportData as $name => $value ) {
657 $entry = array();
658 $entry['name'] = $name;
659 if ( !is_array( $value ) ) {
660 $value = array( $value );
661 }
662 ApiResult::setIndexedTagNameRecursive( $value, 'param' );
663 $entry = array_merge( $entry, $value );
664 $result[] = $entry;
665 }
666
667 return $result;
668 }
669
670 private function setIndexedTagNames( &$array, $mapping ) {
671 foreach ( $mapping as $key => $name ) {
672 if ( isset( $array[$key] ) ) {
673 ApiResult::setIndexedTagName( $array[$key], $name );
674 }
675 }
676 }
677
678 public function getAllowedParams() {
679 return array(
680 'title' => null,
681 'text' => null,
682 'summary' => null,
683 'page' => null,
684 'pageid' => array(
685 ApiBase::PARAM_TYPE => 'integer',
686 ),
687 'redirects' => false,
688 'oldid' => array(
689 ApiBase::PARAM_TYPE => 'integer',
690 ),
691 'prop' => array(
692 ApiBase::PARAM_DFLT => 'text|langlinks|categories|links|templates|' .
693 'images|externallinks|sections|revid|displaytitle|iwlinks|properties',
694 ApiBase::PARAM_ISMULTI => true,
695 ApiBase::PARAM_TYPE => array(
696 'text',
697 'langlinks',
698 'categories',
699 'categorieshtml',
700 'links',
701 'templates',
702 'images',
703 'externallinks',
704 'sections',
705 'revid',
706 'displaytitle',
707 'headitems',
708 'headhtml',
709 'modules',
710 'indicators',
711 'iwlinks',
712 'wikitext',
713 'properties',
714 'limitreportdata',
715 'limitreporthtml',
716 )
717 ),
718 'pst' => false,
719 'onlypst' => false,
720 'effectivelanglinks' => false,
721 'section' => null,
722 'sectiontitle' => array(
723 ApiBase::PARAM_TYPE => 'string',
724 ),
725 'disablepp' => false,
726 'disableeditsection' => false,
727 'generatexml' => array(
728 ApiBase::PARAM_DFLT => false,
729 ApiBase::PARAM_HELP_MSG => array(
730 'apihelp-parse-param-generatexml', CONTENT_MODEL_WIKITEXT
731 ),
732 ),
733 'preview' => false,
734 'sectionpreview' => false,
735 'disabletoc' => false,
736 'contentformat' => array(
737 ApiBase::PARAM_TYPE => ContentHandler::getAllContentFormats(),
738 ),
739 'contentmodel' => array(
740 ApiBase::PARAM_TYPE => ContentHandler::getContentModels(),
741 )
742 );
743 }
744
745 protected function getExamplesMessages() {
746 return array(
747 'action=parse&page=Project:Sandbox'
748 => 'apihelp-parse-example-page',
749 'action=parse&text={{Project:Sandbox}}&contentmodel=wikitext'
750 => 'apihelp-parse-example-text',
751 'action=parse&text={{PAGENAME}}&title=Test'
752 => 'apihelp-parse-example-texttitle',
753 'action=parse&summary=Some+[[link]]&prop='
754 => 'apihelp-parse-example-summary',
755 );
756 }
757
758 public function getHelpUrls() {
759 return 'https://www.mediawiki.org/wiki/API:Parsing_wikitext#parse';
760 }
761 }