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