1<?php 2 3namespace MediaWiki\ParamValidator\TypeDef; 4 5use ApiResult; 6use NamespaceInfo; 7use Wikimedia\ParamValidator\Callbacks; 8use Wikimedia\ParamValidator\ParamValidator; 9use Wikimedia\ParamValidator\TypeDef\EnumDef; 10 11/** 12 * Type definition for namespace types 13 * 14 * A namespace type is an enum type that accepts MediaWiki namespace IDs. 15 * 16 * @since 1.35 17 */ 18class NamespaceDef extends EnumDef { 19 20 /** 21 * (int[]) Additional namespace IDs to recognize. 22 * 23 * Generally this will be used to include NS_SPECIAL and/or NS_MEDIA. 24 */ 25 public const PARAM_EXTRA_NAMESPACES = 'param-extra-namespaces'; 26 27 /** @var NamespaceInfo */ 28 private $nsInfo; 29 30 public function __construct( Callbacks $callbacks, NamespaceInfo $nsInfo ) { 31 parent::__construct( $callbacks ); 32 $this->nsInfo = $nsInfo; 33 } 34 35 public function validate( $name, $value, array $settings, array $options ) { 36 if ( !is_int( $value ) && preg_match( '/^[+-]?\d+$/D', $value ) ) { 37 // Convert to int since that's what getEnumValues() returns. 38 $value = (int)$value; 39 } 40 41 return parent::validate( $name, $value, $settings, $options ); 42 } 43 44 public function getEnumValues( $name, array $settings, array $options ) { 45 $namespaces = $this->nsInfo->getValidNamespaces(); 46 $extra = $settings[self::PARAM_EXTRA_NAMESPACES] ?? []; 47 if ( is_array( $extra ) && $extra !== [] ) { 48 $namespaces = array_merge( $namespaces, $extra ); 49 } 50 sort( $namespaces ); 51 return $namespaces; 52 } 53 54 public function normalizeSettings( array $settings ) { 55 // Force PARAM_ALL 56 if ( !empty( $settings[ParamValidator::PARAM_ISMULTI] ) ) { 57 $settings[ParamValidator::PARAM_ALL] = true; 58 } 59 return parent::normalizeSettings( $settings ); 60 } 61 62 public function checkSettings( string $name, $settings, array $options, array $ret ) : array { 63 $ret = parent::checkSettings( $name, $settings, $options, $ret ); 64 65 $ret['allowedKeys'] = array_merge( $ret['allowedKeys'], [ 66 self::PARAM_EXTRA_NAMESPACES, 67 ] ); 68 69 if ( !empty( $settings[ParamValidator::PARAM_ISMULTI] ) && 70 ( $settings[ParamValidator::PARAM_ALL] ?? true ) !== true && 71 !isset( $ret['issues'][ParamValidator::PARAM_ALL] ) 72 ) { 73 $ret['issues'][ParamValidator::PARAM_ALL] = 74 'PARAM_ALL cannot be false or a string for namespace-type parameters'; 75 } 76 77 $ns = $settings[self::PARAM_EXTRA_NAMESPACES] ?? []; 78 if ( !is_array( $ns ) ) { 79 $type = gettype( $ns ); 80 } elseif ( $ns === [] ) { 81 $type = 'integer[]'; 82 } else { 83 $types = array_unique( array_map( 'gettype', $ns ) ); 84 $type = implode( '|', $types ); 85 $type = count( $types ) > 1 ? "($type)[]" : "{$type}[]"; 86 } 87 if ( $type !== 'integer[]' ) { 88 $ret['issues'][self::PARAM_EXTRA_NAMESPACES] = 89 "PARAM_EXTRA_NAMESPACES must be an integer[], got $type"; 90 } 91 92 return $ret; 93 } 94 95 public function getParamInfo( $name, array $settings, array $options ) { 96 $info = parent::getParamInfo( $name, $settings, $options ); 97 98 $info['type'] = 'namespace'; 99 $extra = $settings[self::PARAM_EXTRA_NAMESPACES] ?? []; 100 if ( is_array( $extra ) && $extra !== [] ) { 101 $info['extranamespaces'] = array_values( $extra ); 102 if ( isset( $options['module'] ) ) { 103 // ApiResult metadata when used with the Action API. 104 ApiResult::setIndexedTagName( $info['extranamespaces'], 'ns' ); 105 } 106 } 107 108 return $info; 109 } 110 111} 112