MediaWiki REL1_34
ApiContinuationManager.php
Go to the documentation of this file.
1<?php
27 private $source;
28
29 private $allModules = [];
30 private $generatedModules = [];
31
32 private $continuationData = [];
35
36 private $generatorParams = [];
37 private $generatorDone = false;
38
45 public function __construct(
46 ApiBase $module, array $allModules = [], array $generatedModules = []
47 ) {
48 $this->source = get_class( $module );
49 $request = $module->getRequest();
50
51 $this->generatedModules = $generatedModules
52 ? array_combine( $generatedModules, $generatedModules )
53 : [];
54
55 $skip = [];
56 $continue = $request->getVal( 'continue', '' );
57 if ( $continue !== '' ) {
58 $continue = explode( '||', $continue );
59 if ( count( $continue ) !== 2 ) {
60 throw ApiUsageException::newWithMessage( $module->getMain(), 'apierror-badcontinue' );
61 }
62 $this->generatorDone = ( $continue[0] === '-' );
63 $skip = explode( '|', $continue[1] );
64 if ( !$this->generatorDone ) {
65 $params = explode( '|', $continue[0] );
66 if ( $params ) {
67 $this->generatorParams = array_intersect_key(
68 $request->getValues(),
69 array_flip( $params )
70 );
71 }
72 } else {
73 // When the generator is complete, don't run any modules that
74 // depend on it.
76 }
77 }
78
79 foreach ( $allModules as $module ) {
80 $name = $module->getModuleName();
81 if ( in_array( $name, $skip, true ) ) {
82 $this->allModules[$name] = false;
83 // Prevent spurious "unused parameter" warnings
84 $module->extractRequestParams();
85 } else {
86 $this->allModules[$name] = $module;
87 }
88 }
89 }
90
95 public function getSource() {
96 return $this->source;
97 }
98
103 public function isGeneratorDone() {
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 // XXX: Not sure why phan is complaining here...
221 // @phan-suppress-next-line PhanTypeInvalidLeftOperand
222 $data += $kvp;
223 }
224 $generatorParams = [];
225 foreach ( $this->generatorNonContinuationData as $kvp ) {
226 $generatorParams += $kvp;
227 }
229 $data += $generatorParams;
230 $generatorKeys = implode( '|', array_keys( $generatorParams ) );
231 } elseif ( $this->generatorContinuationData ) {
232 // All the generator-using modules are complete, but the
233 // generator isn't. Continue the generator and restart the
234 // generator-using modules
235 $generatorParams = [];
236 foreach ( $this->generatorContinuationData as $kvp ) {
237 $generatorParams += $kvp;
238 }
239 $data += $generatorParams;
240 $finishedModules = array_diff( $finishedModules, $this->generatedModules );
241 $generatorKeys = implode( '|', array_keys( $generatorParams ) );
242 $batchcomplete = true;
243 } else {
244 // Generator and prop modules are all done. Mark it so.
245 $generatorKeys = '-';
246 $batchcomplete = true;
247 }
248
249 // Set 'continue' if any continuation data is set or if the generator
250 // still needs to run
251 if ( $data || $generatorKeys !== '-' ) {
252 $data['continue'] = $generatorKeys . '||' . implode( '|', $finishedModules );
253 }
254
255 return [ $data, $batchcomplete ];
256 }
257
262 public function setContinuationIntoResult( ApiResult $result ) {
263 list( $data, $batchcomplete ) = $this->getContinuation();
264 if ( $data ) {
265 $result->addValue( null, 'continue', $data,
266 ApiResult::ADD_ON_TOP | ApiResult::NO_SIZE_CHECK );
267 }
268 if ( $batchcomplete ) {
269 $result->addValue( null, 'batchcomplete', true,
270 ApiResult::ADD_ON_TOP | ApiResult::NO_SIZE_CHECK );
271 }
272 }
273}
This abstract class implements many basic API functions, and is the base of all API classes.
Definition ApiBase.php:42
encodeParamName( $paramName)
This method mangles parameter name based on the prefix supplied to the constructor.
Definition ApiBase.php:739
getMain()
Get the main module.
Definition ApiBase.php:536
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition ApiBase.php:761
getModuleName()
Get the name of the module being executed by this instance.
Definition ApiBase.php:520
This manages continuation state.
addGeneratorNonContinueParam(ApiBase $module, $paramName, $paramValue)
Set the non-continuation parameter for the generator module.
isGeneratorDone()
Is the generator done?
addGeneratorContinueParam(ApiBase $module, $paramName, $paramValue)
Set the continuation parameter for the generator module.
setContinuationIntoResult(ApiResult $result)
Store the continuation data into the result.
getRunModules()
Get the list of modules that should actually be run.
addContinueParam(ApiBase $module, $paramName, $paramValue)
Set the continuation parameter for a module.
getSource()
Get the class that created this manager.
getRawNonContinuation()
Fetch raw non-continuation data.
__construct(ApiBase $module, array $allModules=[], array $generatedModules=[])
getContinuation()
Fetch continuation result data.
getRawContinuation()
Fetch raw continuation data.
This class represents the result of the API operations.
Definition ApiResult.php:35
addValue( $path, $name, $value, $flags=0)
Add value to the output data at the given path.