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