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