failure(). * * Note that this does not add any values to the enumeration, it only * documents existing values as being deprecated. * * Failure codes: (non-fatal) * - 'deprecated-value': A deprecated value was encountered. No data. */ public const PARAM_DEPRECATED_VALUES = 'param-deprecated-values'; public function validate( $name, $value, array $settings, array $options ) { $values = $this->getEnumValues( $name, $settings, $options ); if ( in_array( $value, $values, true ) ) { // Set a warning if a deprecated parameter value has been passed if ( empty( $options['is-default'] ) && isset( $settings[self::PARAM_DEPRECATED_VALUES][$value] ) ) { $msg = $settings[self::PARAM_DEPRECATED_VALUES][$value]; if ( $msg instanceof MessageValue ) { $message = DataMessageValue::new( $msg->getKey(), $msg->getParams(), 'deprecated-value', $msg instanceof DataMessageValue ? $msg->getData() : null ); } else { $message = $this->failureMessage( 'deprecated-value' ); } $this->failure( $message, $name, $value, $settings, $options, false ); } return $value; } $isMulti = isset( $options['values-list'] ); $this->failure( $this->failureMessage( 'badvalue', [], $isMulti ? 'enummulti' : 'enumnotmulti' ) ->textListParams( array_map( function ( $v ) { return new ScalarParam( ParamType::PLAINTEXT, $v ); }, $values ) ) ->numParams( count( $values ) ), $name, $value, $settings, $options ); } public function checkSettings( string $name, $settings, array $options, array $ret ) : array { $ret = parent::checkSettings( $name, $settings, $options, $ret ); $ret['allowedKeys'][] = self::PARAM_DEPRECATED_VALUES; $dv = $settings[self::PARAM_DEPRECATED_VALUES] ?? []; if ( !is_array( $dv ?? false ) ) { $ret['issues'][self::PARAM_DEPRECATED_VALUES] = 'PARAM_DEPRECATED_VALUES must be an array, got ' . gettype( $dv ); } else { $values = array_map( function ( $v ) use ( $name, $settings, $options ) { return $this->stringifyValue( $name, $v, $settings, $options ); }, $this->getEnumValues( $name, $settings, $options ) ); foreach ( $dv as $k => $v ) { $k = $this->stringifyValue( $name, $k, $settings, $options ); if ( !in_array( $k, $values, true ) ) { $ret['issues'][] = "PARAM_DEPRECATED_VALUES contains \"$k\", which is not " . 'one of the enumerated values'; } elseif ( $v instanceof MessageValue ) { $ret['messages'][] = $v; } elseif ( $v !== null && $v !== true ) { $type = $v === false ? 'false' : ( is_object( $v ) ? get_class( $v ) : gettype( $v ) ); $ret['issues'][] = 'Values in PARAM_DEPRECATED_VALUES must be null, true, or MessageValue, ' . "but value for \"$k\" is $type"; } } } return $ret; } public function getEnumValues( $name, array $settings, array $options ) { return array_values( $settings[ParamValidator::PARAM_TYPE] ); } public function stringifyValue( $name, $value, array $settings, array $options ) { if ( !is_array( $value ) ) { return parent::stringifyValue( $name, $value, $settings, $options ); } return ParamValidator::implodeMultiValue( $value ); } public function getParamInfo( $name, array $settings, array $options ) { $info = parent::getParamInfo( $name, $settings, $options ); $info['type'] = $this->sortEnumValues( $name, $this->getEnumValues( $name, $settings, $options ), $settings, $options ); if ( !empty( $settings[self::PARAM_DEPRECATED_VALUES] ) ) { $deprecatedValues = array_intersect( array_keys( $settings[self::PARAM_DEPRECATED_VALUES] ), $this->getEnumValues( $name, $settings, $options ) ); if ( $deprecatedValues ) { $deprecatedValues = $this->sortEnumValues( $name, $deprecatedValues, $settings, $options ); $info['deprecatedvalues'] = array_values( $deprecatedValues ); } } return $info; } public function getHelpInfo( $name, array $settings, array $options ) { $info = parent::getHelpInfo( $name, $settings, $options ); $isMulti = !empty( $settings[ParamValidator::PARAM_ISMULTI] ); $values = $this->getEnumValuesForHelp( $name, $settings, $options ); $count = count( $values ); $i = array_search( '', $values, true ); if ( $i === false ) { $valuesParam = new ListParam( ListType::COMMA, $values ); } else { unset( $values[$i] ); $valuesParam = MessageValue::new( 'paramvalidator-help-type-enum-can-be-empty' ) ->commaListParams( $values ) ->numParams( count( $values ) ); } $info[ParamValidator::PARAM_TYPE] = MessageValue::new( 'paramvalidator-help-type-enum' ) ->params( $isMulti ? 2 : 1 ) ->params( $valuesParam ) ->numParams( $count ); // Suppress standard ISMULTI message, it should be incorporated into our type message. $info[ParamValidator::PARAM_ISMULTI] = null; return $info; } /** * Sort enum values for help/param info output * * @param string $name Parameter name being described. * @param string[] $values Values being sorted * @param array $settings Parameter settings array. * @param array $options Options array. * @return string[] */ protected function sortEnumValues( string $name, array $values, array $settings, array $options ) : array { // sort values by deprecation status and name $flags = []; foreach ( $values as $k => $value ) { $flag = 0; if ( isset( $settings[self::PARAM_DEPRECATED_VALUES][$value] ) ) { $flag |= 1; } $flags[$k] = $flag; } array_multisort( $flags, $values, SORT_NATURAL ); return $values; } /** * Return enum values formatted for the help message * * @param string $name Parameter name being described. * @param array $settings Parameter settings array. * @param array $options Options array. * @return (MessageParam|string)[] */ protected function getEnumValuesForHelp( $name, array $settings, array $options ) { $values = $this->getEnumValues( $name, $settings, $options ); $values = $this->sortEnumValues( $name, $values, $settings, $options ); // @todo Indicate deprecated values in some manner. Probably that needs // MessageValue and/or MessageParam to have a generic ability to wrap // values in HTML without that HTML coming out in the text format too. return $values; } }