Merge "Add MessagesSdh.php for Southern Kurdish"
[lhc/web/wiklou.git] / includes / api / ApiResult.php
1 <?php
2 /**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
17 *
18 * @file
19 */
20
21 /**
22 * This class represents the result of the API operations.
23 * It simply wraps a nested array() structure, adding some functions to simplify
24 * array's modifications. As various modules execute, they add different pieces
25 * of information to this result, structuring it as it will be given to the client.
26 *
27 * Each subarray may either be a dictionary - key-value pairs with unique keys,
28 * or lists, where the items are added using $data[] = $value notation.
29 *
30 * @since 1.25 this is no longer a subclass of ApiBase
31 * @ingroup API
32 */
33 class ApiResult implements ApiSerializable {
34
35 /**
36 * Override existing value in addValue(), setValue(), and similar functions
37 * @since 1.21
38 */
39 const OVERRIDE = 1;
40
41 /**
42 * For addValue(), setValue() and similar functions, if the value does not
43 * exist, add it as the first element. In case the new value has no name
44 * (numerical index), all indexes will be renumbered.
45 * @since 1.21
46 */
47 const ADD_ON_TOP = 2;
48
49 /**
50 * For addValue() and similar functions, do not check size while adding a value
51 * Don't use this unless you REALLY know what you're doing.
52 * Values added while the size checking was disabled will never be counted.
53 * Ignored for setValue() and similar functions.
54 * @since 1.24
55 */
56 const NO_SIZE_CHECK = 4;
57
58 /**
59 * For addValue(), setValue() and similar functions, do not validate data.
60 * Also disables size checking. If you think you need to use this, you're
61 * probably wrong.
62 * @since 1.25
63 */
64 const NO_VALIDATE = 12;
65
66 /**
67 * Key for the 'indexed tag name' metadata item. Value is string.
68 * @since 1.25
69 */
70 const META_INDEXED_TAG_NAME = '_element';
71
72 /**
73 * Key for the 'subelements' metadata item. Value is string[].
74 * @since 1.25
75 */
76 const META_SUBELEMENTS = '_subelements';
77
78 /**
79 * Key for the 'preserve keys' metadata item. Value is string[].
80 * @since 1.25
81 */
82 const META_PRESERVE_KEYS = '_preservekeys';
83
84 /**
85 * Key for the 'content' metadata item. Value is string.
86 * @since 1.25
87 */
88 const META_CONTENT = '_content';
89
90 /**
91 * Key for the 'type' metadata item. Value is one of the following strings:
92 * - default: Like 'array' if all (non-metadata) keys are numeric with no
93 * gaps, otherwise like 'assoc'.
94 * - array: Keys are used for ordering, but are not output. In a format
95 * like JSON, outputs as [].
96 * - assoc: In a format like JSON, outputs as {}.
97 * - kvp: For a format like XML where object keys have a restricted
98 * character set, use an alternative output format. For example,
99 * <container><item name="key">value</item></container> rather than
100 * <container key="value" />
101 * - BCarray: Like 'array' normally, 'default' in backwards-compatibility mode.
102 * - BCassoc: Like 'assoc' normally, 'default' in backwards-compatibility mode.
103 * - BCkvp: Like 'kvp' normally. In backwards-compatibility mode, forces
104 * the alternative output format for all formats, for example
105 * [{"name":key,"*":value}] in JSON. META_KVP_KEY_NAME must also be set.
106 * @since 1.25
107 */
108 const META_TYPE = '_type';
109
110 /**
111 * Key (rather than "name" or other default) for when META_TYPE is 'kvp' or
112 * 'BCkvp'. Value is string.
113 * @since 1.25
114 */
115 const META_KVP_KEY_NAME = '_kvpkeyname';
116
117 /**
118 * Key for the 'BC bools' metadata item. Value is string[].
119 * Note no setter is provided.
120 * @since 1.25
121 */
122 const META_BC_BOOLS = '_BC_bools';
123
124 /**
125 * Key for the 'BC subelements' metadata item. Value is string[].
126 * Note no setter is provided.
127 * @since 1.25
128 */
129 const META_BC_SUBELEMENTS = '_BC_subelements';
130
131 private $data, $size, $maxSize;
132 private $errorFormatter;
133
134 // Deprecated fields
135 private $isRawMode, $checkingSize, $mainForContinuation;
136
137 /**
138 * @param int|bool $maxSize Maximum result "size", or false for no limit
139 * @since 1.25 Takes an integer|bool rather than an ApiMain
140 */
141 public function __construct( $maxSize ) {
142 if ( $maxSize instanceof ApiMain ) {
143 wfDeprecated( 'ApiMain to ' . __METHOD__, '1.25' );
144 $this->errorFormatter = $maxSize->getErrorFormatter();
145 $this->mainForContinuation = $maxSize;
146 $maxSize = $maxSize->getConfig()->get( 'APIMaxResultSize' );
147 }
148
149 $this->maxSize = $maxSize;
150 $this->isRawMode = false;
151 $this->checkingSize = true;
152 $this->reset();
153 }
154
155 /**
156 * Set the error formatter
157 * @since 1.25
158 * @param ApiErrorFormatter $formatter
159 */
160 public function setErrorFormatter( ApiErrorFormatter $formatter ) {
161 $this->errorFormatter = $formatter;
162 }
163
164 /**
165 * Allow for adding one ApiResult into another
166 * @since 1.25
167 * @return mixed
168 */
169 public function serializeForApiResult() {
170 return $this->data;
171 }
172
173 /************************************************************************//**
174 * @name Content
175 * @{
176 */
177
178 /**
179 * Clear the current result data.
180 */
181 public function reset() {
182 $this->data = array(
183 self::META_TYPE => 'assoc', // Usually what's desired
184 );
185 $this->size = 0;
186 }
187
188 /**
189 * Get the result data array
190 *
191 * The returned value should be considered read-only.
192 *
193 * Transformations include:
194 *
195 * Custom: (callable) Applied before other transformations. Signature is
196 * function ( &$data, &$metadata ), return value is ignored. Called for
197 * each nested array.
198 *
199 * BC: (array) This transformation does various adjustments to bring the
200 * output in line with the pre-1.25 result format. The value array is a
201 * list of flags: 'nobool', 'no*', 'nosub'.
202 * - Boolean-valued items are changed to '' if true or removed if false,
203 * unless listed in META_BC_BOOLS. This may be skipped by including
204 * 'nobool' in the value array.
205 * - The tag named by META_CONTENT is renamed to '*', and META_CONTENT is
206 * set to '*'. This may be skipped by including 'no*' in the value
207 * array.
208 * - Tags listed in META_BC_SUBELEMENTS will have their values changed to
209 * array( '*' => $value ). This may be skipped by including 'nosub' in
210 * the value array.
211 * - If META_TYPE is 'BCarray', set it to 'default'
212 * - If META_TYPE is 'BCassoc', set it to 'default'
213 * - If META_TYPE is 'BCkvp', perform the transformation (even if
214 * the Types transformation is not being applied).
215 *
216 * Types: (assoc) Apply transformations based on META_TYPE. The values
217 * array is an associative array with the following possible keys:
218 * - AssocAsObject: (bool) If true, return arrays with META_TYPE 'assoc'
219 * as objects.
220 * - ArmorKVP: (string) If provided, transform arrays with META_TYPE 'kvp'
221 * and 'BCkvp' into arrays of two-element arrays, something like this:
222 * $output = array();
223 * foreach ( $input as $key => $value ) {
224 * $pair = array();
225 * $pair[$META_KVP_KEY_NAME ?: $ArmorKVP_value] = $key;
226 * ApiResult::setContentValue( $pair, 'value', $value );
227 * $output[] = $pair;
228 * }
229 *
230 * Strip: (string) Strips metadata keys from the result.
231 * - 'all': Strip all metadata, recursively
232 * - 'base': Strip metadata at the top-level only.
233 * - 'none': Do not strip metadata.
234 * - 'bc': Like 'all', but leave certain pre-1.25 keys.
235 *
236 * @since 1.25
237 * @param array|string|null $path Path to fetch, see ApiResult::addValue
238 * @param array $transforms See above
239 * @return mixed Result data, or null if not found
240 */
241 public function getResultData( $path = array(), $transforms = array() ) {
242 $path = (array)$path;
243 if ( !$path ) {
244 return self::applyTransformations( $this->data, $transforms );
245 }
246
247 $last = array_pop( $path );
248 $ret = &$this->path( $path, 'dummy' );
249 if ( !isset( $ret[$last] ) ) {
250 return null;
251 } elseif ( is_array( $ret[$last] ) ) {
252 return self::applyTransformations( $ret[$last], $transforms );
253 } else {
254 return $ret[$last];
255 }
256 }
257
258 /**
259 * Get the size of the result, i.e. the amount of bytes in it
260 * @return int
261 */
262 public function getSize() {
263 return $this->size;
264 }
265
266 /**
267 * Add an output value to the array by name.
268 *
269 * Verifies that value with the same name has not been added before.
270 *
271 * @since 1.25
272 * @param array &$arr To add $value to
273 * @param string|int|null $name Index of $arr to add $value at,
274 * or null to use the next numeric index.
275 * @param mixed $value
276 * @param int $flags Zero or more OR-ed flags like OVERRIDE | ADD_ON_TOP.
277 */
278 public static function setValue( array &$arr, $name, $value, $flags = 0 ) {
279 if ( !( $flags & ApiResult::NO_VALIDATE ) ) {
280 $value = self::validateValue( $value );
281 }
282
283 if ( $name === null ) {
284 if ( $flags & ApiResult::ADD_ON_TOP ) {
285 array_unshift( $arr, $value );
286 } else {
287 array_push( $arr, $value );
288 }
289 return;
290 }
291
292 $exists = isset( $arr[$name] );
293 if ( !$exists || ( $flags & ApiResult::OVERRIDE ) ) {
294 if ( !$exists && ( $flags & ApiResult::ADD_ON_TOP ) ) {
295 $arr = array( $name => $value ) + $arr;
296 } else {
297 $arr[$name] = $value;
298 }
299 } elseif ( is_array( $arr[$name] ) && is_array( $value ) ) {
300 $conflicts = array_intersect_key( $arr[$name], $value );
301 if ( !$conflicts ) {
302 $arr[$name] += $value;
303 } else {
304 $keys = join( ', ', array_keys( $conflicts ) );
305 throw new RuntimeException(
306 "Conflicting keys ($keys) when attempting to merge element $name"
307 );
308 }
309 } else {
310 throw new RuntimeException(
311 "Attempting to add element $name=$value, existing value is {$arr[$name]}"
312 );
313 }
314 }
315
316 /**
317 * Validate a value for addition to the result
318 * @param mixed $value
319 */
320 private static function validateValue( $value ) {
321 global $wgContLang;
322
323 if ( is_object( $value ) ) {
324 // Note we use is_callable() here instead of instanceof because
325 // ApiSerializable is an informal protocol (see docs there for details).
326 if ( is_callable( array( $value, 'serializeForApiResult' ) ) ) {
327 $oldValue = $value;
328 $value = $value->serializeForApiResult();
329 if ( is_object( $value ) ) {
330 throw new UnexpectedValueException(
331 get_class( $oldValue ) . "::serializeForApiResult() returned an object of class " .
332 get_class( $value )
333 );
334 }
335
336 // Recursive call instead of fall-through so we can throw a
337 // better exception message.
338 try {
339 return self::validateValue( $value );
340 } catch ( Exception $ex ) {
341 throw new UnexpectedValueException(
342 get_class( $oldValue ) . "::serializeForApiResult() returned an invalid value: " .
343 $ex->getMessage(),
344 0,
345 $ex
346 );
347 }
348 } elseif ( is_callable( array( $value, '__toString' ) ) ) {
349 $value = (string)$value;
350 } else {
351 $value = (array)$value + array( self::META_TYPE => 'assoc' );
352 }
353 }
354 if ( is_array( $value ) ) {
355 foreach ( $value as $k => $v ) {
356 $value[$k] = self::validateValue( $v );
357 }
358 } elseif ( is_float( $value ) && !is_finite( $value ) ) {
359 throw new InvalidArgumentException( "Cannot add non-finite floats to ApiResult" );
360 } elseif ( is_string( $value ) ) {
361 $value = $wgContLang->normalize( $value );
362 } elseif ( $value !== null && !is_scalar( $value ) ) {
363 $type = gettype( $value );
364 if ( is_resource( $value ) ) {
365 $type .= '(' . get_resource_type( $value ) . ')';
366 }
367 throw new InvalidArgumentException( "Cannot add $type to ApiResult" );
368 }
369
370 return $value;
371 }
372
373 /**
374 * Add value to the output data at the given path.
375 *
376 * Path can be an indexed array, each element specifying the branch at which to add the new
377 * value. Setting $path to array('a','b','c') is equivalent to data['a']['b']['c'] = $value.
378 * If $path is null, the value will be inserted at the data root.
379 *
380 * @param array|string|int|null $path
381 * @param string|int|null $name See ApiResult::setValue()
382 * @param mixed $value
383 * @param int $flags Zero or more OR-ed flags like OVERRIDE | ADD_ON_TOP.
384 * This parameter used to be boolean, and the value of OVERRIDE=1 was specifically
385 * chosen so that it would be backwards compatible with the new method signature.
386 * @return bool True if $value fits in the result, false if not
387 * @since 1.21 int $flags replaced boolean $override
388 */
389 public function addValue( $path, $name, $value, $flags = 0 ) {
390 $arr = &$this->path( $path, ( $flags & ApiResult::ADD_ON_TOP ) ? 'prepend' : 'append' );
391
392 if ( $this->checkingSize && !( $flags & ApiResult::NO_SIZE_CHECK ) ) {
393 $newsize = $this->size + self::valueSize( $value );
394 if ( $this->maxSize !== false && $newsize > $this->maxSize ) {
395 /// @todo Add i18n message when replacing calls to ->setWarning()
396 $msg = new ApiRawMessage( 'This result was truncated because it would otherwise ' .
397 ' be larger than the limit of $1 bytes', 'truncatedresult' );
398 $msg->numParams( $this->maxSize );
399 $this->errorFormatter->addWarning( 'result', $msg );
400 return false;
401 }
402 $this->size = $newsize;
403 }
404
405 self::setValue( $arr, $name, $value, $flags );
406 return true;
407 }
408
409 /**
410 * Remove an output value to the array by name.
411 * @param array &$arr To remove $value from
412 * @param string|int $name Index of $arr to remove
413 * @return mixed Old value, or null
414 */
415 public static function unsetValue( array &$arr, $name ) {
416 $ret = null;
417 if ( isset( $arr[$name] ) ) {
418 $ret = $arr[$name];
419 unset( $arr[$name] );
420 }
421 return $ret;
422 }
423
424 /**
425 * Remove value from the output data at the given path.
426 *
427 * @since 1.25
428 * @param array|string|null $path See ApiResult::addValue()
429 * @param string|int|null $name Index to remove at $path.
430 * If null, $path itself is removed.
431 * @param int $flags Flags used when adding the value
432 * @return mixed Old value, or null
433 */
434 public function removeValue( $path, $name, $flags = 0 ) {
435 $path = (array)$path;
436 if ( $name === null ) {
437 if ( !$path ) {
438 throw new InvalidArgumentException( 'Cannot remove the data root' );
439 }
440 $name = array_pop( $path );
441 }
442 $ret = self::unsetValue( $this->path( $path, 'dummy' ), $name );
443 if ( $this->checkingSize && !( $flags & ApiResult::NO_SIZE_CHECK ) ) {
444 $newsize = $this->size - self::valueSize( $ret );
445 $this->size = max( $newsize, 0 );
446 }
447 return $ret;
448 }
449
450 /**
451 * Add an output value to the array by name and mark as META_CONTENT.
452 *
453 * @since 1.25
454 * @param array &$arr To add $value to
455 * @param string|int $name Index of $arr to add $value at.
456 * @param mixed $value
457 * @param int $flags Zero or more OR-ed flags like OVERRIDE | ADD_ON_TOP.
458 */
459 public static function setContentValue( array &$arr, $name, $value, $flags = 0 ) {
460 if ( $name === null ) {
461 throw new InvalidArgumentException( 'Content value must be named' );
462 }
463 self::setContentField( $arr, $name, $flags );
464 self::setValue( $arr, $name, $value, $flags );
465 }
466
467 /**
468 * Add value to the output data at the given path and mark as META_CONTENT
469 *
470 * @since 1.25
471 * @param array|string|null $path See ApiResult::addValue()
472 * @param string|int $name See ApiResult::setValue()
473 * @param mixed $value
474 * @param int $flags Zero or more OR-ed flags like OVERRIDE | ADD_ON_TOP.
475 * @return bool True if $value fits in the result, false if not
476 */
477 public function addContentValue( $path, $name, $value, $flags = 0 ) {
478 if ( $name === null ) {
479 throw new InvalidArgumentException( 'Content value must be named' );
480 }
481 $this->addContentField( $path, $name, $flags );
482 $this->addValue( $path, $name, $value, $flags );
483 }
484
485 /**
486 * Add the numeric limit for a limit=max to the result.
487 *
488 * @since 1.25
489 * @param string $moduleName
490 * @param int $limit
491 */
492 public function addParsedLimit( $moduleName, $limit ) {
493 // Add value, allowing overwriting
494 $this->addValue( 'limits', $moduleName, $limit,
495 ApiResult::OVERRIDE | ApiResult::NO_SIZE_CHECK );
496 }
497
498 /**@}*/
499
500 /************************************************************************//**
501 * @name Metadata
502 * @{
503 */
504
505 /**
506 * Set the name of the content field name (META_CONTENT)
507 *
508 * @since 1.25
509 * @param array &$arr
510 * @param string|int $name Name of the field
511 * @param int $flags Zero or more OR-ed flags like OVERRIDE | ADD_ON_TOP.
512 */
513 public static function setContentField( array &$arr, $name, $flags = 0 ) {
514 if ( isset( $arr[self::META_CONTENT] ) &&
515 isset( $arr[$arr[self::META_CONTENT]] ) &&
516 !( $flags & self::OVERRIDE )
517 ) {
518 throw new RuntimeException(
519 "Attempting to set content element as $name when " . $arr[self::META_CONTENT] .
520 " is already set as the content element"
521 );
522 }
523 $arr[self::META_CONTENT] = $name;
524 }
525
526 /**
527 * Set the name of the content field name (META_CONTENT)
528 *
529 * @since 1.25
530 * @param array|string|null $path See ApiResult::addValue()
531 * @param string|int $name Name of the field
532 * @param int $flags Zero or more OR-ed flags like OVERRIDE | ADD_ON_TOP.
533 */
534 public function addContentField( $path, $name, $flags = 0 ) {
535 $arr = &$this->path( $path, ( $flags & ApiResult::ADD_ON_TOP ) ? 'prepend' : 'append' );
536 self::setContentField( $arr, $name, $flags );
537 }
538
539 /**
540 * Causes the elements with the specified names to be output as
541 * subelements rather than attributes.
542 * @since 1.25 is static
543 * @param array &$arr
544 * @param array|string|int $names The element name(s) to be output as subelements
545 */
546 public static function setSubelementsList( array &$arr, $names ) {
547 if ( !isset( $arr[self::META_SUBELEMENTS] ) ) {
548 $arr[self::META_SUBELEMENTS] = (array)$names;
549 } else {
550 $arr[self::META_SUBELEMENTS] = array_merge( $arr[self::META_SUBELEMENTS], (array)$names );
551 }
552 }
553
554 /**
555 * Causes the elements with the specified names to be output as
556 * subelements rather than attributes.
557 * @since 1.25
558 * @param array|string|null $path See ApiResult::addValue()
559 * @param array|string|int $names The element name(s) to be output as subelements
560 */
561 public function addSubelementsList( $path, $names ) {
562 $arr = &$this->path( $path );
563 self::setSubelementsList( $arr, $names );
564 }
565
566 /**
567 * Causes the elements with the specified names to be output as
568 * attributes (when possible) rather than as subelements.
569 * @since 1.25
570 * @param array &$arr
571 * @param array|string|int $names The element name(s) to not be output as subelements
572 */
573 public static function unsetSubelementsList( array &$arr, $names ) {
574 if ( isset( $arr[self::META_SUBELEMENTS] ) ) {
575 $arr[self::META_SUBELEMENTS] = array_diff( $arr[self::META_SUBELEMENTS], (array)$names );
576 }
577 }
578
579 /**
580 * Causes the elements with the specified names to be output as
581 * attributes (when possible) rather than as subelements.
582 * @since 1.25
583 * @param array|string|null $path See ApiResult::addValue()
584 * @param array|string|int $names The element name(s) to not be output as subelements
585 */
586 public function removeSubelementsList( $path, $names ) {
587 $arr = &$this->path( $path );
588 self::unsetSubelementsList( $arr, $names );
589 }
590
591 /**
592 * Set the tag name for numeric-keyed values in XML format
593 * @since 1.25 is static
594 * @param array &$arr
595 * @param string $tag Tag name
596 */
597 public static function setIndexedTagName( array &$arr, $tag ) {
598 if ( !is_string( $tag ) ) {
599 throw new InvalidArgumentException( 'Bad tag name' );
600 }
601 $arr[self::META_INDEXED_TAG_NAME] = $tag;
602 }
603
604 /**
605 * Set the tag name for numeric-keyed values in XML format
606 * @since 1.25
607 * @param array|string|null $path See ApiResult::addValue()
608 * @param string $tag Tag name
609 */
610 public function addIndexedTagName( $path, $tag ) {
611 $arr = &$this->path( $path );
612 self::setIndexedTagName( $arr, $tag );
613 }
614
615 /**
616 * Set indexed tag name on $arr and all subarrays
617 *
618 * @since 1.25
619 * @param array &$arr
620 * @param string $tag Tag name
621 */
622 public static function setIndexedTagNameRecursive( array &$arr, $tag ) {
623 if ( !is_string( $tag ) ) {
624 throw new InvalidArgumentException( 'Bad tag name' );
625 }
626 $arr[self::META_INDEXED_TAG_NAME] = $tag;
627 foreach ( $arr as $k => &$v ) {
628 if ( !self::isMetadataKey( $k ) && is_array( $v ) ) {
629 self::setIndexedTagNameRecursive( $v, $tag );
630 }
631 }
632 }
633
634 /**
635 * Set indexed tag name on $path and all subarrays
636 *
637 * @since 1.25
638 * @param array|string|null $path See ApiResult::addValue()
639 * @param string $tag Tag name
640 */
641 public function addIndexedTagNameRecursive( $path, $tag ) {
642 $arr = &$this->path( $path );
643 self::setIndexedTagNameRecursive( $arr, $tag );
644 }
645
646 /**
647 * Preserve specified keys.
648 *
649 * This prevents XML name mangling and preventing keys from being removed
650 * by self::stripMetadata().
651 *
652 * @since 1.25
653 * @param array &$arr
654 * @param array|string $names The element name(s) to preserve
655 */
656 public static function setPreserveKeysList( array &$arr, $names ) {
657 if ( !isset( $arr[self::META_PRESERVE_KEYS] ) ) {
658 $arr[self::META_PRESERVE_KEYS] = (array)$names;
659 } else {
660 $arr[self::META_PRESERVE_KEYS] = array_merge( $arr[self::META_PRESERVE_KEYS], (array)$names );
661 }
662 }
663
664 /**
665 * Preserve specified keys.
666 * @since 1.25
667 * @see self::setPreserveKeysList()
668 * @param array|string|null $path See ApiResult::addValue()
669 * @param array|string $names The element name(s) to preserve
670 */
671 public function addPreserveKeysList( $path, $names ) {
672 $arr = &$this->path( $path );
673 self::setPreserveKeysList( $arr, $names );
674 }
675
676 /**
677 * Don't preserve specified keys.
678 * @since 1.25
679 * @see self::setPreserveKeysList()
680 * @param array &$arr
681 * @param array|string $names The element name(s) to not preserve
682 */
683 public static function unsetPreserveKeysList( array &$arr, $names ) {
684 if ( isset( $arr[self::META_PRESERVE_KEYS] ) ) {
685 $arr[self::META_PRESERVE_KEYS] = array_diff( $arr[self::META_PRESERVE_KEYS], (array)$names );
686 }
687 }
688
689 /**
690 * Don't preserve specified keys.
691 * @since 1.25
692 * @see self::setPreserveKeysList()
693 * @param array|string|null $path See ApiResult::addValue()
694 * @param array|string $names The element name(s) to not preserve
695 */
696 public function removePreserveKeysList( $path, $names ) {
697 $arr = &$this->path( $path );
698 self::unsetPreserveKeysList( $arr, $names );
699 }
700
701 /**
702 * Set the array data type
703 *
704 * @since 1.25
705 * @param array &$arr
706 * @param string $type See ApiResult::META_TYPE
707 * @param string $kvpKeyName See ApiResult::META_KVP_KEY_NAME
708 */
709 public static function setArrayType( array &$arr, $type, $kvpKeyName = null ) {
710 if ( !in_array( $type, array(
711 'default', 'array', 'assoc', 'kvp', 'BCarray', 'BCassoc', 'BCkvp'
712 ), true ) ) {
713 throw new InvalidArgumentException( 'Bad type' );
714 }
715 $arr[self::META_TYPE] = $type;
716 if ( is_string( $kvpKeyName ) ) {
717 $arr[self::META_KVP_KEY_NAME] = $kvpKeyName;
718 }
719 }
720
721 /**
722 * Set the array data type for a path
723 * @since 1.25
724 * @param array|string|null $path See ApiResult::addValue()
725 * @param string $type See ApiResult::META_TYPE
726 * @param string $kvpKeyName See ApiResult::META_KVP_KEY_NAME
727 */
728 public function addArrayType( $path, $tag, $kvpKeyName = null ) {
729 $arr = &$this->path( $path );
730 self::setArrayType( $arr, $tag, $kvpKeyName );
731 }
732
733 /**
734 * Set the array data type recursively
735 * @since 1.25
736 * @param array &$arr
737 * @param string $type See ApiResult::META_TYPE
738 * @param string $kvpKeyName See ApiResult::META_KVP_KEY_NAME
739 */
740 public static function setArrayTypeRecursive( array &$arr, $type, $kvpKeyName = null ) {
741 self::setArrayType( $arr, $type, $kvpKeyName );
742 foreach ( $arr as $k => &$v ) {
743 if ( !self::isMetadataKey( $k ) && is_array( $v ) ) {
744 self::setArrayTypeRecursive( $v, $type, $kvpKeyName );
745 }
746 }
747 }
748
749 /**
750 * Set the array data type for a path recursively
751 * @since 1.25
752 * @param array|string|null $path See ApiResult::addValue()
753 * @param string $type See ApiResult::META_TYPE
754 * @param string $kvpKeyName See ApiResult::META_KVP_KEY_NAME
755 */
756 public function addArrayTypeRecursive( $path, $tag, $kvpKeyName = null ) {
757 $arr = &$this->path( $path );
758 self::setArrayTypeRecursive( $arr, $tag, $kvpKeyName );
759 }
760
761 /**@}*/
762
763 /************************************************************************//**
764 * @name Utility
765 * @{
766 */
767
768 /**
769 * Test whether a key should be considered metadata
770 *
771 * @param string $key
772 * @return bool
773 */
774 public static function isMetadataKey( $key ) {
775 return substr( $key, 0, 1 ) === '_';
776 }
777
778 /**
779 * Apply transformations to an array, returning the transformed array.
780 *
781 * @see ApiResult::getResultData()
782 * @since 1.25
783 * @param array $data
784 * @param array $transforms
785 * @return array|object
786 */
787 protected static function applyTransformations( array $dataIn, array $transforms ) {
788 $strip = isset( $transforms['Strip'] ) ? $transforms['Strip'] : 'none';
789 if ( $strip === 'base' ) {
790 $transforms['Strip'] = 'none';
791 }
792 $transformTypes = isset( $transforms['Types'] ) ? $transforms['Types'] : null;
793 if ( $transformTypes !== null && !is_array( $transformTypes ) ) {
794 throw new InvalidArgumentException( __METHOD__ . ':Value for "Types" must be an array' );
795 }
796
797 $metadata = array();
798 $data = self::stripMetadataNonRecursive( $dataIn, $metadata );
799
800 if ( isset( $transforms['Custom'] ) ) {
801 if ( !is_callable( $transforms['Custom'] ) ) {
802 throw new InvalidArgumentException( __METHOD__ . ': Value for "Custom" must be callable' );
803 }
804 call_user_func_array( $transforms['Custom'], array( &$data, &$metadata ) );
805 }
806
807 if ( ( isset( $transforms['BC'] ) || $transformTypes !== null ) &&
808 isset( $metadata[self::META_TYPE] ) && $metadata[self::META_TYPE] === 'BCkvp' &&
809 !isset( $metadata[self::META_KVP_KEY_NAME] )
810 ) {
811 throw new UnexpectedValueException( 'Type "BCkvp" used without setting ' .
812 'ApiResult::META_KVP_KEY_NAME metadata item' );
813 }
814
815 // BC transformations
816 $boolKeys = null;
817 $forceKVP = false;
818 if ( isset( $transforms['BC'] ) ) {
819 if ( !is_array( $transforms['BC'] ) ) {
820 throw new InvalidArgumentException( __METHOD__ . ':Value for "BC" must be an array' );
821 }
822 if ( !in_array( 'nobool', $transforms['BC'], true ) ) {
823 $boolKeys = isset( $metadata[self::META_BC_BOOLS] )
824 ? array_flip( $metadata[self::META_BC_BOOLS] )
825 : array();
826 }
827
828 if ( !in_array( 'no*', $transforms['BC'], true ) &&
829 isset( $metadata[self::META_CONTENT] ) && $metadata[self::META_CONTENT] !== '*'
830 ) {
831 $k = $metadata[self::META_CONTENT];
832 $data['*'] = $data[$k];
833 unset( $data[$k] );
834 $metadata[self::META_CONTENT] = '*';
835 }
836
837 if ( !in_array( 'nosub', $transforms['BC'], true ) &&
838 isset( $metadata[self::META_BC_SUBELEMENTS] )
839 ) {
840 foreach ( $metadata[self::META_BC_SUBELEMENTS] as $k ) {
841 if ( isset( $data[$k] ) ) {
842 $data[$k] = array(
843 '*' => $data[$k],
844 self::META_CONTENT => '*',
845 self::META_TYPE => 'assoc',
846 );
847 }
848 }
849 }
850
851 if ( isset( $metadata[self::META_TYPE] ) ) {
852 switch ( $metadata[self::META_TYPE] ) {
853 case 'BCarray':
854 case 'BCassoc':
855 $metadata[self::META_TYPE] = 'default';
856 break;
857 case 'BCkvp':
858 $transformTypes['ArmorKVP'] = $metadata[self::META_KVP_KEY_NAME];
859 break;
860 }
861 }
862 }
863
864 // Figure out type, do recursive calls, and do boolean transform if necessary
865 $defaultType = 'array';
866 $maxKey = -1;
867 foreach ( $data as $k => &$v ) {
868 $v = is_array( $v ) ? self::applyTransformations( $v, $transforms ) : $v;
869 if ( $boolKeys !== null && is_bool( $v ) && !isset( $boolKeys[$k] ) ) {
870 if ( !$v ) {
871 unset( $data[$k] );
872 continue;
873 }
874 $v = '';
875 }
876 if ( is_string( $k ) ) {
877 $defaultType = 'assoc';
878 } elseif ( $k > $maxKey ) {
879 $maxKey = $k;
880 }
881 }
882 unset( $v );
883
884 // Determine which metadata to keep
885 switch ( $strip ) {
886 case 'all':
887 case 'base':
888 $keepMetadata = array();
889 break;
890 case 'none':
891 $keepMetadata = &$metadata;
892 break;
893 case 'bc':
894 $keepMetadata = array_intersect_key( $metadata, array(
895 self::META_INDEXED_TAG_NAME => 1,
896 self::META_SUBELEMENTS => 1,
897 ) );
898 break;
899 default:
900 throw new InvalidArgumentException( __METHOD__ . ': Unknown value for "Strip"' );
901 }
902
903 // Type transformation
904 if ( $transformTypes !== null ) {
905 if ( $defaultType === 'array' && $maxKey !== count( $data ) - 1 ) {
906 $defaultType = 'assoc';
907 }
908
909 // Override type, if provided
910 $type = $defaultType;
911 if ( isset( $metadata[self::META_TYPE] ) && $metadata[self::META_TYPE] !== 'default' ) {
912 $type = $metadata[self::META_TYPE];
913 }
914 if ( ( $type === 'kvp' || $type === 'BCkvp' ) &&
915 empty( $transformTypes['ArmorKVP'] )
916 ) {
917 $type = 'assoc';
918 } elseif ( $type === 'BCarray' ) {
919 $type = 'array';
920 } elseif ( $type === 'BCassoc' ) {
921 $type = 'assoc';
922 }
923
924 // Apply transformation
925 switch ( $type ) {
926 case 'assoc':
927 $metadata[self::META_TYPE] = 'assoc';
928 $data += $keepMetadata;
929 return empty( $transformTypes['AssocAsObject'] ) ? $data : (object)$data;
930
931 case 'array':
932 ksort( $data );
933 $data = array_values( $data );
934 $metadata[self::META_TYPE] = 'array';
935 return $data + $keepMetadata;
936
937 case 'kvp':
938 case 'BCkvp':
939 $key = isset( $metadata[self::META_KVP_KEY_NAME] )
940 ? $metadata[self::META_KVP_KEY_NAME]
941 : $transformTypes['ArmorKVP'];
942 $valKey = isset( $transforms['BC'] ) ? '*' : 'value';
943 $assocAsObject = !empty( $transformTypes['AssocAsObject'] );
944
945 $ret = array();
946 foreach ( $data as $k => $v ) {
947 $item = array(
948 $key => $k,
949 $valKey => $v,
950 );
951 if ( $strip === 'none' ) {
952 $item += array(
953 self::META_PRESERVE_KEYS => array( $key ),
954 self::META_CONTENT => $valKey,
955 self::META_TYPE => 'assoc',
956 );
957 }
958 $ret[] = $assocAsObject ? (object)$item : $item;
959 }
960 $metadata[self::META_TYPE] = 'array';
961
962 return $ret + $keepMetadata;
963
964 default:
965 throw new UnexpectedValueException( "Unknown type '$type'" );
966 }
967 } else {
968 return $data + $keepMetadata;
969 }
970 }
971
972 /**
973 * Recursively remove metadata keys from a data array or object
974 *
975 * Note this removes all potential metadata keys, not just the defined
976 * ones.
977 *
978 * @since 1.25
979 * @param array|object $data
980 * @return array|object
981 */
982 public static function stripMetadata( $data ) {
983 if ( is_array( $data ) || is_object( $data ) ) {
984 $isObj = is_object( $data );
985 if ( $isObj ) {
986 $data = (array)$data;
987 }
988 $preserveKeys = isset( $data[self::META_PRESERVE_KEYS] )
989 ? (array)$data[self::META_PRESERVE_KEYS]
990 : array();
991 foreach ( $data as $k => $v ) {
992 if ( self::isMetadataKey( $k ) && !in_array( $k, $preserveKeys, true ) ) {
993 unset( $data[$k] );
994 } elseif ( is_array( $v ) || is_object( $v ) ) {
995 $data[$k] = self::stripMetadata( $v );
996 }
997 }
998 if ( $isObj ) {
999 $data = (object)$data;
1000 }
1001 }
1002 return $data;
1003 }
1004
1005 /**
1006 * Remove metadata keys from a data array or object, non-recursive
1007 *
1008 * Note this removes all potential metadata keys, not just the defined
1009 * ones.
1010 *
1011 * @since 1.25
1012 * @param array|object $data
1013 * @param array &$metadata Store metadata here, if provided
1014 * @return array|object
1015 */
1016 public static function stripMetadataNonRecursive( $data, &$metadata = null ) {
1017 if ( !is_array( $metadata ) ) {
1018 $metadata = array();
1019 }
1020 if ( is_array( $data ) || is_object( $data ) ) {
1021 $isObj = is_object( $data );
1022 if ( $isObj ) {
1023 $data = (array)$data;
1024 }
1025 $preserveKeys = isset( $data[self::META_PRESERVE_KEYS] )
1026 ? (array)$data[self::META_PRESERVE_KEYS]
1027 : array();
1028 foreach ( $data as $k => $v ) {
1029 if ( self::isMetadataKey( $k ) && !in_array( $k, $preserveKeys, true ) ) {
1030 $metadata[$k] = $v;
1031 unset( $data[$k] );
1032 }
1033 }
1034 if ( $isObj ) {
1035 $data = (object)$data;
1036 }
1037 }
1038 return $data;
1039 }
1040
1041 /**
1042 * Get the 'real' size of a result item. This means the strlen() of the item,
1043 * or the sum of the strlen()s of the elements if the item is an array.
1044 * @note Once the deprecated public self::size is removed, we can rename
1045 * this back to a less awkward name.
1046 * @param mixed $value
1047 * @return int
1048 */
1049 private static function valueSize( $value ) {
1050 $s = 0;
1051 if ( is_array( $value ) ||
1052 is_object( $value ) && !is_callable( array( $value, '__toString' ) )
1053 ) {
1054 foreach ( $value as $k => $v ) {
1055 if ( !self::isMetadataKey( $s ) ) {
1056 $s += self::valueSize( $v );
1057 }
1058 }
1059 } elseif ( is_scalar( $value ) ) {
1060 $s = strlen( $value );
1061 }
1062
1063 return $s;
1064 }
1065
1066 /**
1067 * Return a reference to the internal data at $path
1068 *
1069 * @param array|string|null $path
1070 * @param string $create
1071 * If 'append', append empty arrays.
1072 * If 'prepend', prepend empty arrays.
1073 * If 'dummy', return a dummy array.
1074 * Else, raise an error.
1075 * @return array
1076 */
1077 private function &path( $path, $create = 'append' ) {
1078 $path = (array)$path;
1079 $ret = &$this->data;
1080 foreach ( $path as $i => $k ) {
1081 if ( !isset( $ret[$k] ) ) {
1082 switch ( $create ) {
1083 case 'append':
1084 $ret[$k] = array();
1085 break;
1086 case 'prepend':
1087 $ret = array( $k => array() ) + $ret;
1088 break;
1089 case 'dummy':
1090 $tmp = array();
1091 return $tmp;
1092 default:
1093 $fail = join( '.', array_slice( $path, 0, $i + 1 ) );
1094 throw new InvalidArgumentException( "Path $fail does not exist" );
1095 }
1096 }
1097 if ( !is_array( $ret[$k] ) ) {
1098 $fail = join( '.', array_slice( $path, 0, $i + 1 ) );
1099 throw new InvalidArgumentException( "Path $fail is not an array" );
1100 }
1101 $ret = &$ret[$k];
1102 }
1103 return $ret;
1104 }
1105
1106 /**
1107 * Add the correct metadata to an array of vars we want to export through
1108 * the API.
1109 *
1110 * @param array $vars
1111 * @param boolean $forceHash
1112 * @return array
1113 */
1114 public static function addMetadataToResultVars( $vars, $forceHash = true ) {
1115 // Process subarrays and determine if this is a JS [] or {}
1116 $hash = $forceHash;
1117 $maxKey = -1;
1118 $bools = array();
1119 foreach ( $vars as $k => $v ) {
1120 if ( is_array( $v ) || is_object( $v ) ) {
1121 $vars[$k] = ApiResult::addMetadataToResultVars( (array)$v, is_object( $v ) );
1122 } elseif ( is_bool( $v ) ) {
1123 // Better here to use real bools even in BC formats
1124 $bools[] = $k;
1125 }
1126 if ( is_string( $k ) ) {
1127 $hash = true;
1128 } elseif ( $k > $maxKey ) {
1129 $maxKey = $k;
1130 }
1131 }
1132 if ( !$hash && $maxKey !== count( $vars ) - 1 ) {
1133 $hash = true;
1134 }
1135
1136 // Set metadata appropriately
1137 if ( $hash ) {
1138 // Get the list of keys we actually care about. Unfortunately, we can't support
1139 // certain keys that conflict with ApiResult metadata.
1140 $keys = array_diff( array_keys( $vars ), array(
1141 ApiResult::META_TYPE, ApiResult::META_PRESERVE_KEYS, ApiResult::META_KVP_KEY_NAME,
1142 ApiResult::META_INDEXED_TAG_NAME, ApiResult::META_BC_BOOLS
1143 ) );
1144
1145 return array(
1146 ApiResult::META_TYPE => 'kvp',
1147 ApiResult::META_KVP_KEY_NAME => 'key',
1148 ApiResult::META_PRESERVE_KEYS => $keys,
1149 ApiResult::META_BC_BOOLS => $bools,
1150 ApiResult::META_INDEXED_TAG_NAME => 'var',
1151 ) + $vars;
1152 } else {
1153 return array(
1154 ApiResult::META_TYPE => 'array',
1155 ApiResult::META_BC_BOOLS => $bools,
1156 ApiResult::META_INDEXED_TAG_NAME => 'value',
1157 ) + $vars;
1158 }
1159 }
1160
1161 /**@}*/
1162
1163 /************************************************************************//**
1164 * @name Deprecated
1165 * @{
1166 */
1167
1168 /**
1169 * Call this function when special elements such as '_element'
1170 * are needed by the formatter, for example in XML printing.
1171 * @deprecated since 1.25, you shouldn't have been using it in the first place
1172 * @since 1.23 $flag parameter added
1173 * @param bool $flag Set the raw mode flag to this state
1174 */
1175 public function setRawMode( $flag = true ) {
1176 // Can't wfDeprecated() here, since we need to set this flag from
1177 // ApiMain for BC with stuff using self::getIsRawMode as
1178 // "self::getIsXMLMode".
1179 $this->isRawMode = $flag;
1180 }
1181
1182 /**
1183 * Returns true whether the formatter requested raw data.
1184 * @deprecated since 1.25, you shouldn't have been using it in the first place
1185 * @return bool
1186 */
1187 public function getIsRawMode() {
1188 /// @todo: After Wikibase stops calling this, warn
1189 return $this->isRawMode;
1190 }
1191
1192 /**
1193 * Get the result's internal data array (read-only)
1194 * @deprecated since 1.25, use $this->getResultData() instead
1195 * @return array
1196 */
1197 public function getData() {
1198 wfDeprecated( __METHOD__, '1.25' );
1199 return $this->getResultData( null, array(
1200 'BC' => array(),
1201 'Types' => array(),
1202 'Strip' => $this->isRawMode ? 'bc' : 'all',
1203 ) );
1204 }
1205
1206 /**
1207 * Disable size checking in addValue(). Don't use this unless you
1208 * REALLY know what you're doing. Values added while size checking
1209 * was disabled will not be counted (ever)
1210 * @deprecated since 1.24, use ApiResult::NO_SIZE_CHECK
1211 */
1212 public function disableSizeCheck() {
1213 wfDeprecated( __METHOD__, '1.24' );
1214 $this->checkingSize = false;
1215 }
1216
1217 /**
1218 * Re-enable size checking in addValue()
1219 * @deprecated since 1.24, use ApiResult::NO_SIZE_CHECK
1220 */
1221 public function enableSizeCheck() {
1222 wfDeprecated( __METHOD__, '1.24' );
1223 $this->checkingSize = true;
1224 }
1225
1226 /**
1227 * Alias for self::setValue()
1228 *
1229 * @since 1.21 int $flags replaced boolean $override
1230 * @deprecated since 1.25, use self::setValue() instead
1231 * @param array $arr To add $value to
1232 * @param string $name Index of $arr to add $value at
1233 * @param mixed $value
1234 * @param int $flags Zero or more OR-ed flags like OVERRIDE | ADD_ON_TOP.
1235 * This parameter used to be boolean, and the value of OVERRIDE=1 was
1236 * specifically chosen so that it would be backwards compatible with the
1237 * new method signature.
1238 */
1239 public static function setElement( &$arr, $name, $value, $flags = 0 ) {
1240 wfDeprecated( __METHOD__, '1.25' );
1241 return self::setValue( $arr, $name, $value, $flags );
1242 }
1243
1244 /**
1245 * Adds a content element to an array.
1246 * Use this function instead of hardcoding the '*' element.
1247 * @deprecated since 1.25, use self::setContentValue() instead
1248 * @param array $arr To add the content element to
1249 * @param mixed $value
1250 * @param string $subElemName When present, content element is created
1251 * as a sub item of $arr. Use this parameter to create elements in
1252 * format "<elem>text</elem>" without attributes.
1253 */
1254 public static function setContent( &$arr, $value, $subElemName = null ) {
1255 wfDeprecated( __METHOD__, '1.25' );
1256 if ( is_array( $value ) ) {
1257 throw new InvalidArgumentException( __METHOD__ . ': Bad parameter' );
1258 }
1259 if ( is_null( $subElemName ) ) {
1260 self::setContentValue( $arr, 'content', $value );
1261 } else {
1262 if ( !isset( $arr[$subElemName] ) ) {
1263 $arr[$subElemName] = array();
1264 }
1265 self::setContentValue( $arr[$subElemName], 'content', $value );
1266 }
1267 }
1268
1269 /**
1270 * Set indexed tag name on all subarrays of $arr
1271 *
1272 * Does not set the tag name for $arr itself.
1273 *
1274 * @deprecated since 1.25, use self::setIndexedTagNameRecursive() instead
1275 * @param array $arr
1276 * @param string $tag Tag name
1277 */
1278 public function setIndexedTagName_recursive( &$arr, $tag ) {
1279 wfDeprecated( __METHOD__, '1.25' );
1280 if ( !is_array( $arr ) ) {
1281 return;
1282 }
1283 if ( !is_string( $tag ) ) {
1284 throw new InvalidArgumentException( 'Bad tag name' );
1285 }
1286 foreach ( $arr as $k => &$v ) {
1287 if ( !self::isMetadataKey( $k ) && is_array( $v ) ) {
1288 $v[self::META_INDEXED_TAG_NAME] = $tag;
1289 $this->setIndexedTagName_recursive( $v, $tag );
1290 }
1291 }
1292 }
1293
1294 /**
1295 * Alias for self::addIndexedTagName()
1296 * @deprecated since 1.25, use $this->addIndexedTagName() instead
1297 * @param array $path Path to the array, like addValue()'s $path
1298 * @param string $tag
1299 */
1300 public function setIndexedTagName_internal( $path, $tag ) {
1301 wfDeprecated( __METHOD__, '1.25' );
1302 $this->addIndexedTagName( $path, $tag );
1303 }
1304
1305 /**
1306 * Alias for self::addParsedLimit()
1307 * @deprecated since 1.25, use $this->addParsedLimit() instead
1308 * @param string $moduleName
1309 * @param int $limit
1310 */
1311 public function setParsedLimit( $moduleName, $limit ) {
1312 wfDeprecated( __METHOD__, '1.25' );
1313 $this->addParsedLimit( $moduleName, $limit );
1314 }
1315
1316 /**
1317 * Set the ApiMain for use by $this->beginContinuation()
1318 * @since 1.25
1319 * @deprecated for backwards compatibility only, do not use
1320 * @param ApiMain $main
1321 */
1322 public function setMainForContinuation( ApiMain $main ) {
1323 $this->mainForContinuation = $main;
1324 }
1325
1326 /**
1327 * Parse a 'continue' parameter and return status information.
1328 *
1329 * This must be balanced by a call to endContinuation().
1330 *
1331 * @since 1.24
1332 * @deprecated since 1.25, use ApiContinuationManager instead
1333 * @param string|null $continue
1334 * @param ApiBase[] $allModules
1335 * @param array $generatedModules
1336 * @return array
1337 */
1338 public function beginContinuation(
1339 $continue, array $allModules = array(), array $generatedModules = array()
1340 ) {
1341 wfDeprecated( __METHOD__, '1.25' );
1342 if ( $this->mainForContinuation->getContinuationManager() ) {
1343 throw new UnexpectedValueException(
1344 __METHOD__ . ': Continuation already in progress from ' .
1345 $this->mainForContinuation->getContinuationManager()->getSource()
1346 );
1347 }
1348
1349 // Ugh. If $continue doesn't match that in the request, temporarily
1350 // replace the request when creating the ApiContinuationManager.
1351 if ( $continue === null ) {
1352 $continue = '';
1353 }
1354 if ( $this->mainForContinuation->getVal( 'continue', '' ) !== $continue ) {
1355 $oldCtx = $this->mainForContinuation->getContext();
1356 $newCtx = new DerivativeContext( $oldCtx );
1357 $newCtx->setRequest( new DerivativeRequest(
1358 $oldCtx->getRequest(),
1359 array( 'continue' => $continue ) + $oldCtx->getRequest()->getValues(),
1360 $oldCtx->getRequest()->wasPosted()
1361 ) );
1362 $this->mainForContinuation->setContext( $newCtx );
1363 $reset = new ScopedCallback(
1364 array( $this->mainForContinuation, 'setContext' ),
1365 array( $oldCtx )
1366 );
1367 }
1368 $manager = new ApiContinuationManager(
1369 $this->mainForContinuation, $allModules, $generatedModules
1370 );
1371 $reset = null;
1372
1373 $this->mainForContinuation->setContinuationManager( $manager );
1374
1375 return array(
1376 $manager->isGeneratorDone(),
1377 $manager->getRunModules(),
1378 );
1379 }
1380
1381 /**
1382 * @since 1.24
1383 * @deprecated since 1.25, use ApiContinuationManager instead
1384 * @param ApiBase $module
1385 * @param string $paramName
1386 * @param string|array $paramValue
1387 */
1388 public function setContinueParam( ApiBase $module, $paramName, $paramValue ) {
1389 wfDeprecated( __METHOD__, '1.25' );
1390 if ( $this->mainForContinuation->getContinuationManager() ) {
1391 $this->mainForContinuation->getContinuationManager()->addContinueParam(
1392 $module, $paramName, $paramValue
1393 );
1394 }
1395 }
1396
1397 /**
1398 * @since 1.24
1399 * @deprecated since 1.25, use ApiContinuationManager instead
1400 * @param ApiBase $module
1401 * @param string $paramName
1402 * @param string|array $paramValue
1403 */
1404 public function setGeneratorContinueParam( ApiBase $module, $paramName, $paramValue ) {
1405 wfDeprecated( __METHOD__, '1.25' );
1406 if ( $this->mainForContinuation->getContinuationManager() ) {
1407 $this->mainForContinuation->getContinuationManager()->addGeneratorContinueParam(
1408 $module, $paramName, $paramValue
1409 );
1410 }
1411 }
1412
1413 /**
1414 * Close continuation, writing the data into the result
1415 * @since 1.24
1416 * @deprecated since 1.25, use ApiContinuationManager instead
1417 * @param string $style 'standard' for the new style since 1.21, 'raw' for
1418 * the style used in 1.20 and earlier.
1419 */
1420 public function endContinuation( $style = 'standard' ) {
1421 wfDeprecated( __METHOD__, '1.25' );
1422 if ( !$this->mainForContinuation->getContinuationManager() ) {
1423 return;
1424 }
1425
1426 if ( $style === 'raw' ) {
1427 $data = $this->mainForContinuation->getContinuationManager()->getRawContinuation();
1428 if ( $data ) {
1429 $this->addValue( null, 'query-continue', $data, self::ADD_ON_TOP | self::NO_SIZE_CHECK );
1430 }
1431 } else {
1432 $this->mainForContinuation->getContinuationManager()->setContinuationIntoResult( $this );
1433 }
1434 }
1435
1436 /**
1437 * No-op, this is now checked on insert.
1438 * @deprecated since 1.25
1439 */
1440 public function cleanUpUTF8() {
1441 wfDeprecated( __METHOD__, '1.25' );
1442 }
1443
1444 /**
1445 * Get the 'real' size of a result item. This means the strlen() of the item,
1446 * or the sum of the strlen()s of the elements if the item is an array.
1447 * @deprecated since 1.25, no external users known and there doesn't seem
1448 * to be any case for such use over just checking the return value from the
1449 * add/set methods.
1450 * @param mixed $value
1451 * @return int
1452 */
1453 public static function size( $value ) {
1454 wfDeprecated( __METHOD__, '1.25' );
1455 return self::valueSize( $value );
1456 }
1457
1458 /**
1459 * Converts a Status object to an array suitable for addValue
1460 * @deprecated since 1.25, use ApiErrorFormatter::arrayFromStatus()
1461 * @param Status $status
1462 * @param string $errorType
1463 * @return array
1464 */
1465 public function convertStatusToArray( $status, $errorType = 'error' ) {
1466 wfDeprecated( __METHOD__, '1.25' );
1467 return $this->errorFormatter->arrayFromStatus( $status, $errorType );
1468 }
1469
1470 /**@}*/
1471 }
1472
1473 /**
1474 * For really cool vim folding this needs to be at the end:
1475 * vim: foldmarker=@{,@} foldmethod=marker
1476 */