Merge "Remove unused 'XMPGetInfo' and 'XMPGetResults' hooks"
[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 // To be removed in 1.27
354 $result_array['modulemessages'] = array();
355 $this->setWarning( 'modulemessages is deprecated since MediaWiki 1.26' );
356 }
357
358 if ( isset( $prop['jsconfigvars'] ) ) {
359 $result_array['jsconfigvars'] = $this->formatJsConfigVars( $p_result->getJsConfigVars() );
360 }
361
362 if ( isset( $prop['encodedjsconfigvars'] ) ) {
363 $result_array['encodedjsconfigvars'] = FormatJson::encode(
364 $p_result->getJsConfigVars(), false, FormatJson::ALL_OK
365 );
366 $result_array[ApiResult::META_SUBELEMENTS][] = 'encodedjsconfigvars';
367 }
368
369 if ( isset( $prop['indicators'] ) ) {
370 $result_array['indicators'] = (array)$p_result->getIndicators();
371 ApiResult::setArrayType( $result_array['indicators'], 'BCkvp', 'name' );
372 }
373
374 if ( isset( $prop['iwlinks'] ) ) {
375 $result_array['iwlinks'] = $this->formatIWLinks( $p_result->getInterwikiLinks() );
376 }
377
378 if ( isset( $prop['wikitext'] ) ) {
379 $result_array['wikitext'] = $this->content->serialize( $format );
380 $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'wikitext';
381 if ( !is_null( $this->pstContent ) ) {
382 $result_array['psttext'] = $this->pstContent->serialize( $format );
383 $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'psttext';
384 }
385 }
386 if ( isset( $prop['properties'] ) ) {
387 $result_array['properties'] = (array)$p_result->getProperties();
388 ApiResult::setArrayType( $result_array['properties'], 'BCkvp', 'name' );
389 }
390
391 if ( isset( $prop['limitreportdata'] ) ) {
392 $result_array['limitreportdata'] =
393 $this->formatLimitReportData( $p_result->getLimitReportData() );
394 }
395 if ( isset( $prop['limitreporthtml'] ) ) {
396 $result_array['limitreporthtml'] = EditPage::getPreviewLimitReport( $p_result );
397 $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'limitreporthtml';
398 }
399
400 if ( $params['generatexml'] ) {
401 if ( $this->content->getModel() != CONTENT_MODEL_WIKITEXT ) {
402 $this->dieUsage( "generatexml is only supported for wikitext content", "notwikitext" );
403 }
404
405 $wgParser->startExternalParse( $titleObj, $popts, Parser::OT_PREPROCESS );
406 $dom = $wgParser->preprocessToDom( $this->content->getNativeData() );
407 if ( is_callable( array( $dom, 'saveXML' ) ) ) {
408 $xml = $dom->saveXML();
409 } else {
410 $xml = $dom->__toString();
411 }
412 $result_array['parsetree'] = $xml;
413 $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'parsetree';
414 }
415
416 $result_mapping = array(
417 'redirects' => 'r',
418 'langlinks' => 'll',
419 'categories' => 'cl',
420 'links' => 'pl',
421 'templates' => 'tl',
422 'images' => 'img',
423 'externallinks' => 'el',
424 'iwlinks' => 'iw',
425 'sections' => 's',
426 'headitems' => 'hi',
427 'modules' => 'm',
428 'indicators' => 'ind',
429 'modulescripts' => 'm',
430 'modulestyles' => 'm',
431 'modulemessages' => 'm',
432 'properties' => 'pp',
433 'limitreportdata' => 'lr',
434 );
435 $this->setIndexedTagNames( $result_array, $result_mapping );
436 $result->addValue( null, $this->getModuleName(), $result_array );
437 }
438
439 /**
440 * Constructs a ParserOptions object
441 *
442 * @param WikiPage $pageObj
443 * @param array $params
444 *
445 * @return ParserOptions
446 */
447 protected function makeParserOptions( WikiPage $pageObj, array $params ) {
448
449 $popts = $pageObj->makeParserOptions( $this->getContext() );
450 $popts->enableLimitReport( !$params['disablepp'] );
451 $popts->setIsPreview( $params['preview'] || $params['sectionpreview'] );
452 $popts->setIsSectionPreview( $params['sectionpreview'] );
453 $popts->setEditSection( !$params['disableeditsection'] );
454
455 return $popts;
456 }
457
458 /**
459 * @param WikiPage $page
460 * @param ParserOptions $popts
461 * @param int $pageId
462 * @param bool $getWikitext
463 * @return ParserOutput
464 */
465 private function getParsedContent( WikiPage $page, $popts, $pageId = null, $getWikitext = false ) {
466 $this->content = $page->getContent( Revision::RAW ); //XXX: really raw?
467
468 if ( $this->section !== false && $this->content !== null ) {
469 $this->content = $this->getSectionContent(
470 $this->content,
471 !is_null( $pageId ) ? 'page id ' . $pageId : $page->getTitle()->getPrefixedText()
472 );
473
474 // Not cached (save or load)
475 return $this->content->getParserOutput( $page->getTitle(), null, $popts );
476 }
477
478 // Try the parser cache first
479 // getParserOutput will save to Parser cache if able
480 $pout = $page->getParserOutput( $popts );
481 if ( !$pout ) {
482 $this->dieUsage( "There is no revision ID {$page->getLatest()}", 'missingrev' );
483 }
484 if ( $getWikitext ) {
485 $this->content = $page->getContent( Revision::RAW );
486 }
487
488 return $pout;
489 }
490
491 /**
492 * @param Content $content
493 * @param string $what Identifies the content in error messages, e.g. page title.
494 * @return Content|bool
495 */
496 private function getSectionContent( Content $content, $what ) {
497 // Not cached (save or load)
498 $section = $content->getSection( $this->section );
499 if ( $section === false ) {
500 $this->dieUsage( "There is no section {$this->section} in " . $what, 'nosuchsection' );
501 }
502 if ( $section === null ) {
503 $this->dieUsage( "Sections are not supported by " . $what, 'nosuchsection' );
504 $section = false;
505 }
506
507 return $section;
508 }
509
510 /**
511 * This mimicks the behavior of EditPage in formatting a summary
512 *
513 * @param Title $title of the page being parsed
514 * @param Array $params the API parameters of the request
515 * @return Content|bool
516 */
517 private function formatSummary( $title, $params ) {
518 global $wgParser;
519 $summary = !is_null( $params['summary'] ) ? $params['summary'] : '';
520 $sectionTitle = !is_null( $params['sectiontitle'] ) ? $params['sectiontitle'] : '';
521
522 if ( $this->section === 'new' && ( $sectionTitle === '' || $summary === '' ) ) {
523 if( $sectionTitle !== '' ) {
524 $summary = $params['sectiontitle'];
525 }
526 if ( $summary !== '' ) {
527 $summary = wfMessage( 'newsectionsummary' )->rawParams( $wgParser->stripSectionName( $summary ) )
528 ->inContentLanguage()->text();
529 }
530 }
531 return Linker::formatComment( $summary, $title, $this->section === 'new' );
532 }
533
534 private function formatLangLinks( $links ) {
535 $result = array();
536 foreach ( $links as $link ) {
537 $entry = array();
538 $bits = explode( ':', $link, 2 );
539 $title = Title::newFromText( $link );
540
541 $entry['lang'] = $bits[0];
542 if ( $title ) {
543 $entry['url'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
544 // localised language name in 'uselang' language
545 $entry['langname'] = Language::fetchLanguageName(
546 $title->getInterwiki(),
547 $this->getLanguage()->getCode()
548 );
549
550 // native language name
551 $entry['autonym'] = Language::fetchLanguageName( $title->getInterwiki() );
552 }
553 ApiResult::setContentValue( $entry, 'title', $bits[1] );
554 $result[] = $entry;
555 }
556
557 return $result;
558 }
559
560 private function formatCategoryLinks( $links ) {
561 $result = array();
562
563 if ( !$links ) {
564 return $result;
565 }
566
567 // Fetch hiddencat property
568 $lb = new LinkBatch;
569 $lb->setArray( array( NS_CATEGORY => $links ) );
570 $db = $this->getDB();
571 $res = $db->select( array( 'page', 'page_props' ),
572 array( 'page_title', 'pp_propname' ),
573 $lb->constructSet( 'page', $db ),
574 __METHOD__,
575 array(),
576 array( 'page_props' => array(
577 'LEFT JOIN', array( 'pp_propname' => 'hiddencat', 'pp_page = page_id' )
578 ) )
579 );
580 $hiddencats = array();
581 foreach ( $res as $row ) {
582 $hiddencats[$row->page_title] = isset( $row->pp_propname );
583 }
584
585 foreach ( $links as $link => $sortkey ) {
586 $entry = array();
587 $entry['sortkey'] = $sortkey;
588 ApiResult::setContentValue( $entry, 'category', $link );
589 if ( !isset( $hiddencats[$link] ) ) {
590 $entry['missing'] = true;
591 } elseif ( $hiddencats[$link] ) {
592 $entry['hidden'] = true;
593 }
594 $result[] = $entry;
595 }
596
597 return $result;
598 }
599
600 private function categoriesHtml( $categories ) {
601 $context = $this->getContext();
602 $context->getOutput()->addCategoryLinks( $categories );
603
604 return $context->getSkin()->getCategories();
605 }
606
607 private function formatLinks( $links ) {
608 $result = array();
609 foreach ( $links as $ns => $nslinks ) {
610 foreach ( $nslinks as $title => $id ) {
611 $entry = array();
612 $entry['ns'] = $ns;
613 ApiResult::setContentValue( $entry, 'title', Title::makeTitle( $ns, $title )->getFullText() );
614 $entry['exists'] = $id != 0;
615 $result[] = $entry;
616 }
617 }
618
619 return $result;
620 }
621
622 private function formatIWLinks( $iw ) {
623 $result = array();
624 foreach ( $iw as $prefix => $titles ) {
625 foreach ( array_keys( $titles ) as $title ) {
626 $entry = array();
627 $entry['prefix'] = $prefix;
628
629 $title = Title::newFromText( "{$prefix}:{$title}" );
630 if ( $title ) {
631 $entry['url'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
632 }
633
634 ApiResult::setContentValue( $entry, 'title', $title->getFullText() );
635 $result[] = $entry;
636 }
637 }
638
639 return $result;
640 }
641
642 private function formatHeadItems( $headItems ) {
643 $result = array();
644 foreach ( $headItems as $tag => $content ) {
645 $entry = array();
646 $entry['tag'] = $tag;
647 ApiResult::setContentValue( $entry, 'content', $content );
648 $result[] = $entry;
649 }
650
651 return $result;
652 }
653
654 private function formatCss( $css ) {
655 $result = array();
656 foreach ( $css as $file => $link ) {
657 $entry = array();
658 $entry['file'] = $file;
659 ApiResult::setContentValue( $entry, 'link', $link );
660 $result[] = $entry;
661 }
662
663 return $result;
664 }
665
666 private function formatLimitReportData( $limitReportData ) {
667 $result = array();
668 $apiResult = $this->getResult();
669
670 foreach ( $limitReportData as $name => $value ) {
671 $entry = array();
672 $entry['name'] = $name;
673 if ( !is_array( $value ) ) {
674 $value = array( $value );
675 }
676 ApiResult::setIndexedTagNameRecursive( $value, 'param' );
677 $entry = array_merge( $entry, $value );
678 $result[] = $entry;
679 }
680
681 return $result;
682 }
683
684 private function formatJsConfigVars( $vars, $forceHash = true ) {
685 // Process subarrays and determine if this is a JS [] or {}
686 $hash = $forceHash;
687 $maxKey = -1;
688 $bools = array();
689 foreach ( $vars as $k => $v ) {
690 if ( is_array( $v ) || is_object( $v ) ) {
691 $vars[$k] = $this->formatJsConfigVars( (array)$v, false );
692 } elseif ( is_bool( $v ) ) {
693 // Better here to use real bools even in BC formats
694 $bools[] = $k;
695 }
696 if ( is_string( $k ) ) {
697 $hash = true;
698 } elseif ( $k > $maxKey ) {
699 $maxKey = $k;
700 }
701 }
702 if ( !$hash && $maxKey !== count( $vars ) - 1 ) {
703 $hash = true;
704 }
705
706 // Get the list of keys we actually care about. Unfortunately, we can't support
707 // certain keys that conflict with ApiResult metadata.
708 $keys = array_diff( array_keys( $vars ), array(
709 ApiResult::META_TYPE, ApiResult::META_PRESERVE_KEYS, ApiResult::META_KVP_KEY_NAME,
710 ApiResult::META_INDEXED_TAG_NAME, ApiResult::META_BC_BOOLS
711 ) );
712
713 // Set metadata appropriately
714 if ( $hash ) {
715 return array(
716 ApiResult::META_TYPE => 'kvp',
717 ApiResult::META_KVP_KEY_NAME => 'key',
718 ApiResult::META_PRESERVE_KEYS => $keys,
719 ApiResult::META_BC_BOOLS => $bools,
720 ApiResult::META_INDEXED_TAG_NAME => 'var',
721 ) + $vars;
722 } else {
723 return array(
724 ApiResult::META_TYPE => 'array',
725 ApiResult::META_BC_BOOLS => $bools,
726 ApiResult::META_INDEXED_TAG_NAME => 'value',
727 ) + $vars;
728 }
729 }
730
731 private function setIndexedTagNames( &$array, $mapping ) {
732 foreach ( $mapping as $key => $name ) {
733 if ( isset( $array[$key] ) ) {
734 ApiResult::setIndexedTagName( $array[$key], $name );
735 }
736 }
737 }
738
739 public function getAllowedParams() {
740 return array(
741 'title' => null,
742 'text' => null,
743 'summary' => null,
744 'page' => null,
745 'pageid' => array(
746 ApiBase::PARAM_TYPE => 'integer',
747 ),
748 'redirects' => false,
749 'oldid' => array(
750 ApiBase::PARAM_TYPE => 'integer',
751 ),
752 'prop' => array(
753 ApiBase::PARAM_DFLT => 'text|langlinks|categories|links|templates|' .
754 'images|externallinks|sections|revid|displaytitle|iwlinks|properties',
755 ApiBase::PARAM_ISMULTI => true,
756 ApiBase::PARAM_TYPE => array(
757 'text',
758 'langlinks',
759 'categories',
760 'categorieshtml',
761 'links',
762 'templates',
763 'images',
764 'externallinks',
765 'sections',
766 'revid',
767 'displaytitle',
768 'headitems',
769 'headhtml',
770 'modules',
771 'jsconfigvars',
772 'encodedjsconfigvars',
773 'indicators',
774 'iwlinks',
775 'wikitext',
776 'properties',
777 'limitreportdata',
778 'limitreporthtml',
779 ),
780 ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
781 ),
782 'pst' => false,
783 'onlypst' => false,
784 'effectivelanglinks' => false,
785 'section' => null,
786 'sectiontitle' => array(
787 ApiBase::PARAM_TYPE => 'string',
788 ),
789 'disablepp' => false,
790 'disableeditsection' => false,
791 'generatexml' => array(
792 ApiBase::PARAM_DFLT => false,
793 ApiBase::PARAM_HELP_MSG => array(
794 'apihelp-parse-param-generatexml', CONTENT_MODEL_WIKITEXT
795 ),
796 ),
797 'preview' => false,
798 'sectionpreview' => false,
799 'disabletoc' => false,
800 'contentformat' => array(
801 ApiBase::PARAM_TYPE => ContentHandler::getAllContentFormats(),
802 ),
803 'contentmodel' => array(
804 ApiBase::PARAM_TYPE => ContentHandler::getContentModels(),
805 )
806 );
807 }
808
809 protected function getExamplesMessages() {
810 return array(
811 'action=parse&page=Project:Sandbox'
812 => 'apihelp-parse-example-page',
813 'action=parse&text={{Project:Sandbox}}&contentmodel=wikitext'
814 => 'apihelp-parse-example-text',
815 'action=parse&text={{PAGENAME}}&title=Test'
816 => 'apihelp-parse-example-texttitle',
817 'action=parse&summary=Some+[[link]]&prop='
818 => 'apihelp-parse-example-summary',
819 );
820 }
821
822 public function getHelpUrls() {
823 return 'https://www.mediawiki.org/wiki/API:Parsing_wikitext#parse';
824 }
825 }