MediaWiki  master
ApiContinuationManager.php
Go to the documentation of this file.
1 <?php
28  private $source;
29 
31  private $allModules = [];
34 
36  private $continuationData = [];
41 
43  private $generatorParams = [];
45  private $generatorDone = false;
46 
53  public function __construct(
54  ApiBase $module, array $allModules = [], array $generatedModules = []
55  ) {
56  $this->source = get_class( $module );
57  $request = $module->getRequest();
58 
59  $this->generatedModules = $generatedModules
60  ? array_combine( $generatedModules, $generatedModules )
61  : [];
62 
63  $skip = [];
64  $continue = $request->getVal( 'continue', '' );
65  if ( $continue !== '' ) {
66  $continue = explode( '||', $continue );
67  if ( count( $continue ) !== 2 ) {
68  throw ApiUsageException::newWithMessage( $module->getMain(), 'apierror-badcontinue' );
69  }
70  $this->generatorDone = ( $continue[0] === '-' );
71  $skip = explode( '|', $continue[1] );
72  if ( !$this->generatorDone ) {
73  $params = explode( '|', $continue[0] );
74  if ( $params ) {
75  $this->generatorParams = array_intersect_key(
76  $request->getValues(),
77  array_fill_keys( $params, true )
78  );
79  }
80  } else {
81  // When the generator is complete, don't run any modules that
82  // depend on it.
83  $skip += $this->generatedModules;
84  }
85  }
86 
87  foreach ( $allModules as $module ) {
88  $name = $module->getModuleName();
89  if ( in_array( $name, $skip, true ) ) {
90  $this->allModules[$name] = false;
91  // Prevent spurious "unused parameter" warnings
92  $module->extractRequestParams();
93  } else {
94  $this->allModules[$name] = $module;
95  }
96  }
97  }
98 
103  public function getSource() {
104  return $this->source;
105  }
106 
110  public function isGeneratorDone() {
111  return $this->generatorDone;
112  }
113 
118  public function getRunModules() {
119  return array_values( array_filter( $this->allModules ) );
120  }
121 
129  public function addContinueParam( ApiBase $module, $paramName, $paramValue ) {
130  $name = $module->getModuleName();
131  if ( !isset( $this->allModules[$name] ) ) {
132  throw new UnexpectedValueException(
133  "Module '$name' called " . __METHOD__ .
134  ' but was not passed to ' . __CLASS__ . '::__construct'
135  );
136  }
137  if ( !$this->allModules[$name] ) {
138  throw new UnexpectedValueException(
139  "Module '$name' was not supposed to have been executed, but " .
140  'it was executed anyway'
141  );
142  }
143  $paramName = $module->encodeParamName( $paramName );
144  if ( is_array( $paramValue ) ) {
145  $paramValue = implode( '|', $paramValue );
146  }
147  $this->continuationData[$name][$paramName] = $paramValue;
148  }
149 
161  public function addGeneratorNonContinueParam( ApiBase $module, $paramName, $paramValue ) {
162  $name = $module->getModuleName();
163  $paramName = $module->encodeParamName( $paramName );
164  if ( is_array( $paramValue ) ) {
165  $paramValue = implode( '|', $paramValue );
166  }
167  $this->generatorNonContinuationData[$name][$paramName] = $paramValue;
168  }
169 
176  public function addGeneratorContinueParam( ApiBase $module, $paramName, $paramValue ) {
177  $name = $module->getModuleName();
178  $paramName = $module->encodeParamName( $paramName );
179  if ( is_array( $paramValue ) ) {
180  $paramValue = implode( '|', $paramValue );
181  }
182  $this->generatorContinuationData[$name][$paramName] = $paramValue;
183  }
184 
189  public function getRawContinuation() {
190  return array_merge_recursive( $this->continuationData, $this->generatorContinuationData );
191  }
192 
198  public function getRawNonContinuation() {
200  }
201 
206  public function getContinuation() {
207  $data = [];
208  $batchcomplete = false;
209 
210  $finishedModules = array_diff(
211  array_keys( $this->allModules ),
212  array_keys( $this->continuationData )
213  );
214 
215  // First, grab the non-generator-using continuation data
216  $continuationData = array_diff_key( $this->continuationData, $this->generatedModules );
217  foreach ( $continuationData as $module => $kvp ) {
218  $data += $kvp;
219  }
220 
221  // Next, handle the generator-using continuation data
222  $continuationData = array_intersect_key( $this->continuationData, $this->generatedModules );
223  if ( $continuationData ) {
224  // Some modules are unfinished: include those params, and copy
225  // the generator params.
226  foreach ( $continuationData as $module => $kvp ) {
227  $data += $kvp;
228  }
229  $generatorParams = [];
230  foreach ( $this->generatorNonContinuationData as $kvp ) {
231  $generatorParams += $kvp;
232  }
234  // @phan-suppress-next-line PhanTypeInvalidLeftOperand False positive in phan
235  $data += $generatorParams;
236  $generatorKeys = implode( '|', array_keys( $generatorParams ) );
237  } elseif ( $this->generatorContinuationData ) {
238  // All the generator-using modules are complete, but the
239  // generator isn't. Continue the generator and restart the
240  // generator-using modules
241  $generatorParams = [];
242  foreach ( $this->generatorContinuationData as $kvp ) {
243  $generatorParams += $kvp;
244  }
245  $data += $generatorParams;
246  $finishedModules = array_diff( $finishedModules, $this->generatedModules );
247  $generatorKeys = implode( '|', array_keys( $generatorParams ) );
248  $batchcomplete = true;
249  } else {
250  // Generator and prop modules are all done. Mark it so.
251  $generatorKeys = '-';
252  $batchcomplete = true;
253  }
254 
255  // Set 'continue' if any continuation data is set or if the generator
256  // still needs to run
257  if ( $data || $generatorKeys !== '-' ) {
258  $data['continue'] = $generatorKeys . '||' . implode( '|', $finishedModules );
259  }
260 
261  return [ $data, $batchcomplete ];
262  }
263 
268  public function setContinuationIntoResult( ApiResult $result ) {
269  list( $data, $batchcomplete ) = $this->getContinuation();
270  if ( $data ) {
271  $result->addValue( null, 'continue', $data,
273  }
274  if ( $batchcomplete ) {
275  $result->addValue( null, 'batchcomplete', true,
277  }
278  }
279 }
ApiContinuationManager\setContinuationIntoResult
setContinuationIntoResult(ApiResult $result)
Store the continuation data into the result.
Definition: ApiContinuationManager.php:268
ApiUsageException\newWithMessage
static newWithMessage(?ApiBase $module, $msg, $code=null, $data=null, $httpCode=0, Throwable $previous=null)
Definition: ApiUsageException.php:68
ApiContinuationManager\$generatorNonContinuationData
array[] $generatorNonContinuationData
Definition: ApiContinuationManager.php:40
ApiContinuationManager
This manages continuation state.
Definition: ApiContinuationManager.php:26
ApiContinuationManager\$generatorContinuationData
array[] $generatorContinuationData
Definition: ApiContinuationManager.php:38
ApiContinuationManager\addContinueParam
addContinueParam(ApiBase $module, $paramName, $paramValue)
Set the continuation parameter for a module.
Definition: ApiContinuationManager.php:129
ApiContinuationManager\getRunModules
getRunModules()
Get the list of modules that should actually be run.
Definition: ApiContinuationManager.php:118
ApiResult\NO_SIZE_CHECK
const NO_SIZE_CHECK
For addValue() and similar functions, do not check size while adding a value Don't use this unless yo...
Definition: ApiResult.php:58
ContextSource\getRequest
getRequest()
Definition: ContextSource.php:81
ApiBase
This abstract class implements many basic API functions, and is the base of all API classes.
Definition: ApiBase.php:55
ApiContinuationManager\$generatorParams
array $generatorParams
Definition: ApiContinuationManager.php:43
ApiContinuationManager\getContinuation
getContinuation()
Fetch continuation result data.
Definition: ApiContinuationManager.php:206
ApiResult
This class represents the result of the API operations.
Definition: ApiResult.php:35
ApiContinuationManager\$continuationData
array[] $continuationData
Definition: ApiContinuationManager.php:36
ApiResult\addValue
addValue( $path, $name, $value, $flags=0)
Add value to the output data at the given path.
Definition: ApiResult.php:393
ApiContinuationManager\addGeneratorNonContinueParam
addGeneratorNonContinueParam(ApiBase $module, $paramName, $paramValue)
Set the non-continuation parameter for the generator module.
Definition: ApiContinuationManager.php:161
ApiBase\encodeParamName
encodeParamName( $paramName)
This method mangles parameter name based on the prefix supplied to the constructor.
Definition: ApiBase.php:685
ApiContinuationManager\$allModules
ApiBase false[] $allModules
Definition: ApiContinuationManager.php:31
ApiContinuationManager\$source
string $source
Definition: ApiContinuationManager.php:28
ApiContinuationManager\getRawNonContinuation
getRawNonContinuation()
Fetch raw non-continuation data.
Definition: ApiContinuationManager.php:198
ApiResult\ADD_ON_TOP
const ADD_ON_TOP
For addValue(), setValue() and similar functions, if the value does not exist, add it as the first el...
Definition: ApiResult.php:49
ApiContinuationManager\isGeneratorDone
isGeneratorDone()
Definition: ApiContinuationManager.php:110
ApiContinuationManager\$generatorDone
bool $generatorDone
Definition: ApiContinuationManager.php:45
ApiBase\getModuleName
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:440
ApiBase\getMain
getMain()
Get the main module.
Definition: ApiBase.php:456
ApiContinuationManager\__construct
__construct(ApiBase $module, array $allModules=[], array $generatedModules=[])
Definition: ApiContinuationManager.php:53
ApiContinuationManager\getRawContinuation
getRawContinuation()
Fetch raw continuation data.
Definition: ApiContinuationManager.php:189
ApiContinuationManager\addGeneratorContinueParam
addGeneratorContinueParam(ApiBase $module, $paramName, $paramValue)
Set the continuation parameter for the generator module.
Definition: ApiContinuationManager.php:176
ApiContinuationManager\$generatedModules
string[] $generatedModules
Definition: ApiContinuationManager.php:33
ApiContinuationManager\getSource
getSource()
Get the class that created this manager.
Definition: ApiContinuationManager.php:103