MediaWiki  master
ParamValidator.php
Go to the documentation of this file.
1 <?php
2 
4 
5 use DomainException;
6 use InvalidArgumentException;
7 use Wikimedia\Assert\Assert;
12 use 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 
174  public const ALL_DEFAULT_STRING = '*';
175 
177  public static $STANDARD_TYPES = [
178  'boolean' => [ 'class' => TypeDef\BooleanDef::class ],
179  'checkbox' => [ 'class' => TypeDef\PresenceBooleanDef::class ],
180  'integer' => [ 'class' => TypeDef\IntegerDef::class ],
181  'limit' => [ 'class' => TypeDef\LimitDef::class ],
182  'float' => [ 'class' => TypeDef\FloatDef::class ],
183  'double' => [ 'class' => TypeDef\FloatDef::class ],
184  'string' => [ 'class' => TypeDef\StringDef::class ],
185  'password' => [ 'class' => TypeDef\PasswordDef::class ],
186  'NULL' => [
187  'class' => TypeDef\StringDef::class,
188  'args' => [ [
189  'allowEmptyWhenRequired' => true,
190  ] ],
191  ],
192  'timestamp' => [ 'class' => TypeDef\TimestampDef::class ],
193  'upload' => [ 'class' => TypeDef\UploadDef::class ],
194  'enum' => [ 'class' => TypeDef\EnumDef::class ],
195  'expiry' => [ 'class' => TypeDef\ExpiryDef::class ],
196  ];
197 
199  private $callbacks;
200 
202  private $objectFactory;
203 
205  private $typeDefs = [];
206 
208  private $ismultiLimit1;
209 
211  private $ismultiLimit2;
212 
222  public function __construct(
223  Callbacks $callbacks,
224  ObjectFactory $objectFactory,
225  array $options = []
226  ) {
227  $this->callbacks = $callbacks;
228  $this->objectFactory = $objectFactory;
229 
230  $this->addTypeDefs( $options['typeDefs'] ?? self::$STANDARD_TYPES );
231  $this->ismultiLimit1 = $options['ismultiLimits'][0] ?? 50;
232  $this->ismultiLimit2 = $options['ismultiLimits'][1] ?? 500;
233  }
234 
239  public function knownTypes() {
240  return array_keys( $this->typeDefs );
241  }
242 
249  public function addTypeDefs( array $typeDefs ) {
250  foreach ( $typeDefs as $name => $def ) {
251  $this->addTypeDef( $name, $def );
252  }
253  }
254 
268  public function addTypeDef( $name, $typeDef ) {
269  Assert::parameterType(
270  [ TypeDef::class, 'array' ],
271  $typeDef,
272  '$typeDef'
273  );
274 
275  if ( isset( $this->typeDefs[$name] ) ) {
276  throw new InvalidArgumentException( "Type '$name' is already registered" );
277  }
278  $this->typeDefs[$name] = $typeDef;
279  }
280 
287  public function overrideTypeDef( $name, $typeDef ) {
288  Assert::parameterType(
289  [ TypeDef::class, 'array', 'null' ],
290  $typeDef,
291  '$typeDef'
292  );
293 
294  if ( $typeDef === null ) {
295  unset( $this->typeDefs[$name] );
296  } else {
297  $this->typeDefs[$name] = $typeDef;
298  }
299  }
300 
306  public function hasTypeDef( $name ) {
307  return isset( $this->typeDefs[$name] );
308  }
309 
315  public function getTypeDef( $type ) {
316  if ( is_array( $type ) ) {
317  $type = 'enum';
318  }
319 
320  if ( !isset( $this->typeDefs[$type] ) ) {
321  return null;
322  }
323 
324  $def = $this->typeDefs[$type];
325  if ( !$def instanceof TypeDef ) {
326  $def = $this->objectFactory->createObject( $def, [
327  'extraArgs' => [ $this->callbacks ],
328  'assertClass' => TypeDef::class,
329  ] );
330  $this->typeDefs[$type] = $def;
331  }
332 
333  return $def;
334  }
335 
341  private function normalizeSettingsInternal( $settings ) {
342  // Shorthand
343  if ( !is_array( $settings ) ) {
344  $settings = [
345  self::PARAM_DEFAULT => $settings,
346  ];
347  }
348 
349  // When type is not given, determine it from the type of the PARAM_DEFAULT
350  if ( !isset( $settings[self::PARAM_TYPE] ) ) {
351  $settings[self::PARAM_TYPE] = gettype( $settings[self::PARAM_DEFAULT] ?? null );
352  }
353 
354  return $settings;
355  }
356 
363  public function normalizeSettings( $settings ) {
364  $settings = $this->normalizeSettingsInternal( $settings );
365 
366  $typeDef = $this->getTypeDef( $settings[self::PARAM_TYPE] );
367  if ( $typeDef ) {
368  $settings = $typeDef->normalizeSettings( $settings );
369  }
370 
371  return $settings;
372  }
373 
392  public function checkSettings( string $name, $settings, array $options ): array {
393  $settings = $this->normalizeSettingsInternal( $settings );
394  $issues = [];
395  $allowedKeys = [
398  ];
399  $messages = [];
400 
401  $type = $settings[self::PARAM_TYPE];
402  $typeDef = null;
403  if ( !is_string( $type ) && !is_array( $type ) ) {
404  $issues[self::PARAM_TYPE] = 'PARAM_TYPE must be a string or array, got ' . gettype( $type );
405  } else {
406  $typeDef = $this->getTypeDef( $settings[self::PARAM_TYPE] );
407  if ( !$typeDef ) {
408  if ( is_array( $type ) ) {
409  $type = 'enum';
410  }
411  $issues[self::PARAM_TYPE] = "Unknown/unregistered PARAM_TYPE \"$type\"";
412  }
413  }
414 
415  if ( isset( $settings[self::PARAM_DEFAULT] ) ) {
416  try {
417  $this->validateValue(
418  $name, $settings[self::PARAM_DEFAULT], $settings, [ 'is-default' => true ] + $options
419  );
420  } catch ( ValidationException $ex ) {
421  $issues[self::PARAM_DEFAULT] = 'Value for PARAM_DEFAULT does not validate (code '
422  . $ex->getFailureMessage()->getCode() . ')';
423  }
424  }
425 
426  if ( !is_bool( $settings[self::PARAM_REQUIRED] ?? false ) ) {
427  $issues[self::PARAM_REQUIRED] = 'PARAM_REQUIRED must be boolean, got '
428  . gettype( $settings[self::PARAM_REQUIRED] );
429  }
430 
431  if ( !is_bool( $settings[self::PARAM_ISMULTI] ?? false ) ) {
432  $issues[self::PARAM_ISMULTI] = 'PARAM_ISMULTI must be boolean, got '
433  . gettype( $settings[self::PARAM_ISMULTI] );
434  }
435 
436  if ( !empty( $settings[self::PARAM_ISMULTI] ) ) {
437  $allowedKeys = array_merge( $allowedKeys, [
438  self::PARAM_ISMULTI_LIMIT1, self::PARAM_ISMULTI_LIMIT2,
439  self::PARAM_ALL, self::PARAM_ALLOW_DUPLICATES
440  ] );
441 
442  $limit1 = $settings[self::PARAM_ISMULTI_LIMIT1] ?? $this->ismultiLimit1;
443  $limit2 = $settings[self::PARAM_ISMULTI_LIMIT2] ?? $this->ismultiLimit2;
444  if ( !is_int( $limit1 ) ) {
445  $issues[self::PARAM_ISMULTI_LIMIT1] = 'PARAM_ISMULTI_LIMIT1 must be an integer, got '
446  . gettype( $settings[self::PARAM_ISMULTI_LIMIT1] );
447  } elseif ( $limit1 <= 0 ) {
448  $issues[self::PARAM_ISMULTI_LIMIT1] =
449  "PARAM_ISMULTI_LIMIT1 must be greater than 0, got $limit1";
450  }
451  if ( !is_int( $limit2 ) ) {
452  $issues[self::PARAM_ISMULTI_LIMIT2] = 'PARAM_ISMULTI_LIMIT2 must be an integer, got '
453  . gettype( $settings[self::PARAM_ISMULTI_LIMIT2] );
454  } elseif ( $limit2 < $limit1 ) {
455  $issues[self::PARAM_ISMULTI_LIMIT2] =
456  'PARAM_ISMULTI_LIMIT2 must be greater than or equal to PARAM_ISMULTI_LIMIT1, but '
457  . "$limit2 < $limit1";
458  }
459 
460  $all = $settings[self::PARAM_ALL] ?? false;
461  if ( !is_string( $all ) && !is_bool( $all ) ) {
462  $issues[self::PARAM_ALL] = 'PARAM_ALL must be a string or boolean, got ' . gettype( $all );
463  } elseif ( $all !== false && $typeDef ) {
464  if ( $all === true ) {
466  }
467  $values = $typeDef->getEnumValues( $name, $settings, $options );
468  if ( !is_array( $values ) ) {
469  $issues[self::PARAM_ALL] = 'PARAM_ALL cannot be used with non-enumerated types';
470  } elseif ( in_array( $all, $values, true ) ) {
471  $issues[self::PARAM_ALL] = 'Value for PARAM_ALL conflicts with an enumerated value';
472  }
473  }
474 
475  if ( !is_bool( $settings[self::PARAM_ALLOW_DUPLICATES] ?? false ) ) {
476  $issues[self::PARAM_ALLOW_DUPLICATES] = 'PARAM_ALLOW_DUPLICATES must be boolean, got '
477  . gettype( $settings[self::PARAM_ALLOW_DUPLICATES] );
478  }
479  }
480 
481  if ( !is_bool( $settings[self::PARAM_SENSITIVE] ?? false ) ) {
482  $issues[self::PARAM_SENSITIVE] = 'PARAM_SENSITIVE must be boolean, got '
483  . gettype( $settings[self::PARAM_SENSITIVE] );
484  }
485 
486  if ( !is_bool( $settings[self::PARAM_DEPRECATED] ?? false ) ) {
487  $issues[self::PARAM_DEPRECATED] = 'PARAM_DEPRECATED must be boolean, got '
488  . gettype( $settings[self::PARAM_DEPRECATED] );
489  }
490 
491  if ( !is_bool( $settings[self::PARAM_IGNORE_UNRECOGNIZED_VALUES] ?? false ) ) {
492  $issues[self::PARAM_IGNORE_UNRECOGNIZED_VALUES] = 'PARAM_IGNORE_UNRECOGNIZED_VALUES must be '
493  . 'boolean, got ' . gettype( $settings[self::PARAM_IGNORE_UNRECOGNIZED_VALUES] );
494  }
495 
496  $ret = [ 'issues' => $issues, 'allowedKeys' => $allowedKeys, 'messages' => $messages ];
497  if ( $typeDef ) {
498  $ret = $typeDef->checkSettings( $name, $settings, $options, $ret );
499  }
500 
501  return $ret;
502  }
503 
515  public function getValue( $name, $settings, array $options = [] ) {
516  $settings = $this->normalizeSettings( $settings );
517 
518  $typeDef = $this->getTypeDef( $settings[self::PARAM_TYPE] );
519  if ( !$typeDef ) {
520  throw new DomainException(
521  "Param $name's type is unknown - {$settings[self::PARAM_TYPE]}"
522  );
523  }
524 
525  $value = $typeDef->getValue( $name, $settings, $options );
526 
527  if ( $value !== null ) {
528  if ( !empty( $settings[self::PARAM_SENSITIVE] ) ) {
529  $strValue = $typeDef->stringifyValue( $name, $value, $settings, $options );
530  $this->callbacks->recordCondition(
531  DataMessageValue::new( 'paramvalidator-param-sensitive', [], 'param-sensitive' )
532  ->plaintextParams( $name, $strValue ),
533  $name, $value, $settings, $options
534  );
535  }
536 
537  // Set a warning if a deprecated parameter has been passed
538  if ( !empty( $settings[self::PARAM_DEPRECATED] ) ) {
539  $strValue = $typeDef->stringifyValue( $name, $value, $settings, $options );
540  $this->callbacks->recordCondition(
541  DataMessageValue::new( 'paramvalidator-param-deprecated', [], 'param-deprecated' )
542  ->plaintextParams( $name, $strValue ),
543  $name, $value, $settings, $options
544  );
545  }
546  } elseif ( isset( $settings[self::PARAM_DEFAULT] ) ) {
547  $value = $settings[self::PARAM_DEFAULT];
548  $options['is-default'] = true;
549  }
550 
551  return $this->validateValue( $name, $value, $settings, $options );
552  }
553 
567  public function validateValue( $name, $value, $settings, array $options = [] ) {
568  $settings = $this->normalizeSettings( $settings );
569 
570  $typeDef = $this->getTypeDef( $settings[self::PARAM_TYPE] );
571  if ( !$typeDef ) {
572  throw new DomainException(
573  "Param $name's type is unknown - {$settings[self::PARAM_TYPE]}"
574  );
575  }
576 
577  if ( $value === null ) {
578  if ( !empty( $settings[self::PARAM_REQUIRED] ) ) {
579  throw new ValidationException(
580  DataMessageValue::new( 'paramvalidator-missingparam', [], 'missingparam' )
581  ->plaintextParams( $name ),
582  $name, $value, $settings
583  );
584  }
585  return null;
586  }
587 
588  // Non-multi
589  if ( empty( $settings[self::PARAM_ISMULTI] ) ) {
590  if ( is_string( $value ) && substr( $value, 0, 1 ) === "\x1f" ) {
591  throw new ValidationException(
592  DataMessageValue::new( 'paramvalidator-notmulti', [], 'badvalue' )
593  ->plaintextParams( $name, $value ),
594  $name, $value, $settings
595  );
596  }
597 
598  // T326764: If the type of the actual param value is different from
599  // the type that is defined via getParamSettings(), throw an exception
600  // because this is a type to value mismatch.
601  if ( is_array( $value ) ) {
602  throw new ValidationException(
603  DataMessageValue::new( 'paramvalidator-notmulti', [], 'badvalue' )
604  ->plaintextParams( $name, gettype( $value ) ),
605  $name, $value, $settings
606  );
607  }
608 
609  return $typeDef->validate( $name, $value, $settings, $options );
610  }
611 
612  // Split the multi-value and validate each parameter
613  $limit1 = $settings[self::PARAM_ISMULTI_LIMIT1] ?? $this->ismultiLimit1;
614  $limit2 = max( $limit1, $settings[self::PARAM_ISMULTI_LIMIT2] ?? $this->ismultiLimit2 );
615  $valuesList = is_array( $value ) ? $value : self::explodeMultiValue( $value, $limit2 + 1 );
616 
617  // Handle PARAM_ALL
618  $enumValues = $typeDef->getEnumValues( $name, $settings, $options );
619  if ( is_array( $enumValues ) && isset( $settings[self::PARAM_ALL] ) &&
620  count( $valuesList ) === 1
621  ) {
622  $allValue = is_string( $settings[self::PARAM_ALL] )
623  ? $settings[self::PARAM_ALL]
624  : self::ALL_DEFAULT_STRING;
625  if ( $valuesList[0] === $allValue ) {
626  return $enumValues;
627  }
628  }
629 
630  // Avoid checking useHighLimits() unless it's actually necessary
631  $sizeLimit = (
632  $limit2 > $limit1 && count( $valuesList ) > $limit1 &&
633  $this->callbacks->useHighLimits( $options )
634  ) ? $limit2 : $limit1;
635  if ( count( $valuesList ) > $sizeLimit ) {
636  throw new ValidationException(
637  DataMessageValue::new( 'paramvalidator-toomanyvalues', [], 'toomanyvalues', [
638  'parameter' => $name,
639  'limit' => $sizeLimit,
640  'lowlimit' => $limit1,
641  'highlimit' => $limit2,
642  ] )->plaintextParams( $name )->numParams( $sizeLimit ),
643  $name, $valuesList, $settings
644  );
645  }
646 
647  $options['values-list'] = $valuesList;
648  $validValues = [];
649  $invalidValues = [];
650  foreach ( $valuesList as $v ) {
651  try {
652  $validValues[] = $typeDef->validate( $name, $v, $settings, $options );
653  } catch ( ValidationException $ex ) {
654  if ( $ex->getFailureMessage()->getCode() !== 'badvalue' ||
655  empty( $settings[self::PARAM_IGNORE_UNRECOGNIZED_VALUES] )
656  ) {
657  throw $ex;
658  }
659  $invalidValues[] = $v;
660  }
661  }
662  if ( $invalidValues ) {
663  if ( is_array( $value ) ) {
664  $value = self::implodeMultiValue( $value );
665  }
666  $this->callbacks->recordCondition(
667  DataMessageValue::new( 'paramvalidator-unrecognizedvalues', [], 'unrecognizedvalues', [
668  'values' => $invalidValues,
669  ] )
670  ->plaintextParams( $name, $value )
671  ->commaListParams( array_map( static function ( $v ) {
672  return new ScalarParam( ParamType::PLAINTEXT, $v );
673  }, $invalidValues ) )
674  ->numParams( count( $invalidValues ) ),
675  $name, $value, $settings, $options
676  );
677  }
678 
679  // Throw out duplicates if requested
680  if ( empty( $settings[self::PARAM_ALLOW_DUPLICATES] ) ) {
681  $validValues = array_values( array_unique( $validValues ) );
682  }
683 
684  return $validValues;
685  }
686 
696  public function getParamInfo( $name, $settings, array $options ) {
697  $settings = $this->normalizeSettings( $settings );
698  $typeDef = $this->getTypeDef( $settings[self::PARAM_TYPE] );
699  $info = [];
700 
701  $info['type'] = $settings[self::PARAM_TYPE];
702  $info['required'] = !empty( $settings[self::PARAM_REQUIRED] );
703  if ( !empty( $settings[self::PARAM_DEPRECATED] ) ) {
704  $info['deprecated'] = true;
705  }
706  if ( !empty( $settings[self::PARAM_SENSITIVE] ) ) {
707  $info['sensitive'] = true;
708  }
709  if ( isset( $settings[self::PARAM_DEFAULT] ) ) {
710  $info['default'] = $settings[self::PARAM_DEFAULT];
711  }
712  $info['multi'] = !empty( $settings[self::PARAM_ISMULTI] );
713  if ( $info['multi'] ) {
714  $info['lowlimit'] = $settings[self::PARAM_ISMULTI_LIMIT1] ?? $this->ismultiLimit1;
715  $info['highlimit'] = max(
716  $info['lowlimit'], $settings[self::PARAM_ISMULTI_LIMIT2] ?? $this->ismultiLimit2
717  );
718  $info['limit'] =
719  $info['highlimit'] > $info['lowlimit'] && $this->callbacks->useHighLimits( $options )
720  ? $info['highlimit']
721  : $info['lowlimit'];
722 
723  if ( !empty( $settings[self::PARAM_ALLOW_DUPLICATES] ) ) {
724  $info['allowsduplicates'] = true;
725  }
726 
727  $allSpecifier = $settings[self::PARAM_ALL] ?? false;
728  if ( $allSpecifier !== false ) {
729  if ( !is_string( $allSpecifier ) ) {
730  $allSpecifier = self::ALL_DEFAULT_STRING;
731  }
732  $info['allspecifier'] = $allSpecifier;
733  }
734  }
735 
736  if ( $typeDef ) {
737  $info = array_merge( $info, $typeDef->getParamInfo( $name, $settings, $options ) );
738  }
739 
740  // Filter out nulls (strictly)
741  return array_filter( $info, static function ( $v ) {
742  return $v !== null;
743  } );
744  }
745 
755  public function getHelpInfo( $name, $settings, array $options ) {
756  $settings = $this->normalizeSettings( $settings );
757  $typeDef = $this->getTypeDef( $settings[self::PARAM_TYPE] );
758 
759  // Define ordering. Some are overwritten below, some expected from the TypeDef
760  $info = [
761  self::PARAM_DEPRECATED => null,
762  self::PARAM_REQUIRED => null,
763  self::PARAM_SENSITIVE => null,
764  self::PARAM_TYPE => null,
765  self::PARAM_ISMULTI => null,
766  self::PARAM_ISMULTI_LIMIT1 => null,
767  self::PARAM_ALL => null,
768  self::PARAM_DEFAULT => null,
769  ];
770 
771  if ( !empty( $settings[self::PARAM_DEPRECATED] ) ) {
772  $info[self::PARAM_DEPRECATED] = MessageValue::new( 'paramvalidator-help-deprecated' );
773  }
774 
775  if ( !empty( $settings[self::PARAM_REQUIRED] ) ) {
776  $info[self::PARAM_REQUIRED] = MessageValue::new( 'paramvalidator-help-required' );
777  }
778 
779  if ( !empty( $settings[self::PARAM_ISMULTI] ) ) {
780  $info[self::PARAM_ISMULTI] = MessageValue::new( 'paramvalidator-help-multi-separate' );
781 
782  $lowcount = $settings[self::PARAM_ISMULTI_LIMIT1] ?? $this->ismultiLimit1;
783  $highcount = max( $lowcount, $settings[self::PARAM_ISMULTI_LIMIT2] ?? $this->ismultiLimit2 );
784  $values = $typeDef ? $typeDef->getEnumValues( $name, $settings, $options ) : null;
785  if (
786  // Only mention the limits if they're likely to matter.
787  $values === null || count( $values ) > $lowcount ||
788  !empty( $settings[self::PARAM_ALLOW_DUPLICATES] )
789  ) {
790  if ( $highcount > $lowcount ) {
791  $info[self::PARAM_ISMULTI_LIMIT1] = MessageValue::new( 'paramvalidator-help-multi-max' )
792  ->numParams( $lowcount, $highcount );
793  } else {
794  $info[self::PARAM_ISMULTI_LIMIT1] = MessageValue::new( 'paramvalidator-help-multi-max-simple' )
795  ->numParams( $lowcount );
796  }
797  }
798 
799  $allSpecifier = $settings[self::PARAM_ALL] ?? false;
800  if ( $allSpecifier !== false ) {
801  if ( !is_string( $allSpecifier ) ) {
802  $allSpecifier = self::ALL_DEFAULT_STRING;
803  }
804  $info[self::PARAM_ALL] = MessageValue::new( 'paramvalidator-help-multi-all' )
805  ->plaintextParams( $allSpecifier );
806  }
807  }
808 
809  if ( isset( $settings[self::PARAM_DEFAULT] ) && $typeDef ) {
810  $value = $typeDef->stringifyValue( $name, $settings[self::PARAM_DEFAULT], $settings, $options );
811  if ( $value === '' ) {
812  $info[self::PARAM_DEFAULT] = MessageValue::new( 'paramvalidator-help-default-empty' );
813  } elseif ( $value !== null ) {
814  $info[self::PARAM_DEFAULT] = MessageValue::new( 'paramvalidator-help-default' )
815  ->plaintextParams( $value );
816  }
817  }
818 
819  if ( $typeDef ) {
820  $info = array_merge( $info, $typeDef->getHelpInfo( $name, $settings, $options ) );
821  }
822 
823  // Put the default at the very end (the TypeDef may have added extra messages)
824  $default = $info[self::PARAM_DEFAULT];
825  unset( $info[self::PARAM_DEFAULT] );
826  $info[self::PARAM_DEFAULT] = $default;
827 
828  // Filter out nulls
829  return array_filter( $info );
830  }
831 
842  public static function explodeMultiValue( $value, $limit ) {
843  if ( $value === '' || $value === "\x1f" ) {
844  return [];
845  }
846 
847  if ( substr( $value, 0, 1 ) === "\x1f" ) {
848  $sep = "\x1f";
849  $value = substr( $value, 1 );
850  } else {
851  $sep = '|';
852  }
853 
854  return explode( $sep, $value, $limit );
855  }
856 
863  public static function implodeMultiValue( array $value ) {
864  if ( $value === [ '' ] ) {
865  // There's no value that actually returns a single empty string.
866  // Best we can do is this that returns two, which will be deduplicated to one.
867  return '|';
868  }
869 
870  foreach ( $value as $v ) {
871  if ( strpos( $v, '|' ) !== false ) {
872  return "\x1f" . implode( "\x1f", $value );
873  }
874  }
875  return implode( '|', $value );
876  }
877 
878 }
Value object representing a message for i18n with alternative machine-readable data.
static new( $key, $params=[], $code=null, array $data=null)
Static constructor for easier chaining of ->params() methods.
Value object representing a message for i18n.
static new( $key, $params=[])
Static constructor for easier chaining of ->params() methods.
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:97
Value object representing a message parameter holding a single value.
Definition: ScalarParam.php:14
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
Error reporting for ParamValidator.
getFailureMessage()
Fetch the validation failure message.
Interface defining callbacks needed by ParamValidator.
Definition: Callbacks.php:21