MediaWiki  master
ApiContinuationManager.php
Go to the documentation of this file.
1 <?php
27  private $source;
28 
29  private $allModules = [];
30  private $generatedModules = [];
31 
33  private $continuationData = [];
36 
37  private $generatorParams = [];
38  private $generatorDone = false;
39 
46  public function __construct(
47  ApiBase $module, array $allModules = [], array $generatedModules = []
48  ) {
49  $this->source = get_class( $module );
50  $request = $module->getRequest();
51 
52  $this->generatedModules = $generatedModules
53  ? array_combine( $generatedModules, $generatedModules )
54  : [];
55 
56  $skip = [];
57  $continue = $request->getVal( 'continue', '' );
58  if ( $continue !== '' ) {
59  $continue = explode( '||', $continue );
60  if ( count( $continue ) !== 2 ) {
61  throw ApiUsageException::newWithMessage( $module->getMain(), 'apierror-badcontinue' );
62  }
63  $this->generatorDone = ( $continue[0] === '-' );
64  $skip = explode( '|', $continue[1] );
65  if ( !$this->generatorDone ) {
66  $params = explode( '|', $continue[0] );
67  if ( $params ) {
68  $this->generatorParams = array_intersect_key(
69  $request->getValues(),
70  array_flip( $params )
71  );
72  }
73  } else {
74  // When the generator is complete, don't run any modules that
75  // depend on it.
76  $skip += $this->generatedModules;
77  }
78  }
79 
80  foreach ( $allModules as $module ) {
81  $name = $module->getModuleName();
82  if ( in_array( $name, $skip, true ) ) {
83  $this->allModules[$name] = false;
84  // Prevent spurious "unused parameter" warnings
85  $module->extractRequestParams();
86  } else {
87  $this->allModules[$name] = $module;
88  }
89  }
90  }
91 
96  public function getSource() {
97  return $this->source;
98  }
99 
103  public function isGeneratorDone() {
104  return $this->generatorDone;
105  }
106 
111  public function getRunModules() {
112  return array_values( array_filter( $this->allModules ) );
113  }
114 
122  public function addContinueParam( ApiBase $module, $paramName, $paramValue ) {
123  $name = $module->getModuleName();
124  if ( !isset( $this->allModules[$name] ) ) {
125  throw new UnexpectedValueException(
126  "Module '$name' called " . __METHOD__ .
127  ' but was not passed to ' . __CLASS__ . '::__construct'
128  );
129  }
130  if ( !$this->allModules[$name] ) {
131  throw new UnexpectedValueException(
132  "Module '$name' was not supposed to have been executed, but " .
133  'it was executed anyway'
134  );
135  }
136  $paramName = $module->encodeParamName( $paramName );
137  if ( is_array( $paramValue ) ) {
138  $paramValue = implode( '|', $paramValue );
139  }
140  $this->continuationData[$name][$paramName] = $paramValue;
141  }
142 
154  public function addGeneratorNonContinueParam( ApiBase $module, $paramName, $paramValue ) {
155  $name = $module->getModuleName();
156  $paramName = $module->encodeParamName( $paramName );
157  if ( is_array( $paramValue ) ) {
158  $paramValue = implode( '|', $paramValue );
159  }
160  $this->generatorNonContinuationData[$name][$paramName] = $paramValue;
161  }
162 
169  public function addGeneratorContinueParam( ApiBase $module, $paramName, $paramValue ) {
170  $name = $module->getModuleName();
171  $paramName = $module->encodeParamName( $paramName );
172  if ( is_array( $paramValue ) ) {
173  $paramValue = implode( '|', $paramValue );
174  }
175  $this->generatorContinuationData[$name][$paramName] = $paramValue;
176  }
177 
182  public function getRawContinuation() {
183  return array_merge_recursive( $this->continuationData, $this->generatorContinuationData );
184  }
185 
191  public function getRawNonContinuation() {
193  }
194 
199  public function getContinuation() {
200  $data = [];
201  $batchcomplete = false;
202 
203  $finishedModules = array_diff(
204  array_keys( $this->allModules ),
205  array_keys( $this->continuationData )
206  );
207 
208  // First, grab the non-generator-using continuation data
209  $continuationData = array_diff_key( $this->continuationData, $this->generatedModules );
210  foreach ( $continuationData as $module => $kvp ) {
211  $data += $kvp;
212  }
213 
214  // Next, handle the generator-using continuation data
215  $continuationData = array_intersect_key( $this->continuationData, $this->generatedModules );
216  if ( $continuationData ) {
217  // Some modules are unfinished: include those params, and copy
218  // the generator params.
219  foreach ( $continuationData as $module => $kvp ) {
220  $data += $kvp;
221  }
222  $generatorParams = [];
223  foreach ( $this->generatorNonContinuationData as $kvp ) {
224  $generatorParams += $kvp;
225  }
227  $data += $generatorParams;
228  $generatorKeys = implode( '|', array_keys( $generatorParams ) );
229  } elseif ( $this->generatorContinuationData ) {
230  // All the generator-using modules are complete, but the
231  // generator isn't. Continue the generator and restart the
232  // generator-using modules
233  $generatorParams = [];
234  foreach ( $this->generatorContinuationData as $kvp ) {
235  $generatorParams += $kvp;
236  }
237  $data += $generatorParams;
238  $finishedModules = array_diff( $finishedModules, $this->generatedModules );
239  $generatorKeys = implode( '|', array_keys( $generatorParams ) );
240  $batchcomplete = true;
241  } else {
242  // Generator and prop modules are all done. Mark it so.
243  $generatorKeys = '-';
244  $batchcomplete = true;
245  }
246 
247  // Set 'continue' if any continuation data is set or if the generator
248  // still needs to run
249  if ( $data || $generatorKeys !== '-' ) {
250  $data['continue'] = $generatorKeys . '||' . implode( '|', $finishedModules );
251  }
252 
253  return [ $data, $batchcomplete ];
254  }
255 
260  public function setContinuationIntoResult( ApiResult $result ) {
261  list( $data, $batchcomplete ) = $this->getContinuation();
262  if ( $data ) {
263  $result->addValue( null, 'continue', $data,
265  }
266  if ( $batchcomplete ) {
267  $result->addValue( null, 'batchcomplete', true,
269  }
270  }
271 }
ApiContinuationManager\setContinuationIntoResult
setContinuationIntoResult(ApiResult $result)
Store the continuation data into the result.
Definition: ApiContinuationManager.php:260
ApiUsageException\newWithMessage
static newWithMessage(?ApiBase $module, $msg, $code=null, $data=null, $httpCode=0, Throwable $previous=null)
Definition: ApiUsageException.php:68
ApiContinuationManager
This manages continuation state.
Definition: ApiContinuationManager.php:26
ApiContinuationManager\addContinueParam
addContinueParam(ApiBase $module, $paramName, $paramValue)
Set the continuation parameter for a module.
Definition: ApiContinuationManager.php:122
ApiContinuationManager\getRunModules
getRunModules()
Get the list of modules that should actually be run.
Definition: ApiContinuationManager.php:111
ApiContinuationManager\$generatorContinuationData
$generatorContinuationData
Definition: ApiContinuationManager.php:34
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:80
ApiContinuationManager\$generatorDone
$generatorDone
Definition: ApiContinuationManager.php:38
ApiBase
This abstract class implements many basic API functions, and is the base of all API classes.
Definition: ApiBase.php:52
ApiContinuationManager\getContinuation
getContinuation()
Fetch continuation result data.
Definition: ApiContinuationManager.php:199
ApiContinuationManager\$generatorNonContinuationData
$generatorNonContinuationData
Definition: ApiContinuationManager.php:35
ApiResult
This class represents the result of the API operations.
Definition: ApiResult.php:35
ApiContinuationManager\$continuationData
array[] $continuationData
Definition: ApiContinuationManager.php:33
ApiResult\addValue
addValue( $path, $name, $value, $flags=0)
Add value to the output data at the given path.
Definition: ApiResult.php:391
ApiContinuationManager\$generatedModules
$generatedModules
Definition: ApiContinuationManager.php:30
ApiContinuationManager\addGeneratorNonContinueParam
addGeneratorNonContinueParam(ApiBase $module, $paramName, $paramValue)
Set the non-continuation parameter for the generator module.
Definition: ApiContinuationManager.php:154
ApiBase\encodeParamName
encodeParamName( $paramName)
This method mangles parameter name based on the prefix supplied to the constructor.
Definition: ApiBase.php:684
ApiContinuationManager\getRawNonContinuation
getRawNonContinuation()
Fetch raw non-continuation data.
Definition: ApiContinuationManager.php:191
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:103
ApiBase\getModuleName
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:437
ApiBase\getMain
getMain()
Get the main module.
Definition: ApiBase.php:453
ApiContinuationManager\__construct
__construct(ApiBase $module, array $allModules=[], array $generatedModules=[])
Definition: ApiContinuationManager.php:46
ApiContinuationManager\getRawContinuation
getRawContinuation()
Fetch raw continuation data.
Definition: ApiContinuationManager.php:182
ApiContinuationManager\addGeneratorContinueParam
addGeneratorContinueParam(ApiBase $module, $paramName, $paramValue)
Set the continuation parameter for the generator module.
Definition: ApiContinuationManager.php:169
ApiContinuationManager\$generatorParams
$generatorParams
Definition: ApiContinuationManager.php:37
ApiContinuationManager\$source
$source
Definition: ApiContinuationManager.php:27
ApiContinuationManager\getSource
getSource()
Get the class that created this manager.
Definition: ApiContinuationManager.php:96
ApiContinuationManager\$allModules
$allModules
Definition: ApiContinuationManager.php:29