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