API: Overhaul ApiResult, make format=xml not throw, and add json formatversion
[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 if ( $rev->isCurrent() ) {
111 // May get from/save to parser cache
112 $p_result = $this->getParsedContent( $pageObj, $popts,
113 $pageid, isset( $prop['wikitext'] ) );
114 } else { // This is an old revision, so get the text differently
115 $this->content = $rev->getContent( Revision::FOR_THIS_USER, $this->getUser() );
116
117 if ( $this->section !== false ) {
118 $this->content = $this->getSectionContent( $this->content, 'r' . $rev->getId() );
119 }
120
121 // Should we save old revision parses to the parser cache?
122 $p_result = $this->content->getParserOutput( $titleObj, $rev->getId(), $popts );
123 }
124 } else { // Not $oldid, but $pageid or $page
125 if ( $params['redirects'] ) {
126 $reqParams = array(
127 'redirects' => '',
128 );
129 if ( !is_null( $pageid ) ) {
130 $reqParams['pageids'] = $pageid;
131 } else { // $page
132 $reqParams['titles'] = $page;
133 }
134 $req = new FauxRequest( $reqParams );
135 $main = new ApiMain( $req );
136 $pageSet = new ApiPageSet( $main );
137 $pageSet->execute();
138
139 $to = $page;
140 foreach ( $pageSet->getRedirectTitles() as $title ) {
141 $to = $title->getFullText();
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::setContentValue( $result_array['text'], 'text', $this->pstContent->serialize( $format ) );
227 if ( isset( $prop['wikitext'] ) ) {
228 $result_array['wikitext'] = array();
229 ApiResult::setContentValue( $result_array['wikitext'], 'wikitext', $this->content->serialize( $format ) );
230 }
231 if ( !is_null( $params['summary'] ) ||
232 ( !is_null( $params['sectiontitle'] ) && $this->section === 'new' )
233 ) {
234 $result_array['parsedsummary'] = array();
235 ApiResult::setContentValue(
236 $result_array['parsedsummary'],
237 'parsedsummary',
238 $this->formatSummary( $titleObj, $params )
239 );
240 }
241
242 $result->addValue( null, $this->getModuleName(), $result_array );
243
244 return;
245 }
246
247 // Not cached (save or load)
248 if ( $params['pst'] ) {
249 $p_result = $this->pstContent->getParserOutput( $titleObj, null, $popts );
250 } else {
251 $p_result = $this->content->getParserOutput( $titleObj, null, $popts );
252 }
253 }
254
255 $result_array = array();
256
257 $result_array['title'] = $titleObj->getPrefixedText();
258
259 if ( !is_null( $oldid ) ) {
260 $result_array['revid'] = intval( $oldid );
261 }
262
263 if ( $params['redirects'] && !is_null( $redirValues ) ) {
264 $result_array['redirects'] = $redirValues;
265 }
266
267 if ( $params['disabletoc'] ) {
268 $p_result->setTOCEnabled( false );
269 }
270
271 if ( isset( $prop['text'] ) ) {
272 $result_array['text'] = array();
273 ApiResult::setContentValue( $result_array['text'], 'text', $p_result->getText() );
274 }
275
276 if ( !is_null( $params['summary'] ) ||
277 ( !is_null( $params['sectiontitle'] ) && $this->section === 'new' )
278 ) {
279 $result_array['parsedsummary'] = array();
280 ApiResult::setContentValue(
281 $result_array['parsedsummary'],
282 'parsedsummary',
283 $this->formatSummary( $titleObj, $params )
284 );
285 }
286
287 if ( isset( $prop['langlinks'] ) ) {
288 $langlinks = $p_result->getLanguageLinks();
289
290 if ( $params['effectivelanglinks'] ) {
291 // Link flags are ignored for now, but may in the future be
292 // included in the result.
293 $linkFlags = array();
294 Hooks::run( 'LanguageLinks', array( $titleObj, &$langlinks, &$linkFlags ) );
295 }
296 } else {
297 $langlinks = false;
298 }
299
300 if ( isset( $prop['langlinks'] ) ) {
301 $result_array['langlinks'] = $this->formatLangLinks( $langlinks );
302 }
303 if ( isset( $prop['categories'] ) ) {
304 $result_array['categories'] = $this->formatCategoryLinks( $p_result->getCategories() );
305 }
306 if ( isset( $prop['categorieshtml'] ) ) {
307 $categoriesHtml = $this->categoriesHtml( $p_result->getCategories() );
308 $result_array['categorieshtml'] = array();
309 ApiResult::setContentValue( $result_array['categorieshtml'], 'categorieshtml', $categoriesHtml );
310 }
311 if ( isset( $prop['links'] ) ) {
312 $result_array['links'] = $this->formatLinks( $p_result->getLinks() );
313 }
314 if ( isset( $prop['templates'] ) ) {
315 $result_array['templates'] = $this->formatLinks( $p_result->getTemplates() );
316 }
317 if ( isset( $prop['images'] ) ) {
318 $result_array['images'] = array_keys( $p_result->getImages() );
319 }
320 if ( isset( $prop['externallinks'] ) ) {
321 $result_array['externallinks'] = array_keys( $p_result->getExternalLinks() );
322 }
323 if ( isset( $prop['sections'] ) ) {
324 $result_array['sections'] = $p_result->getSections();
325 }
326
327 if ( isset( $prop['displaytitle'] ) ) {
328 $result_array['displaytitle'] = $p_result->getDisplayTitle() ?
329 $p_result->getDisplayTitle() :
330 $titleObj->getPrefixedText();
331 }
332
333 if ( isset( $prop['headitems'] ) || isset( $prop['headhtml'] ) ) {
334 $context = $this->getContext();
335 $context->setTitle( $titleObj );
336 $context->getOutput()->addParserOutputMetadata( $p_result );
337
338 if ( isset( $prop['headitems'] ) ) {
339 $headItems = $this->formatHeadItems( $p_result->getHeadItems() );
340
341 $css = $this->formatCss( $context->getOutput()->buildCssLinksArray() );
342
343 $scripts = array( $context->getOutput()->getHeadScripts() );
344
345 $result_array['headitems'] = array_merge( $headItems, $css, $scripts );
346 }
347
348 if ( isset( $prop['headhtml'] ) ) {
349 $result_array['headhtml'] = array();
350 ApiResult::setContentValue(
351 $result_array['headhtml'],
352 'headhtml',
353 $context->getOutput()->headElement( $context->getSkin() )
354 );
355 }
356 }
357
358 if ( isset( $prop['modules'] ) ) {
359 $result_array['modules'] = array_values( array_unique( $p_result->getModules() ) );
360 $result_array['modulescripts'] = array_values( array_unique( $p_result->getModuleScripts() ) );
361 $result_array['modulestyles'] = array_values( array_unique( $p_result->getModuleStyles() ) );
362 $result_array['modulemessages'] = array_values( array_unique( $p_result->getModuleMessages() ) );
363 }
364
365 if ( isset( $prop['indicators'] ) ) {
366 foreach ( $p_result->getIndicators() as $name => $content ) {
367 $indicator = array( 'name' => $name );
368 ApiResult::setContentValue( $indicator, 'content', $content );
369 $result_array['indicators'][] = $indicator;
370 }
371 }
372
373 if ( isset( $prop['iwlinks'] ) ) {
374 $result_array['iwlinks'] = $this->formatIWLinks( $p_result->getInterwikiLinks() );
375 }
376
377 if ( isset( $prop['wikitext'] ) ) {
378 $result_array['wikitext'] = array();
379 ApiResult::setContentValue( $result_array['wikitext'], 'wikitext', $this->content->serialize( $format ) );
380 if ( !is_null( $this->pstContent ) ) {
381 $result_array['psttext'] = array();
382 ApiResult::setContentValue( $result_array['psttext'], 'psttext', $this->pstContent->serialize( $format ) );
383 }
384 }
385 if ( isset( $prop['properties'] ) ) {
386 $result_array['properties'] = $this->formatProperties( $p_result->getProperties() );
387 }
388
389 if ( isset( $prop['limitreportdata'] ) ) {
390 $result_array['limitreportdata'] =
391 $this->formatLimitReportData( $p_result->getLimitReportData() );
392 }
393 if ( isset( $prop['limitreporthtml'] ) ) {
394 $limitreportHtml = EditPage::getPreviewLimitReport( $p_result );
395 $result_array['limitreporthtml'] = array();
396 ApiResult::setContentValue( $result_array['limitreporthtml'], 'limitreporthtml', $limitreportHtml );
397 }
398
399 if ( $params['generatexml'] ) {
400 if ( $this->content->getModel() != CONTENT_MODEL_WIKITEXT ) {
401 $this->dieUsage( "generatexml is only supported for wikitext content", "notwikitext" );
402 }
403
404 $wgParser->startExternalParse( $titleObj, $popts, Parser::OT_PREPROCESS );
405 $dom = $wgParser->preprocessToDom( $this->content->getNativeData() );
406 if ( is_callable( array( $dom, 'saveXML' ) ) ) {
407 $xml = $dom->saveXML();
408 } else {
409 $xml = $dom->__toString();
410 }
411 $result_array['parsetree'] = array();
412 ApiResult::setContentValue( $result_array['parsetree'], 'parsetree', $xml );
413 }
414
415 $result_mapping = array(
416 'redirects' => 'r',
417 'langlinks' => 'll',
418 'categories' => 'cl',
419 'links' => 'pl',
420 'templates' => 'tl',
421 'images' => 'img',
422 'externallinks' => 'el',
423 'iwlinks' => 'iw',
424 'sections' => 's',
425 'headitems' => 'hi',
426 'modules' => 'm',
427 'indicators' => 'ind',
428 'modulescripts' => 'm',
429 'modulestyles' => 'm',
430 'modulemessages' => 'm',
431 'properties' => 'pp',
432 'limitreportdata' => 'lr',
433 );
434 $this->setIndexedTagNames( $result_array, $result_mapping );
435 $result->addValue( null, $this->getModuleName(), $result_array );
436 }
437
438 /**
439 * Constructs a ParserOptions object
440 *
441 * @param WikiPage $pageObj
442 * @param array $params
443 *
444 * @return ParserOptions
445 */
446 protected function makeParserOptions( WikiPage $pageObj, array $params ) {
447
448 $popts = $pageObj->makeParserOptions( $this->getContext() );
449 $popts->enableLimitReport( !$params['disablepp'] );
450 $popts->setIsPreview( $params['preview'] || $params['sectionpreview'] );
451 $popts->setIsSectionPreview( $params['sectionpreview'] );
452 $popts->setEditSection( !$params['disableeditsection'] );
453
454 return $popts;
455 }
456
457 /**
458 * @param WikiPage $page
459 * @param ParserOptions $popts
460 * @param int $pageId
461 * @param bool $getWikitext
462 * @return ParserOutput
463 */
464 private function getParsedContent( WikiPage $page, $popts, $pageId = null, $getWikitext = false ) {
465 $this->content = $page->getContent( Revision::RAW ); //XXX: really raw?
466
467 if ( $this->section !== false && $this->content !== null ) {
468 $this->content = $this->getSectionContent(
469 $this->content,
470 !is_null( $pageId ) ? 'page id ' . $pageId : $page->getTitle()->getPrefixedText()
471 );
472
473 // Not cached (save or load)
474 return $this->content->getParserOutput( $page->getTitle(), null, $popts );
475 }
476
477 // Try the parser cache first
478 // getParserOutput will save to Parser cache if able
479 $pout = $page->getParserOutput( $popts );
480 if ( !$pout ) {
481 $this->dieUsage( "There is no revision ID {$page->getLatest()}", 'missingrev' );
482 }
483 if ( $getWikitext ) {
484 $this->content = $page->getContent( Revision::RAW );
485 }
486
487 return $pout;
488 }
489
490 /**
491 * @param Content $content
492 * @param string $what Identifies the content in error messages, e.g. page title.
493 * @return Content|bool
494 */
495 private function getSectionContent( Content $content, $what ) {
496 // Not cached (save or load)
497 $section = $content->getSection( $this->section );
498 if ( $section === false ) {
499 $this->dieUsage( "There is no section {$this->section} in " . $what, 'nosuchsection' );
500 }
501 if ( $section === null ) {
502 $this->dieUsage( "Sections are not supported by " . $what, 'nosuchsection' );
503 $section = false;
504 }
505
506 return $section;
507 }
508
509 /**
510 * This mimicks the behavior of EditPage in formatting a summary
511 *
512 * @param Title $title of the page being parsed
513 * @param Array $params the API parameters of the request
514 * @return Content|bool
515 */
516 private function formatSummary( $title, $params ) {
517 global $wgParser;
518 $summary = !is_null( $params['summary'] ) ? $params['summary'] : '';
519 $sectionTitle = !is_null( $params['sectiontitle'] ) ? $params['sectiontitle'] : '';
520
521 if ( $this->section === 'new' && ( $sectionTitle === '' || $summary === '' ) ) {
522 if( $sectionTitle !== '' ) {
523 $summary = $params['sectiontitle'];
524 }
525 if ( $summary !== '' ) {
526 $summary = wfMessage( 'newsectionsummary' )->rawParams( $wgParser->stripSectionName( $summary ) )
527 ->inContentLanguage()->text();
528 }
529 }
530 return Linker::formatComment( $summary, $title, $this->section === 'new' );
531 }
532
533 private function formatLangLinks( $links ) {
534 $result = array();
535 foreach ( $links as $link ) {
536 $entry = array();
537 $bits = explode( ':', $link, 2 );
538 $title = Title::newFromText( $link );
539
540 $entry['lang'] = $bits[0];
541 if ( $title ) {
542 $entry['url'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
543 // localised language name in 'uselang' language
544 $entry['langname'] = Language::fetchLanguageName(
545 $title->getInterwiki(),
546 $this->getLanguage()->getCode()
547 );
548
549 // native language name
550 $entry['autonym'] = Language::fetchLanguageName( $title->getInterwiki() );
551 }
552 ApiResult::setContentValue( $entry, 'title', $bits[1] );
553 $result[] = $entry;
554 }
555
556 return $result;
557 }
558
559 private function formatCategoryLinks( $links ) {
560 $result = array();
561
562 if ( !$links ) {
563 return $result;
564 }
565
566 // Fetch hiddencat property
567 $lb = new LinkBatch;
568 $lb->setArray( array( NS_CATEGORY => $links ) );
569 $db = $this->getDB();
570 $res = $db->select( array( 'page', 'page_props' ),
571 array( 'page_title', 'pp_propname' ),
572 $lb->constructSet( 'page', $db ),
573 __METHOD__,
574 array(),
575 array( 'page_props' => array(
576 'LEFT JOIN', array( 'pp_propname' => 'hiddencat', 'pp_page = page_id' )
577 ) )
578 );
579 $hiddencats = array();
580 foreach ( $res as $row ) {
581 $hiddencats[$row->page_title] = isset( $row->pp_propname );
582 }
583
584 foreach ( $links as $link => $sortkey ) {
585 $entry = array();
586 $entry['sortkey'] = $sortkey;
587 ApiResult::setContentValue( $entry, 'category', $link );
588 if ( !isset( $hiddencats[$link] ) ) {
589 $entry['missing'] = '';
590 } elseif ( $hiddencats[$link] ) {
591 $entry['hidden'] = '';
592 }
593 $result[] = $entry;
594 }
595
596 return $result;
597 }
598
599 private function categoriesHtml( $categories ) {
600 $context = $this->getContext();
601 $context->getOutput()->addCategoryLinks( $categories );
602
603 return $context->getSkin()->getCategories();
604 }
605
606 private function formatLinks( $links ) {
607 $result = array();
608 foreach ( $links as $ns => $nslinks ) {
609 foreach ( $nslinks as $title => $id ) {
610 $entry = array();
611 $entry['ns'] = $ns;
612 ApiResult::setContentValue( $entry, 'title', Title::makeTitle( $ns, $title )->getFullText() );
613 if ( $id != 0 ) {
614 $entry['exists'] = '';
615 }
616 $result[] = $entry;
617 }
618 }
619
620 return $result;
621 }
622
623 private function formatIWLinks( $iw ) {
624 $result = array();
625 foreach ( $iw as $prefix => $titles ) {
626 foreach ( array_keys( $titles ) as $title ) {
627 $entry = array();
628 $entry['prefix'] = $prefix;
629
630 $title = Title::newFromText( "{$prefix}:{$title}" );
631 if ( $title ) {
632 $entry['url'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
633 }
634
635 ApiResult::setContentValue( $entry, 'title', $title->getFullText() );
636 $result[] = $entry;
637 }
638 }
639
640 return $result;
641 }
642
643 private function formatHeadItems( $headItems ) {
644 $result = array();
645 foreach ( $headItems as $tag => $content ) {
646 $entry = array();
647 $entry['tag'] = $tag;
648 ApiResult::setContentValue( $entry, 'content', $content );
649 $result[] = $entry;
650 }
651
652 return $result;
653 }
654
655 private function formatProperties( $properties ) {
656 $result = array();
657 foreach ( $properties as $name => $value ) {
658 $entry = array();
659 $entry['name'] = $name;
660 ApiResult::setContentValue( $entry, 'value', $value );
661 $result[] = $entry;
662 }
663
664 return $result;
665 }
666
667 private function formatCss( $css ) {
668 $result = array();
669 foreach ( $css as $file => $link ) {
670 $entry = array();
671 $entry['file'] = $file;
672 ApiResult::setContentValue( $entry, 'link', $link );
673 $result[] = $entry;
674 }
675
676 return $result;
677 }
678
679 private function formatLimitReportData( $limitReportData ) {
680 $result = array();
681 $apiResult = $this->getResult();
682
683 foreach ( $limitReportData as $name => $value ) {
684 $entry = array();
685 $entry['name'] = $name;
686 if ( !is_array( $value ) ) {
687 $value = array( $value );
688 }
689 ApiResult::setIndexedTagName( $value, 'param' );
690 ApiResult::setIndexedTagNameOnSubarrays( $value, 'param' );
691 $entry = array_merge( $entry, $value );
692 $result[] = $entry;
693 }
694
695 return $result;
696 }
697
698 private function setIndexedTagNames( &$array, $mapping ) {
699 foreach ( $mapping as $key => $name ) {
700 if ( isset( $array[$key] ) ) {
701 ApiResult::setIndexedTagName( $array[$key], $name );
702 }
703 }
704 }
705
706 public function getAllowedParams() {
707 return array(
708 'title' => null,
709 'text' => null,
710 'summary' => null,
711 'page' => null,
712 'pageid' => array(
713 ApiBase::PARAM_TYPE => 'integer',
714 ),
715 'redirects' => false,
716 'oldid' => array(
717 ApiBase::PARAM_TYPE => 'integer',
718 ),
719 'prop' => array(
720 ApiBase::PARAM_DFLT => 'text|langlinks|categories|links|templates|' .
721 'images|externallinks|sections|revid|displaytitle|iwlinks|properties',
722 ApiBase::PARAM_ISMULTI => true,
723 ApiBase::PARAM_TYPE => array(
724 'text',
725 'langlinks',
726 'categories',
727 'categorieshtml',
728 'links',
729 'templates',
730 'images',
731 'externallinks',
732 'sections',
733 'revid',
734 'displaytitle',
735 'headitems',
736 'headhtml',
737 'modules',
738 'indicators',
739 'iwlinks',
740 'wikitext',
741 'properties',
742 'limitreportdata',
743 'limitreporthtml',
744 )
745 ),
746 'pst' => false,
747 'onlypst' => false,
748 'effectivelanglinks' => false,
749 'section' => null,
750 'sectiontitle' => array(
751 ApiBase::PARAM_TYPE => 'string',
752 ),
753 'disablepp' => false,
754 'disableeditsection' => false,
755 'generatexml' => array(
756 ApiBase::PARAM_DFLT => false,
757 ApiBase::PARAM_HELP_MSG => array(
758 'apihelp-parse-param-generatexml', CONTENT_MODEL_WIKITEXT
759 ),
760 ),
761 'preview' => false,
762 'sectionpreview' => false,
763 'disabletoc' => false,
764 'contentformat' => array(
765 ApiBase::PARAM_TYPE => ContentHandler::getAllContentFormats(),
766 ),
767 'contentmodel' => array(
768 ApiBase::PARAM_TYPE => ContentHandler::getContentModels(),
769 )
770 );
771 }
772
773 protected function getExamplesMessages() {
774 return array(
775 'action=parse&page=Project:Sandbox'
776 => 'apihelp-parse-example-page',
777 'action=parse&text={{Project:Sandbox}}&contentmodel=wikitext'
778 => 'apihelp-parse-example-text',
779 'action=parse&text={{PAGENAME}}&title=Test'
780 => 'apihelp-parse-example-texttitle',
781 'action=parse&summary=Some+[[link]]&prop='
782 => 'apihelp-parse-example-summary',
783 );
784 }
785
786 public function getHelpUrls() {
787 return 'https://www.mediawiki.org/wiki/API:Parsing_wikitext#parse';
788 }
789 }