MediaWiki master
ParamValidator.php
Go to the documentation of this file.
1<?php
2
4
5use DomainException;
6use InvalidArgumentException;
7use Wikimedia\Assert\Assert;
12use Wikimedia\ObjectFactory\ObjectFactory;
13
43
44 // region Constants for parameter settings arrays
68 public const PARAM_DEFAULT = 'param-default';
69
76 public const PARAM_TYPE = 'param-type';
77
84 public const PARAM_REQUIRED = 'param-required';
85
112 public const PARAM_ISMULTI = 'param-ismulti';
113
119 public const PARAM_ISMULTI_LIMIT1 = 'param-ismulti-limit1';
120
127 public const PARAM_ISMULTI_LIMIT2 = 'param-ismulti-limit2';
128
137 public const PARAM_ALL = 'param-all';
138
145 public const PARAM_ALLOW_DUPLICATES = 'param-allow-duplicates';
146
153 public const PARAM_SENSITIVE = 'param-sensitive';
154
161 public const PARAM_DEPRECATED = 'param-deprecated';
162
168 public const PARAM_IGNORE_UNRECOGNIZED_VALUES = 'param-ignore-unrecognized-values';
169
171 // endregion -- end of Constants for parameter settings arrays
172
177
179 public const ALL_DEFAULT_STRING = '*';
180
182 public static $STANDARD_TYPES = [
183 'boolean' => [ 'class' => TypeDef\BooleanDef::class ],
184 'checkbox' => [ 'class' => TypeDef\PresenceBooleanDef::class ],
185 'integer' => [ 'class' => TypeDef\IntegerDef::class ],
186 'limit' => [ 'class' => TypeDef\LimitDef::class ],
187 'float' => [ 'class' => TypeDef\FloatDef::class ],
188 'double' => [ 'class' => TypeDef\FloatDef::class ],
189 'string' => [ 'class' => TypeDef\StringDef::class ],
190 'password' => [ 'class' => TypeDef\PasswordDef::class ],
191 'NULL' => [
192 'class' => TypeDef\StringDef::class,
193 'args' => [ [
194 TypeDef\StringDef::OPT_ALLOW_EMPTY => true,
195 ] ],
196 ],
197 'timestamp' => [ 'class' => TypeDef\TimestampDef::class ],
198 'upload' => [ 'class' => TypeDef\UploadDef::class ],
199 'enum' => [ 'class' => TypeDef\EnumDef::class ],
200 'expiry' => [ 'class' => TypeDef\ExpiryDef::class ],
201 ];
202
204 private $callbacks;
205
207 private $objectFactory;
208
210 private $typeDefs = [];
211
213 private $ismultiLimit1;
214
216 private $ismultiLimit2;
217
227 public function __construct(
228 Callbacks $callbacks,
229 ObjectFactory $objectFactory,
230 array $options = []
231 ) {
232 $this->callbacks = $callbacks;
233 $this->objectFactory = $objectFactory;
234
235 $this->addTypeDefs( $options['typeDefs'] ?? self::$STANDARD_TYPES );
236 $this->ismultiLimit1 = $options['ismultiLimits'][0] ?? 50;
237 $this->ismultiLimit2 = $options['ismultiLimits'][1] ?? 500;
238 }
239
244 public function knownTypes() {
245 return array_keys( $this->typeDefs );
246 }
247
254 public function addTypeDefs( array $typeDefs ) {
255 foreach ( $typeDefs as $name => $def ) {
256 $this->addTypeDef( $name, $def );
257 }
258 }
259
273 public function addTypeDef( $name, $typeDef ) {
274 Assert::parameterType(
275 [ TypeDef::class, 'array' ],
276 $typeDef,
277 '$typeDef'
278 );
279
280 if ( isset( $this->typeDefs[$name] ) ) {
281 throw new InvalidArgumentException( "Type '$name' is already registered" );
282 }
283 $this->typeDefs[$name] = $typeDef;
284 }
285
292 public function overrideTypeDef( $name, $typeDef ) {
293 Assert::parameterType(
294 [ TypeDef::class, 'array', 'null' ],
295 $typeDef,
296 '$typeDef'
297 );
298
299 if ( $typeDef === null ) {
300 unset( $this->typeDefs[$name] );
301 } else {
302 $this->typeDefs[$name] = $typeDef;
303 }
304 }
305
311 public function hasTypeDef( $name ) {
312 return isset( $this->typeDefs[$name] );
313 }
314
320 public function getTypeDef( $type ) {
321 if ( is_array( $type ) ) {
322 $type = 'enum';
323 }
324
325 if ( !isset( $this->typeDefs[$type] ) ) {
326 return null;
327 }
328
329 $def = $this->typeDefs[$type];
330 if ( !$def instanceof TypeDef ) {
331 $def = $this->objectFactory->createObject( $def, [
332 'extraArgs' => [ $this->callbacks ],
333 'assertClass' => TypeDef::class,
334 ] );
335 $this->typeDefs[$type] = $def;
336 }
337
338 return $def;
339 }
340
346 private function normalizeSettingsInternal( $settings ) {
347 // Shorthand
348 if ( !is_array( $settings ) ) {
349 $settings = [
350 self::PARAM_DEFAULT => $settings,
351 ];
352 }
353
354 // When type is not given, determine it from the type of the PARAM_DEFAULT
355 if ( !isset( $settings[self::PARAM_TYPE] ) ) {
356 $settings[self::PARAM_TYPE] = gettype( $settings[self::PARAM_DEFAULT] ?? null );
357 }
358
359 return $settings;
360 }
361
368 public function normalizeSettings( $settings ) {
369 $settings = $this->normalizeSettingsInternal( $settings );
370
371 $typeDef = $this->getTypeDef( $settings[self::PARAM_TYPE] );
372 if ( $typeDef ) {
373 $settings = $typeDef->normalizeSettings( $settings );
374 }
375
376 return $settings;
377 }
378
397 public function checkSettings( string $name, $settings, array $options ): array {
398 $settings = $this->normalizeSettingsInternal( $settings );
399 $issues = [];
400 $allowedKeys = [
403 ];
404 $messages = [];
405
406 $type = $settings[self::PARAM_TYPE];
407 $typeDef = null;
408 if ( !is_string( $type ) && !is_array( $type ) ) {
409 $issues[self::PARAM_TYPE] = 'PARAM_TYPE must be a string or array, got ' . gettype( $type );
410 } else {
411 $typeDef = $this->getTypeDef( $settings[self::PARAM_TYPE] );
412 if ( !$typeDef ) {
413 if ( is_array( $type ) ) {
414 $type = 'enum';
415 }
416 $issues[self::PARAM_TYPE] = "Unknown/unregistered PARAM_TYPE \"$type\"";
417 }
418 }
419
420 if ( isset( $settings[self::PARAM_DEFAULT] ) ) {
421 try {
422 $this->validateValue(
423 $name, $settings[self::PARAM_DEFAULT], $settings, [ 'is-default' => true ] + $options
424 );
425 } catch ( ValidationException $ex ) {
426 $issues[self::PARAM_DEFAULT] = 'Value for PARAM_DEFAULT does not validate (code '
427 . $ex->getFailureMessage()->getCode() . ')';
428 }
429 }
430
431 if ( !is_bool( $settings[self::PARAM_REQUIRED] ?? false ) ) {
432 $issues[self::PARAM_REQUIRED] = 'PARAM_REQUIRED must be boolean, got '
433 . gettype( $settings[self::PARAM_REQUIRED] );
434 }
435
436 if ( !is_bool( $settings[self::PARAM_ISMULTI] ?? false ) ) {
437 $issues[self::PARAM_ISMULTI] = 'PARAM_ISMULTI must be boolean, got '
438 . gettype( $settings[self::PARAM_ISMULTI] );
439 }
440
441 if ( !empty( $settings[self::PARAM_ISMULTI] ) ) {
442 $allowedKeys = array_merge( $allowedKeys, [
443 self::PARAM_ISMULTI_LIMIT1, self::PARAM_ISMULTI_LIMIT2,
444 self::PARAM_ALL, self::PARAM_ALLOW_DUPLICATES
445 ] );
446
447 $limit1 = $settings[self::PARAM_ISMULTI_LIMIT1] ?? $this->ismultiLimit1;
448 $limit2 = $settings[self::PARAM_ISMULTI_LIMIT2] ?? $this->ismultiLimit2;
449 if ( !is_int( $limit1 ) ) {
450 $issues[self::PARAM_ISMULTI_LIMIT1] = 'PARAM_ISMULTI_LIMIT1 must be an integer, got '
451 . gettype( $settings[self::PARAM_ISMULTI_LIMIT1] );
452 } elseif ( $limit1 <= 0 ) {
454 "PARAM_ISMULTI_LIMIT1 must be greater than 0, got $limit1";
455 }
456 if ( !is_int( $limit2 ) ) {
457 $issues[self::PARAM_ISMULTI_LIMIT2] = 'PARAM_ISMULTI_LIMIT2 must be an integer, got '
458 . gettype( $settings[self::PARAM_ISMULTI_LIMIT2] );
459 } elseif ( $limit2 < $limit1 ) {
461 'PARAM_ISMULTI_LIMIT2 must be greater than or equal to PARAM_ISMULTI_LIMIT1, but '
462 . "$limit2 < $limit1";
463 }
464
465 $all = $settings[self::PARAM_ALL] ?? false;
466 if ( !is_string( $all ) && !is_bool( $all ) ) {
467 $issues[self::PARAM_ALL] = 'PARAM_ALL must be a string or boolean, got ' . gettype( $all );
468 } elseif ( $all !== false && $typeDef ) {
469 if ( $all === true ) {
471 }
472 $values = $typeDef->getEnumValues( $name, $settings, $options );
473 if ( !is_array( $values ) ) {
474 $issues[self::PARAM_ALL] = 'PARAM_ALL cannot be used with non-enumerated types';
475 } elseif ( in_array( $all, $values, true ) ) {
476 $issues[self::PARAM_ALL] = 'Value for PARAM_ALL conflicts with an enumerated value';
477 }
478 }
479
480 if ( !is_bool( $settings[self::PARAM_ALLOW_DUPLICATES] ?? false ) ) {
481 $issues[self::PARAM_ALLOW_DUPLICATES] = 'PARAM_ALLOW_DUPLICATES must be boolean, got '
482 . gettype( $settings[self::PARAM_ALLOW_DUPLICATES] );
483 }
484 }
485
486 if ( !is_bool( $settings[self::PARAM_SENSITIVE] ?? false ) ) {
487 $issues[self::PARAM_SENSITIVE] = 'PARAM_SENSITIVE must be boolean, got '
488 . gettype( $settings[self::PARAM_SENSITIVE] );
489 }
490
491 if ( !is_bool( $settings[self::PARAM_DEPRECATED] ?? false ) ) {
492 $issues[self::PARAM_DEPRECATED] = 'PARAM_DEPRECATED must be boolean, got '
493 . gettype( $settings[self::PARAM_DEPRECATED] );
494 }
495
496 if ( !is_bool( $settings[self::PARAM_IGNORE_UNRECOGNIZED_VALUES] ?? false ) ) {
497 $issues[self::PARAM_IGNORE_UNRECOGNIZED_VALUES] = 'PARAM_IGNORE_UNRECOGNIZED_VALUES must be '
498 . 'boolean, got ' . gettype( $settings[self::PARAM_IGNORE_UNRECOGNIZED_VALUES] );
499 }
500
501 $ret = [ 'issues' => $issues, 'allowedKeys' => $allowedKeys, 'messages' => $messages ];
502 if ( $typeDef ) {
503 $ret = $typeDef->checkSettings( $name, $settings, $options, $ret );
504 }
505
506 return $ret;
507 }
508
520 public function getValue( $name, $settings, array $options = [] ) {
521 $settings = $this->normalizeSettings( $settings );
522
523 $typeDef = $this->getTypeDef( $settings[self::PARAM_TYPE] );
524 if ( !$typeDef ) {
525 throw new DomainException(
526 "Param $name's type is unknown - {$settings[self::PARAM_TYPE]}"
527 );
528 }
529
530 $value = $typeDef->getValue( $name, $settings, $options );
531
532 if ( $value !== null ) {
533 if ( !empty( $settings[self::PARAM_SENSITIVE] ) ) {
534 $strValue = $typeDef->stringifyValue( $name, $value, $settings, $options );
535 $this->callbacks->recordCondition(
536 DataMessageValue::new( 'paramvalidator-param-sensitive', [], 'param-sensitive' )
537 ->plaintextParams( $name, $strValue ),
538 $name, $value, $settings, $options
539 );
540 }
541
542 // Set a warning if a deprecated parameter has been passed
543 if ( !empty( $settings[self::PARAM_DEPRECATED] ) ) {
544 $strValue = $typeDef->stringifyValue( $name, $value, $settings, $options );
545 $this->callbacks->recordCondition(
546 DataMessageValue::new( 'paramvalidator-param-deprecated', [], 'param-deprecated' )
547 ->plaintextParams( $name, $strValue ),
548 $name, $value, $settings, $options
549 );
550 }
551 } elseif ( isset( $settings[self::PARAM_DEFAULT] ) ) {
552 $value = $settings[self::PARAM_DEFAULT];
553 $options['is-default'] = true;
554 }
555
556 return $this->validateValue( $name, $value, $settings, $options );
557 }
558
572 public function validateValue( $name, $value, $settings, array $options = [] ) {
573 $settings = $this->normalizeSettings( $settings );
574
575 $typeDef = $this->getTypeDef( $settings[self::PARAM_TYPE] );
576 if ( !$typeDef ) {
577 throw new DomainException(
578 "Param $name's type is unknown - {$settings[self::PARAM_TYPE]}"
579 );
580 }
581
582 if ( $value === null ) {
583 if ( !empty( $settings[self::PARAM_REQUIRED] ) ) {
584 throw new ValidationException(
585 DataMessageValue::new( 'paramvalidator-missingparam', [], 'missingparam' )
586 ->plaintextParams( $name ),
587 $name, $value, $settings
588 );
589 }
590 return null;
591 }
592
593 // Non-multi
594 if ( empty( $settings[self::PARAM_ISMULTI] ) ) {
595 if ( is_string( $value ) && substr( $value, 0, 1 ) === "\x1f" ) {
596 throw new ValidationException(
597 DataMessageValue::new( 'paramvalidator-notmulti', [], 'badvalue' )
598 ->plaintextParams( $name, $value ),
599 $name, $value, $settings
600 );
601 }
602
603 // T326764: If the type of the actual param value is different from
604 // the type that is defined via getParamSettings(), throw an exception
605 // because this is a type to value mismatch.
606 if ( is_array( $value ) && !$typeDef->supportsArrays() ) {
607 throw new ValidationException(
608 DataMessageValue::new( 'paramvalidator-notmulti', [], 'badvalue' )
609 ->plaintextParams( $name, gettype( $value ) ),
610 $name, $value, $settings
611 );
612 }
613
614 return $typeDef->validate( $name, $value, $settings, $options );
615 }
616
617 // Split the multi-value and validate each parameter
618 $limit1 = $settings[self::PARAM_ISMULTI_LIMIT1] ?? $this->ismultiLimit1;
619 $limit2 = max( $limit1, $settings[self::PARAM_ISMULTI_LIMIT2] ?? $this->ismultiLimit2 );
620
621 if ( is_array( $value ) ) {
622 $valuesList = $value;
623 } elseif ( $options[ self::OPT_ENFORCE_JSON_TYPES ] ?? false ) {
624 throw new ValidationException(
625 DataMessageValue::new(
626 'paramvalidator-multivalue-must-be-array',
627 [],
628 'multivalue-must-be-array'
629 )->plaintextParams( $name ),
630 $name, $value, $settings
631 );
632 } else {
633 $valuesList = self::explodeMultiValue( $value, $limit2 + 1 );
634 }
635
636 // Handle PARAM_ALL
637 $enumValues = $typeDef->getEnumValues( $name, $settings, $options );
638 if ( is_array( $enumValues ) && isset( $settings[self::PARAM_ALL] ) &&
639 count( $valuesList ) === 1
640 ) {
641 $allValue = is_string( $settings[self::PARAM_ALL] )
642 ? $settings[self::PARAM_ALL]
643 : self::ALL_DEFAULT_STRING;
644 if ( $valuesList[0] === $allValue ) {
645 return $enumValues;
646 }
647 }
648
649 // Avoid checking useHighLimits() unless it's actually necessary
650 $sizeLimit = (
651 $limit2 > $limit1 && count( $valuesList ) > $limit1 &&
652 $this->callbacks->useHighLimits( $options )
653 ) ? $limit2 : $limit1;
654 if ( count( $valuesList ) > $sizeLimit ) {
655 throw new ValidationException(
656 DataMessageValue::new( 'paramvalidator-toomanyvalues', [], 'toomanyvalues', [
657 'parameter' => $name,
658 'limit' => $sizeLimit,
659 'lowlimit' => $limit1,
660 'highlimit' => $limit2,
661 ] )->plaintextParams( $name )->numParams( $sizeLimit ),
662 $name, $valuesList, $settings
663 );
664 }
665
666 $options['values-list'] = $valuesList;
667 $validValues = [];
668 $invalidValues = [];
669 foreach ( $valuesList as $v ) {
670 try {
671 $validValues[] = $typeDef->validate( $name, $v, $settings, $options );
672 } catch ( ValidationException $ex ) {
673 if ( $ex->getFailureMessage()->getCode() !== 'badvalue' ||
674 empty( $settings[self::PARAM_IGNORE_UNRECOGNIZED_VALUES] )
675 ) {
676 throw $ex;
677 }
678 $invalidValues[] = $v;
679 }
680 }
681 if ( $invalidValues ) {
682 if ( is_array( $value ) ) {
683 $value = self::implodeMultiValue( $value );
684 }
685 $this->callbacks->recordCondition(
686 DataMessageValue::new( 'paramvalidator-unrecognizedvalues', [], 'unrecognizedvalues', [
687 'values' => $invalidValues,
688 ] )
689 ->plaintextParams( $name, $value )
690 ->commaListParams( array_map( static function ( $v ) {
691 return new ScalarParam( ParamType::PLAINTEXT, $v );
692 }, $invalidValues ) )
693 ->numParams( count( $invalidValues ) ),
694 $name, $value, $settings, $options
695 );
696 }
697
698 // Throw out duplicates if requested
699 if ( empty( $settings[self::PARAM_ALLOW_DUPLICATES] ) ) {
700 $validValues = array_values( array_unique( $validValues ) );
701 }
702
703 return $validValues;
704 }
705
715 public function getParamInfo( $name, $settings, array $options ) {
716 $settings = $this->normalizeSettings( $settings );
717 $typeDef = $this->getTypeDef( $settings[self::PARAM_TYPE] );
718 $info = [];
719
720 $info['type'] = $settings[self::PARAM_TYPE];
721 $info['required'] = !empty( $settings[self::PARAM_REQUIRED] );
722 if ( !empty( $settings[self::PARAM_DEPRECATED] ) ) {
723 $info['deprecated'] = true;
724 }
725 if ( !empty( $settings[self::PARAM_SENSITIVE] ) ) {
726 $info['sensitive'] = true;
727 }
728 if ( isset( $settings[self::PARAM_DEFAULT] ) ) {
729 $info['default'] = $settings[self::PARAM_DEFAULT];
730 }
731 $info['multi'] = !empty( $settings[self::PARAM_ISMULTI] );
732 if ( $info['multi'] ) {
733 $info['lowlimit'] = $settings[self::PARAM_ISMULTI_LIMIT1] ?? $this->ismultiLimit1;
734 $info['highlimit'] = max(
735 $info['lowlimit'], $settings[self::PARAM_ISMULTI_LIMIT2] ?? $this->ismultiLimit2
736 );
737 $info['limit'] =
738 $info['highlimit'] > $info['lowlimit'] && $this->callbacks->useHighLimits( $options )
739 ? $info['highlimit']
740 : $info['lowlimit'];
741
742 if ( !empty( $settings[self::PARAM_ALLOW_DUPLICATES] ) ) {
743 $info['allowsduplicates'] = true;
744 }
745
746 $allSpecifier = $settings[self::PARAM_ALL] ?? false;
747 if ( $allSpecifier !== false ) {
748 if ( !is_string( $allSpecifier ) ) {
749 $allSpecifier = self::ALL_DEFAULT_STRING;
750 }
751 $info['allspecifier'] = $allSpecifier;
752 }
753 }
754
755 if ( $typeDef ) {
756 $info = array_merge( $info, $typeDef->getParamInfo( $name, $settings, $options ) );
757 }
758
759 // Filter out nulls (strictly)
760 return array_filter( $info, static function ( $v ) {
761 return $v !== null;
762 } );
763 }
764
774 public function getHelpInfo( $name, $settings, array $options ) {
775 $settings = $this->normalizeSettings( $settings );
776 $typeDef = $this->getTypeDef( $settings[self::PARAM_TYPE] );
777
778 // Define ordering. Some are overwritten below, some expected from the TypeDef
779 $info = [
780 self::PARAM_DEPRECATED => null,
781 self::PARAM_REQUIRED => null,
782 self::PARAM_SENSITIVE => null,
783 self::PARAM_TYPE => null,
784 self::PARAM_ISMULTI => null,
785 self::PARAM_ISMULTI_LIMIT1 => null,
786 self::PARAM_ALL => null,
787 self::PARAM_DEFAULT => null,
788 ];
789
790 if ( !empty( $settings[self::PARAM_DEPRECATED] ) ) {
791 $info[self::PARAM_DEPRECATED] = MessageValue::new( 'paramvalidator-help-deprecated' );
792 }
793
794 if ( !empty( $settings[self::PARAM_REQUIRED] ) ) {
795 $info[self::PARAM_REQUIRED] = MessageValue::new( 'paramvalidator-help-required' );
796 }
797
798 if ( !empty( $settings[self::PARAM_ISMULTI] ) ) {
799 $info[self::PARAM_ISMULTI] = MessageValue::new( 'paramvalidator-help-multi-separate' );
800
801 $lowcount = $settings[self::PARAM_ISMULTI_LIMIT1] ?? $this->ismultiLimit1;
802 $highcount = max( $lowcount, $settings[self::PARAM_ISMULTI_LIMIT2] ?? $this->ismultiLimit2 );
803 $values = $typeDef ? $typeDef->getEnumValues( $name, $settings, $options ) : null;
804 if (
805 // Only mention the limits if they're likely to matter.
806 $values === null || count( $values ) > $lowcount ||
807 !empty( $settings[self::PARAM_ALLOW_DUPLICATES] )
808 ) {
809 if ( $highcount > $lowcount ) {
810 $info[self::PARAM_ISMULTI_LIMIT1] = MessageValue::new( 'paramvalidator-help-multi-max' )
811 ->numParams( $lowcount, $highcount );
812 } else {
813 $info[self::PARAM_ISMULTI_LIMIT1] = MessageValue::new( 'paramvalidator-help-multi-max-simple' )
814 ->numParams( $lowcount );
815 }
816 }
817
818 $allSpecifier = $settings[self::PARAM_ALL] ?? false;
819 if ( $allSpecifier !== false ) {
820 if ( !is_string( $allSpecifier ) ) {
821 $allSpecifier = self::ALL_DEFAULT_STRING;
822 }
823 $info[self::PARAM_ALL] = MessageValue::new( 'paramvalidator-help-multi-all' )
824 ->plaintextParams( $allSpecifier );
825 }
826 }
827
828 if ( isset( $settings[self::PARAM_DEFAULT] ) && $typeDef ) {
829 $value = $typeDef->stringifyValue( $name, $settings[self::PARAM_DEFAULT], $settings, $options );
830 if ( $value === '' ) {
831 $info[self::PARAM_DEFAULT] = MessageValue::new( 'paramvalidator-help-default-empty' );
832 } elseif ( $value !== null ) {
833 $info[self::PARAM_DEFAULT] = MessageValue::new( 'paramvalidator-help-default' )
834 ->plaintextParams( $value );
835 }
836 }
837
838 if ( $typeDef ) {
839 $info = array_merge( $info, $typeDef->getHelpInfo( $name, $settings, $options ) );
840 }
841
842 // Put the default at the very end (the TypeDef may have added extra messages)
843 $default = $info[self::PARAM_DEFAULT];
844 unset( $info[self::PARAM_DEFAULT] );
845 $info[self::PARAM_DEFAULT] = $default;
846
847 // Filter out nulls
848 return array_filter( $info );
849 }
850
861 public static function explodeMultiValue( $value, $limit ) {
862 if ( $value === '' || $value === "\x1f" ) {
863 return [];
864 }
865
866 if ( substr( $value, 0, 1 ) === "\x1f" ) {
867 $sep = "\x1f";
868 $value = substr( $value, 1 );
869 } else {
870 $sep = '|';
871 }
872
873 return explode( $sep, $value, $limit );
874 }
875
882 public static function implodeMultiValue( array $value ) {
883 if ( $value === [ '' ] ) {
884 // There's no value that actually returns a single empty string.
885 // Best we can do is this that returns two, which will be deduplicated to one.
886 return '|';
887 }
888
889 foreach ( $value as $v ) {
890 if ( strpos( $v, '|' ) !== false ) {
891 return "\x1f" . implode( "\x1f", $value );
892 }
893 }
894 return implode( '|', $value );
895 }
896
897}
Value object representing a message for i18n with alternative machine-readable data.
Value object representing a message for i18n.
The constants used to specify parameter types.
Definition ParamType.php:11
const PLAINTEXT
A text parameter which is substituted after formatter processing.
Definition ParamType.php:98
Value object representing a message parameter holding a single value.
Service for formatting and validating API parameters.
__construct(Callbacks $callbacks, ObjectFactory $objectFactory, array $options=[])
getValue( $name, $settings, array $options=[])
Fetch and validate a parameter value using a settings array.
normalizeSettings( $settings)
Normalize a parameter settings array.
const PARAM_ALLOW_DUPLICATES
(bool) Allow the same value to be set more than once when PARAM_ISMULTI is true?
static $STANDARD_TYPES
A list of standard type names and types that may be passed as $typeDefs to __construct().
getTypeDef( $type)
Get the TypeDef for a type.
const PARAM_ISMULTI
(bool) Indicate that the parameter is multi-valued.
addTypeDefs(array $typeDefs)
Register multiple type handlers.
getParamInfo( $name, $settings, array $options)
Describe parameter settings in a machine-readable format.
hasTypeDef( $name)
Test if a type is registered.
const PARAM_ISMULTI_LIMIT2
(int) Maximum number of multi-valued parameter values allowed for users allowed high limits.
checkSettings(string $name, $settings, array $options)
Validate a parameter settings array.
const ALL_DEFAULT_STRING
Magic "all values" value when PARAM_ALL is true.
static implodeMultiValue(array $value)
Implode an array as a multi-valued parameter string, like implode()
validateValue( $name, $value, $settings, array $options=[])
Validate a parameter value using a settings array.
const PARAM_ISMULTI_LIMIT1
(int) Maximum number of multi-valued parameter values allowed
const PARAM_DEFAULT
(mixed) Default value of the parameter.
const PARAM_DEPRECATED
(bool) Indicate that a deprecated parameter was used.
const PARAM_TYPE
(string|array) Type of the parameter.
const PARAM_SENSITIVE
(bool) Indicate that the parameter's value should not be logged.
const PARAM_REQUIRED
(bool) Indicate that the parameter is required.
getHelpInfo( $name, $settings, array $options)
Describe parameter settings in human-readable format.
addTypeDef( $name, $typeDef)
Register a type handler.
static explodeMultiValue( $value, $limit)
Split a multi-valued parameter string, like explode()
const PARAM_IGNORE_UNRECOGNIZED_VALUES
(bool) Whether to downgrade "badvalue" errors to non-fatal when validating multi-valued parameters.
const PARAM_ALL
(bool|string) Whether a magic "all values" value exists for multi-valued enumerated types,...
overrideTypeDef( $name, $typeDef)
Register a type handler, overriding any existing handler.
Base definition for ParamValidator types.
Definition TypeDef.php:19
getFailureMessage()
Fetch the validation failure message.
Interface defining callbacks needed by ParamValidator.
Definition Callbacks.php:21