MediaWiki  master
ApiExpandTemplates.php
Go to the documentation of this file.
1 <?php
25 
33 class ApiExpandTemplates extends ApiBase {
35  private $revisionStore;
36 
38  private $parser;
39 
46  public function __construct(
47  ApiMain $main,
48  $action,
49  RevisionStore $revisionStore,
50  Parser $parser
51  ) {
52  parent::__construct( $main, $action );
53  $this->revisionStore = $revisionStore;
54  $this->parser = $parser;
55  }
56 
57  public function execute() {
58  // Cache may vary on the user because ParserOptions gets data from it
59  $this->getMain()->setCacheMode( 'anon-public-user-private' );
60 
61  // Get parameters
62  $params = $this->extractRequestParams();
63  $this->requireMaxOneParameter( $params, 'prop', 'generatexml' );
64 
65  $title = $params['title'];
66  if ( $title === null ) {
67  $titleProvided = false;
68  // A title is needed for parsing, so arbitrarily choose one
69  $title = 'API';
70  } else {
71  $titleProvided = true;
72  }
73 
74  if ( $params['prop'] === null ) {
75  $this->addDeprecation(
76  [ 'apiwarn-deprecation-missingparam', 'prop' ], 'action=expandtemplates&!prop'
77  );
78  $prop = [];
79  } else {
80  $prop = array_fill_keys( $params['prop'], true );
81  }
82 
83  $titleObj = Title::newFromText( $title );
84  if ( !$titleObj || $titleObj->isExternal() ) {
85  $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ] );
86  }
87 
88  // Get title and revision ID for parser
89  $revid = $params['revid'];
90  if ( $revid !== null ) {
91  $rev = $this->revisionStore->getRevisionById( $revid );
92  if ( !$rev ) {
93  $this->dieWithError( [ 'apierror-nosuchrevid', $revid ] );
94  }
95  $pTitleObj = $titleObj;
96  $titleObj = Title::newFromLinkTarget( $rev->getPageAsLinkTarget() );
97  if ( $titleProvided && !$titleObj->equals( $pTitleObj ) ) {
98  $this->addWarning( [ 'apierror-revwrongpage', $rev->getId(),
99  wfEscapeWikiText( $pTitleObj->getPrefixedText() ) ] );
100  }
101  }
102 
103  $result = $this->getResult();
104 
105  // Parse text
106  $options = ParserOptions::newFromContext( $this->getContext() );
107 
108  if ( $params['includecomments'] ) {
109  $options->setRemoveComments( false );
110  }
111 
112  $reset = null;
113  $suppressCache = false;
114  $this->getHookRunner()->onApiMakeParserOptions(
115  $options, $titleObj, $params, $this, $reset, $suppressCache );
116 
117  $retval = [];
118 
119  if ( isset( $prop['parsetree'] ) || $params['generatexml'] ) {
120  $this->parser->startExternalParse( $titleObj, $options, Parser::OT_PREPROCESS );
121  $dom = $this->parser->preprocessToDom( $params['text'] );
122  if ( is_callable( [ $dom, 'saveXML' ] ) ) {
123  // @phan-suppress-next-line PhanUndeclaredMethod
124  $xml = $dom->saveXML();
125  } else {
126  // @phan-suppress-next-line PhanUndeclaredMethod
127  $xml = $dom->__toString();
128  }
129  if ( isset( $prop['parsetree'] ) ) {
130  unset( $prop['parsetree'] );
131  $retval['parsetree'] = $xml;
132  } else {
133  // the old way
134  $result->addValue( null, 'parsetree', $xml );
135  $result->addValue( null, ApiResult::META_BC_SUBELEMENTS, [ 'parsetree' ] );
136  }
137  }
138 
139  // if they didn't want any output except (probably) the parse tree,
140  // then don't bother actually fully expanding it
141  if ( $prop || $params['prop'] === null ) {
142  $this->parser->startExternalParse( $titleObj, $options, Parser::OT_PREPROCESS );
143  $frame = $this->parser->getPreprocessor()->newFrame();
144  $wikitext = $this->parser->preprocess( $params['text'], $titleObj, $options, $revid, $frame );
145  if ( $params['prop'] === null ) {
146  // the old way
147  ApiResult::setContentValue( $retval, 'wikitext', $wikitext );
148  } else {
149  $p_output = $this->parser->getOutput();
150  if ( isset( $prop['categories'] ) ) {
151  $categories = $p_output->getCategories();
152  if ( $categories ) {
153  $categories_result = [];
154  foreach ( $categories as $category => $sortkey ) {
155  $entry = [];
156  $entry['sortkey'] = $sortkey;
157  ApiResult::setContentValue( $entry, 'category', (string)$category );
158  $categories_result[] = $entry;
159  }
160  ApiResult::setIndexedTagName( $categories_result, 'category' );
161  $retval['categories'] = $categories_result;
162  }
163  }
164  if ( isset( $prop['properties'] ) ) {
165  $properties = $p_output->getPageProperties();
166  if ( $properties ) {
167  ApiResult::setArrayType( $properties, 'BCkvp', 'name' );
168  ApiResult::setIndexedTagName( $properties, 'property' );
169  $retval['properties'] = $properties;
170  }
171  }
172  if ( isset( $prop['volatile'] ) ) {
173  $retval['volatile'] = $frame->isVolatile();
174  }
175  if ( isset( $prop['ttl'] ) && $frame->getTTL() !== null ) {
176  $retval['ttl'] = $frame->getTTL();
177  }
178  if ( isset( $prop['wikitext'] ) ) {
179  $retval['wikitext'] = $wikitext;
180  }
181  if ( isset( $prop['modules'] ) ) {
182  $retval['modules'] = array_values( array_unique( $p_output->getModules() ) );
183  // Deprecated since 1.32 (T188689)
184  $retval['modulescripts'] = [];
185  $retval['modulestyles'] = array_values( array_unique( $p_output->getModuleStyles() ) );
186  }
187  if ( isset( $prop['jsconfigvars'] ) ) {
188  $showStrategyKeys = (bool)( $params['showstrategykeys'] );
189  $retval['jsconfigvars'] =
190  ApiResult::addMetadataToResultVars( $p_output->getJsConfigVars( $showStrategyKeys ) );
191  }
192  if ( isset( $prop['encodedjsconfigvars'] ) ) {
193  $retval['encodedjsconfigvars'] = FormatJson::encode(
194  $p_output->getJsConfigVars(), false, FormatJson::ALL_OK
195  );
196  $retval[ApiResult::META_SUBELEMENTS][] = 'encodedjsconfigvars';
197  }
198  if ( isset( $prop['modules'] ) &&
199  !isset( $prop['jsconfigvars'] ) && !isset( $prop['encodedjsconfigvars'] ) ) {
200  $this->addWarning( 'apiwarn-moduleswithoutvars' );
201  }
202  }
203  }
204  ApiResult::setSubelementsList( $retval, [ 'wikitext', 'parsetree' ] );
205  $result->addValue( null, $this->getModuleName(), $retval );
206  }
207 
208  public function getAllowedParams() {
209  return [
210  'title' => null,
211  'text' => [
212  ParamValidator::PARAM_TYPE => 'text',
213  ParamValidator::PARAM_REQUIRED => true,
214  ],
215  'revid' => [
216  ParamValidator::PARAM_TYPE => 'integer',
217  ],
218  'prop' => [
219  ParamValidator::PARAM_TYPE => [
220  'wikitext',
221  'categories',
222  'properties',
223  'volatile',
224  'ttl',
225  'modules',
226  'jsconfigvars',
227  'encodedjsconfigvars',
228  'parsetree',
229  ],
230  ParamValidator::PARAM_ISMULTI => true,
232  ],
233  'includecomments' => false,
234  'showstrategykeys' => false,
235  'generatexml' => [
236  ParamValidator::PARAM_TYPE => 'boolean',
237  ParamValidator::PARAM_DEPRECATED => true,
238  ],
239  ];
240  }
241 
242  protected function getExamplesMessages() {
243  return [
244  'action=expandtemplates&text={{Project:Sandbox}}'
245  => 'apihelp-expandtemplates-example-simple',
246  ];
247  }
248 
249  public function getHelpUrls() {
250  return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Parsing_wikitext#expandtemplates';
251  }
252 }
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
This abstract class implements many basic API functions, and is the base of all API classes.
Definition: ApiBase.php:56
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
Definition: ApiBase.php:1453
getMain()
Get the main module.
Definition: ApiBase.php:514
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, this is an array mapping those values to $msg...
Definition: ApiBase.php:196
addDeprecation( $msg, $feature, $data=[])
Add a deprecation warning for this module.
Definition: ApiBase.php:1385
requireMaxOneParameter( $params,... $required)
Die if more than one of a certain set of parameters is set and not false.
Definition: ApiBase.php:938
getResult()
Get the result object.
Definition: ApiBase.php:629
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:765
addWarning( $msg, $code=null, $data=null)
Add a warning for this module.
Definition: ApiBase.php:1371
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:498
getHookRunner()
Get an ApiHookRunner for running core API hooks.
Definition: ApiBase.php:711
API module that functions as a shortcut to the wikitext preprocessor.
getExamplesMessages()
Returns usage examples for this module.
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
__construct(ApiMain $main, $action, RevisionStore $revisionStore, Parser $parser)
getHelpUrls()
Return links to more detailed help pages about the module.
This is the main API class, used for both external and internal processing.
Definition: ApiMain.php:52
static setArrayType(array &$arr, $type, $kvpKeyName=null)
Set the array data type.
Definition: ApiResult.php:716
static addMetadataToResultVars( $vars, $forceHash=true)
Add the correct metadata to an array of vars we want to export through the API.
Definition: ApiResult.php:1144
const META_SUBELEMENTS
Key for the 'subelements' metadata item.
Definition: ApiResult.php:78
static setSubelementsList(array &$arr, $names)
Causes the elements with the specified names to be output as subelements rather than attributes.
Definition: ApiResult.php:553
const META_BC_SUBELEMENTS
Key for the 'BC subelements' metadata item.
Definition: ApiResult.php:143
static setIndexedTagName(array &$arr, $tag)
Set the tag name for numeric-keyed values in XML format.
Definition: ApiResult.php:604
static setContentValue(array &$arr, $name, $value, $flags=0)
Add an output value to the array by name and mark as META_CONTENT.
Definition: ApiResult.php:467
getContext()
Get the base IContextSource object.
static encode( $value, $pretty=false, $escaping=0)
Returns the JSON representation of a value.
Definition: FormatJson.php:96
const ALL_OK
Skip escaping as many characters as reasonably possible.
Definition: FormatJson.php:55
Service for looking up page revisions.
static newFromContext(IContextSource $context)
Get a ParserOptions object from a IContextSource object.
PHP Parser - Processes wiki markup (which uses a more user-friendly syntax, such as "[[link]]" for ma...
Definition: Parser.php:95
const OT_PREPROCESS
Definition: Parser.php:130
static newFromLinkTarget(LinkTarget $linkTarget, $forceClone='')
Returns a Title given a LinkTarget.
Definition: Title.php:282
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:370
Service for formatting and validating API parameters.