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,
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 ) {
98  if ( !$titleObj->equals( $pTitleObj ) ) {
99  $this->addWarning( [ 'apierror-revwrongpage', $rev->getId(),
100  wfEscapeWikiText( $pTitleObj->getPrefixedText() ) ] );
101  }
102  }
103  }
104 
105  $result = $this->getResult();
106 
107  // Parse text
108  $options = ParserOptions::newFromContext( $this->getContext() );
109 
110  if ( $params['includecomments'] ) {
111  $options->setRemoveComments( false );
112  }
113 
114  $reset = null;
115  $suppressCache = false;
116  $this->getHookRunner()->onApiMakeParserOptions(
117  $options, $titleObj, $params, $this, $reset, $suppressCache );
118 
119  $retval = [];
120 
121  if ( isset( $prop['parsetree'] ) || $params['generatexml'] ) {
122  $this->parser->startExternalParse( $titleObj, $options, Parser::OT_PREPROCESS );
123  $dom = $this->parser->preprocessToDom( $params['text'] );
124  if ( is_callable( [ $dom, 'saveXML' ] ) ) {
125  // @phan-suppress-next-line PhanUndeclaredMethod
126  $xml = $dom->saveXML();
127  } else {
128  // @phan-suppress-next-line PhanUndeclaredMethod
129  $xml = $dom->__toString();
130  }
131  if ( isset( $prop['parsetree'] ) ) {
132  unset( $prop['parsetree'] );
133  $retval['parsetree'] = $xml;
134  } else {
135  // the old way
136  $result->addValue( null, 'parsetree', $xml );
137  $result->addValue( null, ApiResult::META_BC_SUBELEMENTS, [ 'parsetree' ] );
138  }
139  }
140 
141  // if they didn't want any output except (probably) the parse tree,
142  // then don't bother actually fully expanding it
143  if ( $prop || $params['prop'] === null ) {
144  $this->parser->startExternalParse( $titleObj, $options, Parser::OT_PREPROCESS );
145  $frame = $this->parser->getPreprocessor()->newFrame();
146  $wikitext = $this->parser->preprocess( $params['text'], $titleObj, $options, $revid, $frame );
147  if ( $params['prop'] === null ) {
148  // the old way
149  ApiResult::setContentValue( $retval, 'wikitext', $wikitext );
150  } else {
151  $p_output = $this->parser->getOutput();
152  if ( isset( $prop['categories'] ) ) {
153  $categories = $p_output->getCategories();
154  if ( $categories ) {
155  $categories_result = [];
156  foreach ( $categories as $category => $sortkey ) {
157  $entry = [];
158  $entry['sortkey'] = $sortkey;
159  ApiResult::setContentValue( $entry, 'category', (string)$category );
160  $categories_result[] = $entry;
161  }
162  ApiResult::setIndexedTagName( $categories_result, 'category' );
163  $retval['categories'] = $categories_result;
164  }
165  }
166  if ( isset( $prop['properties'] ) ) {
167  $properties = $p_output->getPageProperties();
168  if ( $properties ) {
169  ApiResult::setArrayType( $properties, 'BCkvp', 'name' );
170  ApiResult::setIndexedTagName( $properties, 'property' );
171  $retval['properties'] = $properties;
172  }
173  }
174  if ( isset( $prop['volatile'] ) ) {
175  $retval['volatile'] = $frame->isVolatile();
176  }
177  if ( isset( $prop['ttl'] ) && $frame->getTTL() !== null ) {
178  $retval['ttl'] = $frame->getTTL();
179  }
180  if ( isset( $prop['wikitext'] ) ) {
181  $retval['wikitext'] = $wikitext;
182  }
183  if ( isset( $prop['modules'] ) ) {
184  $retval['modules'] = array_values( array_unique( $p_output->getModules() ) );
185  // Deprecated since 1.32 (T188689)
186  $retval['modulescripts'] = [];
187  $retval['modulestyles'] = array_values( array_unique( $p_output->getModuleStyles() ) );
188  }
189  if ( isset( $prop['jsconfigvars'] ) ) {
190  $showStrategyKeys = (bool)( $params['showstrategykeys'] );
191  $retval['jsconfigvars'] =
192  ApiResult::addMetadataToResultVars( $p_output->getJsConfigVars( $showStrategyKeys ) );
193  }
194  if ( isset( $prop['encodedjsconfigvars'] ) ) {
195  $retval['encodedjsconfigvars'] = FormatJson::encode(
196  $p_output->getJsConfigVars(), false, FormatJson::ALL_OK
197  );
198  $retval[ApiResult::META_SUBELEMENTS][] = 'encodedjsconfigvars';
199  }
200  if ( isset( $prop['modules'] ) &&
201  !isset( $prop['jsconfigvars'] ) && !isset( $prop['encodedjsconfigvars'] ) ) {
202  $this->addWarning( 'apiwarn-moduleswithoutvars' );
203  }
204  }
205  }
206  ApiResult::setSubelementsList( $retval, [ 'wikitext', 'parsetree' ] );
207  $result->addValue( null, $this->getModuleName(), $retval );
208  }
209 
210  public function getAllowedParams() {
211  return [
212  'title' => null,
213  'text' => [
214  ParamValidator::PARAM_TYPE => 'text',
215  ParamValidator::PARAM_REQUIRED => true,
216  ],
217  'revid' => [
218  ParamValidator::PARAM_TYPE => 'integer',
219  ],
220  'prop' => [
221  ParamValidator::PARAM_TYPE => [
222  'wikitext',
223  'categories',
224  'properties',
225  'volatile',
226  'ttl',
227  'modules',
228  'jsconfigvars',
229  'encodedjsconfigvars',
230  'parsetree',
231  ],
232  ParamValidator::PARAM_ISMULTI => true,
234  ],
235  'includecomments' => false,
236  'showstrategykeys' => false,
237  'generatexml' => [
238  ParamValidator::PARAM_TYPE => 'boolean',
239  ParamValidator::PARAM_DEPRECATED => true,
240  ],
241  ];
242  }
243 
244  protected function getExamplesMessages() {
245  return [
246  'action=expandtemplates&text={{Project:Sandbox}}'
247  => 'apihelp-expandtemplates-example-simple',
248  ];
249  }
250 
251  public function getHelpUrls() {
252  return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Parsing_wikitext#expandtemplates';
253  }
254 }
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:1458
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:1390
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:1376
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.
RevisionStore $revisionStore
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:131
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.