1833434e3267bfc185c5879d864f3f2ea81f0df3
[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 ( $params['generatexml'] ) {
414 if ( $this->content->getModel() != CONTENT_MODEL_WIKITEXT ) {
415 $this->dieUsage( "generatexml is only supported for wikitext content", "notwikitext" );
416 }
417
418 $wgParser->startExternalParse( $titleObj, $popts, Parser::OT_PREPROCESS );
419 $dom = $wgParser->preprocessToDom( $this->content->getNativeData() );
420 if ( is_callable( array( $dom, 'saveXML' ) ) ) {
421 $xml = $dom->saveXML();
422 } else {
423 $xml = $dom->__toString();
424 }
425 $result_array['parsetree'] = $xml;
426 $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'parsetree';
427 }
428
429 $result_mapping = array(
430 'redirects' => 'r',
431 'langlinks' => 'll',
432 'categories' => 'cl',
433 'links' => 'pl',
434 'templates' => 'tl',
435 'images' => 'img',
436 'externallinks' => 'el',
437 'iwlinks' => 'iw',
438 'sections' => 's',
439 'headitems' => 'hi',
440 'modules' => 'm',
441 'indicators' => 'ind',
442 'modulescripts' => 'm',
443 'modulestyles' => 'm',
444 'modulemessages' => 'm',
445 'properties' => 'pp',
446 'limitreportdata' => 'lr',
447 );
448 $this->setIndexedTagNames( $result_array, $result_mapping );
449 $result->addValue( null, $this->getModuleName(), $result_array );
450 }
451
452 /**
453 * Constructs a ParserOptions object
454 *
455 * @param WikiPage $pageObj
456 * @param array $params
457 *
458 * @return ParserOptions
459 */
460 protected function makeParserOptions( WikiPage $pageObj, array $params ) {
461
462 $popts = $pageObj->makeParserOptions( $this->getContext() );
463 $popts->enableLimitReport( !$params['disablepp'] );
464 $popts->setIsPreview( $params['preview'] || $params['sectionpreview'] );
465 $popts->setIsSectionPreview( $params['sectionpreview'] );
466 $popts->setEditSection( !$params['disableeditsection'] );
467
468 return $popts;
469 }
470
471 /**
472 * @param WikiPage $page
473 * @param ParserOptions $popts
474 * @param int $pageId
475 * @param bool $getWikitext
476 * @return ParserOutput
477 */
478 private function getParsedContent( WikiPage $page, $popts, $pageId = null, $getWikitext = false ) {
479 $this->content = $page->getContent( Revision::RAW ); //XXX: really raw?
480
481 if ( $this->section !== false && $this->content !== null ) {
482 $this->content = $this->getSectionContent(
483 $this->content,
484 !is_null( $pageId ) ? 'page id ' . $pageId : $page->getTitle()->getPrefixedText()
485 );
486
487 // Not cached (save or load)
488 return $this->content->getParserOutput( $page->getTitle(), null, $popts );
489 }
490
491 // Try the parser cache first
492 // getParserOutput will save to Parser cache if able
493 $pout = $page->getParserOutput( $popts );
494 if ( !$pout ) {
495 $this->dieUsage( "There is no revision ID {$page->getLatest()}", 'missingrev' );
496 }
497 if ( $getWikitext ) {
498 $this->content = $page->getContent( Revision::RAW );
499 }
500
501 return $pout;
502 }
503
504 /**
505 * @param Content $content
506 * @param string $what Identifies the content in error messages, e.g. page title.
507 * @return Content|bool
508 */
509 private function getSectionContent( Content $content, $what ) {
510 // Not cached (save or load)
511 $section = $content->getSection( $this->section );
512 if ( $section === false ) {
513 $this->dieUsage( "There is no section {$this->section} in " . $what, 'nosuchsection' );
514 }
515 if ( $section === null ) {
516 $this->dieUsage( "Sections are not supported by " . $what, 'nosuchsection' );
517 $section = false;
518 }
519
520 return $section;
521 }
522
523 /**
524 * This mimicks the behavior of EditPage in formatting a summary
525 *
526 * @param Title $title of the page being parsed
527 * @param Array $params the API parameters of the request
528 * @return Content|bool
529 */
530 private function formatSummary( $title, $params ) {
531 global $wgParser;
532 $summary = !is_null( $params['summary'] ) ? $params['summary'] : '';
533 $sectionTitle = !is_null( $params['sectiontitle'] ) ? $params['sectiontitle'] : '';
534
535 if ( $this->section === 'new' && ( $sectionTitle === '' || $summary === '' ) ) {
536 if ( $sectionTitle !== '' ) {
537 $summary = $params['sectiontitle'];
538 }
539 if ( $summary !== '' ) {
540 $summary = wfMessage( 'newsectionsummary' )
541 ->rawParams( $wgParser->stripSectionName( $summary ) )
542 ->inContentLanguage()->text();
543 }
544 }
545 return Linker::formatComment( $summary, $title, $this->section === 'new' );
546 }
547
548 private function formatLangLinks( $links ) {
549 $result = array();
550 foreach ( $links as $link ) {
551 $entry = array();
552 $bits = explode( ':', $link, 2 );
553 $title = Title::newFromText( $link );
554
555 $entry['lang'] = $bits[0];
556 if ( $title ) {
557 $entry['url'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
558 // localised language name in 'uselang' language
559 $entry['langname'] = Language::fetchLanguageName(
560 $title->getInterwiki(),
561 $this->getLanguage()->getCode()
562 );
563
564 // native language name
565 $entry['autonym'] = Language::fetchLanguageName( $title->getInterwiki() );
566 }
567 ApiResult::setContentValue( $entry, 'title', $bits[1] );
568 $result[] = $entry;
569 }
570
571 return $result;
572 }
573
574 private function formatCategoryLinks( $links ) {
575 $result = array();
576
577 if ( !$links ) {
578 return $result;
579 }
580
581 // Fetch hiddencat property
582 $lb = new LinkBatch;
583 $lb->setArray( array( NS_CATEGORY => $links ) );
584 $db = $this->getDB();
585 $res = $db->select( array( 'page', 'page_props' ),
586 array( 'page_title', 'pp_propname' ),
587 $lb->constructSet( 'page', $db ),
588 __METHOD__,
589 array(),
590 array( 'page_props' => array(
591 'LEFT JOIN', array( 'pp_propname' => 'hiddencat', 'pp_page = page_id' )
592 ) )
593 );
594 $hiddencats = array();
595 foreach ( $res as $row ) {
596 $hiddencats[$row->page_title] = isset( $row->pp_propname );
597 }
598
599 foreach ( $links as $link => $sortkey ) {
600 $entry = array();
601 $entry['sortkey'] = $sortkey;
602 ApiResult::setContentValue( $entry, 'category', $link );
603 if ( !isset( $hiddencats[$link] ) ) {
604 $entry['missing'] = true;
605 } elseif ( $hiddencats[$link] ) {
606 $entry['hidden'] = true;
607 }
608 $result[] = $entry;
609 }
610
611 return $result;
612 }
613
614 private function categoriesHtml( $categories ) {
615 $context = $this->getContext();
616 $context->getOutput()->addCategoryLinks( $categories );
617
618 return $context->getSkin()->getCategories();
619 }
620
621 private function formatLinks( $links ) {
622 $result = array();
623 foreach ( $links as $ns => $nslinks ) {
624 foreach ( $nslinks as $title => $id ) {
625 $entry = array();
626 $entry['ns'] = $ns;
627 ApiResult::setContentValue( $entry, 'title', Title::makeTitle( $ns, $title )->getFullText() );
628 $entry['exists'] = $id != 0;
629 $result[] = $entry;
630 }
631 }
632
633 return $result;
634 }
635
636 private function formatIWLinks( $iw ) {
637 $result = array();
638 foreach ( $iw as $prefix => $titles ) {
639 foreach ( array_keys( $titles ) as $title ) {
640 $entry = array();
641 $entry['prefix'] = $prefix;
642
643 $title = Title::newFromText( "{$prefix}:{$title}" );
644 if ( $title ) {
645 $entry['url'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
646 }
647
648 ApiResult::setContentValue( $entry, 'title', $title->getFullText() );
649 $result[] = $entry;
650 }
651 }
652
653 return $result;
654 }
655
656 private function formatHeadItems( $headItems ) {
657 $result = array();
658 foreach ( $headItems as $tag => $content ) {
659 $entry = array();
660 $entry['tag'] = $tag;
661 ApiResult::setContentValue( $entry, 'content', $content );
662 $result[] = $entry;
663 }
664
665 return $result;
666 }
667
668 private function formatCss( $css ) {
669 $result = array();
670 foreach ( $css as $file => $link ) {
671 $entry = array();
672 $entry['file'] = $file;
673 ApiResult::setContentValue( $entry, 'link', $link );
674 $result[] = $entry;
675 }
676
677 return $result;
678 }
679
680 private function formatLimitReportData( $limitReportData ) {
681 $result = array();
682 $apiResult = $this->getResult();
683
684 foreach ( $limitReportData as $name => $value ) {
685 $entry = array();
686 $entry['name'] = $name;
687 if ( !is_array( $value ) ) {
688 $value = array( $value );
689 }
690 ApiResult::setIndexedTagNameRecursive( $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' => array(
710 ApiBase::PARAM_TYPE => 'text',
711 ),
712 'summary' => null,
713 'page' => null,
714 'pageid' => array(
715 ApiBase::PARAM_TYPE => 'integer',
716 ),
717 'redirects' => false,
718 'oldid' => array(
719 ApiBase::PARAM_TYPE => 'integer',
720 ),
721 'prop' => array(
722 ApiBase::PARAM_DFLT => 'text|langlinks|categories|links|templates|' .
723 'images|externallinks|sections|revid|displaytitle|iwlinks|properties',
724 ApiBase::PARAM_ISMULTI => true,
725 ApiBase::PARAM_TYPE => array(
726 'text',
727 'langlinks',
728 'categories',
729 'categorieshtml',
730 'links',
731 'templates',
732 'images',
733 'externallinks',
734 'sections',
735 'revid',
736 'displaytitle',
737 'headitems',
738 'headhtml',
739 'modules',
740 'jsconfigvars',
741 'encodedjsconfigvars',
742 'indicators',
743 'iwlinks',
744 'wikitext',
745 'properties',
746 'limitreportdata',
747 'limitreporthtml',
748 ),
749 ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
750 ),
751 'pst' => false,
752 'onlypst' => false,
753 'effectivelanglinks' => false,
754 'section' => null,
755 'sectiontitle' => array(
756 ApiBase::PARAM_TYPE => 'string',
757 ),
758 'disablepp' => false,
759 'disableeditsection' => false,
760 'generatexml' => array(
761 ApiBase::PARAM_DFLT => false,
762 ApiBase::PARAM_HELP_MSG => array(
763 'apihelp-parse-param-generatexml', CONTENT_MODEL_WIKITEXT
764 ),
765 ),
766 'preview' => false,
767 'sectionpreview' => false,
768 'disabletoc' => false,
769 'contentformat' => array(
770 ApiBase::PARAM_TYPE => ContentHandler::getAllContentFormats(),
771 ),
772 'contentmodel' => array(
773 ApiBase::PARAM_TYPE => ContentHandler::getContentModels(),
774 )
775 );
776 }
777
778 protected function getExamplesMessages() {
779 return array(
780 'action=parse&page=Project:Sandbox'
781 => 'apihelp-parse-example-page',
782 'action=parse&text={{Project:Sandbox}}&contentmodel=wikitext'
783 => 'apihelp-parse-example-text',
784 'action=parse&text={{PAGENAME}}&title=Test'
785 => 'apihelp-parse-example-texttitle',
786 'action=parse&summary=Some+[[link]]&prop='
787 => 'apihelp-parse-example-summary',
788 );
789 }
790
791 public function getHelpUrls() {
792 return 'https://www.mediawiki.org/wiki/API:Parsing_wikitext#parse';
793 }
794 }