MediaWiki  master
ApiExpandTemplates.php
Go to the documentation of this file.
1 <?php
26 
34 class ApiExpandTemplates extends ApiBase {
35  private RevisionStore $revisionStore;
36  private ParserFactory $parserFactory;
37 
44  public function __construct(
45  ApiMain $main,
46  $action,
47  RevisionStore $revisionStore,
48  ParserFactory $parserFactory
49  ) {
50  parent::__construct( $main, $action );
51  $this->revisionStore = $revisionStore;
52  $this->parserFactory = $parserFactory;
53  }
54 
55  public function execute() {
56  // Cache may vary on the user because ParserOptions gets data from it
57  $this->getMain()->setCacheMode( 'anon-public-user-private' );
58 
59  // Get parameters
60  $params = $this->extractRequestParams();
61  $this->requireMaxOneParameter( $params, 'prop', 'generatexml' );
62 
63  $title = $params['title'];
64  if ( $title === null ) {
65  $titleProvided = false;
66  // A title is needed for parsing, so arbitrarily choose one
67  $title = 'API';
68  } else {
69  $titleProvided = true;
70  }
71 
72  if ( $params['prop'] === null ) {
73  $this->addDeprecation(
74  [ 'apiwarn-deprecation-missingparam', 'prop' ], 'action=expandtemplates&!prop'
75  );
76  $prop = [];
77  } else {
78  $prop = array_fill_keys( $params['prop'], true );
79  }
80 
81  $titleObj = Title::newFromText( $title );
82  if ( !$titleObj || $titleObj->isExternal() ) {
83  $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ] );
84  }
85 
86  // Get title and revision ID for parser
87  $revid = $params['revid'];
88  if ( $revid !== null ) {
89  $rev = $this->revisionStore->getRevisionById( $revid );
90  if ( !$rev ) {
91  $this->dieWithError( [ 'apierror-nosuchrevid', $revid ] );
92  }
93  $pTitleObj = $titleObj;
94  $titleObj = Title::newFromLinkTarget( $rev->getPageAsLinkTarget() );
95  if ( $titleProvided && !$titleObj->equals( $pTitleObj ) ) {
96  $this->addWarning( [ 'apierror-revwrongpage', $rev->getId(),
97  wfEscapeWikiText( $pTitleObj->getPrefixedText() ) ] );
98  }
99  }
100 
101  $result = $this->getResult();
102 
103  // Parse text
104  $options = ParserOptions::newFromContext( $this->getContext() );
105 
106  if ( $params['includecomments'] ) {
107  $options->setRemoveComments( false );
108  }
109 
110  $reset = null;
111  $suppressCache = false;
112  $this->getHookRunner()->onApiMakeParserOptions(
113  $options, $titleObj, $params, $this, $reset, $suppressCache );
114 
115  $retval = [];
116 
117  if ( isset( $prop['parsetree'] ) || $params['generatexml'] ) {
118  $parser = $this->parserFactory->getInstance();
119  $parser->startExternalParse( $titleObj, $options, Parser::OT_PREPROCESS );
120  $dom = $parser->preprocessToDom( $params['text'] );
121  // @phan-suppress-next-line PhanUndeclaredMethodInCallable
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  $parser = $this->parserFactory->getInstance();
143  $parser->startExternalParse( $titleObj, $options, Parser::OT_PREPROCESS );
144  $frame = $parser->getPreprocessor()->newFrame();
145  $wikitext = $parser->preprocess( $params['text'], $titleObj, $options, $revid, $frame );
146  if ( $params['prop'] === null ) {
147  // the old way
148  ApiResult::setContentValue( $retval, 'wikitext', $wikitext );
149  } else {
150  $p_output = $parser->getOutput();
151  if ( isset( $prop['categories'] ) ) {
152  $categories = $p_output->getCategories();
153  if ( $categories ) {
154  $categories_result = [];
155  foreach ( $categories as $category => $sortkey ) {
156  $entry = [];
157  $entry['sortkey'] = $sortkey;
158  ApiResult::setContentValue( $entry, 'category', (string)$category );
159  $categories_result[] = $entry;
160  }
161  ApiResult::setIndexedTagName( $categories_result, 'category' );
162  $retval['categories'] = $categories_result;
163  }
164  }
165  if ( isset( $prop['properties'] ) ) {
166  $properties = $p_output->getPageProperties();
167  if ( $properties ) {
168  ApiResult::setArrayType( $properties, 'BCkvp', 'name' );
169  ApiResult::setIndexedTagName( $properties, 'property' );
170  $retval['properties'] = $properties;
171  }
172  }
173  if ( isset( $prop['volatile'] ) ) {
174  $retval['volatile'] = $frame->isVolatile();
175  }
176  if ( isset( $prop['ttl'] ) && $frame->getTTL() !== null ) {
177  $retval['ttl'] = $frame->getTTL();
178  }
179  if ( isset( $prop['wikitext'] ) ) {
180  $retval['wikitext'] = $wikitext;
181  }
182  if ( isset( $prop['modules'] ) ) {
183  $retval['modules'] = array_values( array_unique( $p_output->getModules() ) );
184  // Deprecated since 1.32 (T188689)
185  $retval['modulescripts'] = [];
186  $retval['modulestyles'] = array_values( array_unique( $p_output->getModuleStyles() ) );
187  }
188  if ( isset( $prop['jsconfigvars'] ) ) {
189  $showStrategyKeys = (bool)( $params['showstrategykeys'] );
190  $retval['jsconfigvars'] =
191  ApiResult::addMetadataToResultVars( $p_output->getJsConfigVars( $showStrategyKeys ) );
192  }
193  if ( isset( $prop['encodedjsconfigvars'] ) ) {
194  $retval['encodedjsconfigvars'] = FormatJson::encode(
195  $p_output->getJsConfigVars(), false, FormatJson::ALL_OK
196  );
197  $retval[ApiResult::META_SUBELEMENTS][] = 'encodedjsconfigvars';
198  }
199  if ( isset( $prop['modules'] ) &&
200  !isset( $prop['jsconfigvars'] ) && !isset( $prop['encodedjsconfigvars'] ) ) {
201  $this->addWarning( 'apiwarn-moduleswithoutvars' );
202  }
203  }
204  }
205  ApiResult::setSubelementsList( $retval, [ 'wikitext', 'parsetree' ] );
206  $result->addValue( null, $this->getModuleName(), $retval );
207  }
208 
209  public function getAllowedParams() {
210  return [
211  'title' => null,
212  'text' => [
213  ParamValidator::PARAM_TYPE => 'text',
214  ParamValidator::PARAM_REQUIRED => true,
215  ],
216  'revid' => [
217  ParamValidator::PARAM_TYPE => 'integer',
218  ],
219  'prop' => [
220  ParamValidator::PARAM_TYPE => [
221  'wikitext',
222  'categories',
223  'properties',
224  'volatile',
225  'ttl',
226  'modules',
227  'jsconfigvars',
228  'encodedjsconfigvars',
229  'parsetree',
230  ],
231  ParamValidator::PARAM_ISMULTI => true,
233  ],
234  'includecomments' => false,
235  'showstrategykeys' => false,
236  'generatexml' => [
237  ParamValidator::PARAM_TYPE => 'boolean',
238  ParamValidator::PARAM_DEPRECATED => true,
239  ],
240  ];
241  }
242 
243  protected function getExamplesMessages() {
244  return [
245  'action=expandtemplates&text={{Project:Sandbox}}'
246  => 'apihelp-expandtemplates-example-simple',
247  ];
248  }
249 
250  public function getHelpUrls() {
251  return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Expandtemplates';
252  }
253 }
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:63
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
Definition: ApiBase.php:1516
getMain()
Get the main module.
Definition: ApiBase.php:547
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, or 'string' with PARAM_ISMULTI,...
Definition: ApiBase.php:210
addDeprecation( $msg, $feature, $data=[])
Add a deprecation warning for this module.
Definition: ApiBase.php:1448
requireMaxOneParameter( $params,... $required)
Dies if more than one parameter from a certain set of parameters are set and not false.
Definition: ApiBase.php:982
getResult()
Get the result object.
Definition: ApiBase.php:668
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:808
addWarning( $msg, $code=null, $data=null)
Add a warning for this module.
Definition: ApiBase.php:1434
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:529
getHookRunner()
Get an ApiHookRunner for running core API hooks.
Definition: ApiBase.php:753
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, ParserFactory $parserFactory)
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:64
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:98
const ALL_OK
Skip escaping as many characters as reasonably possible.
Definition: FormatJson.php:57
Service for looking up page revisions.
Represents a title within MediaWiki.
Definition: Title.php:76
static newFromContext(IContextSource $context)
Get a ParserOptions object from a IContextSource object.
const OT_PREPROCESS
Output type: like Parser::preprocess()
Definition: Parser.php:156
Service for formatting and validating API parameters.