Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
95.83% covered (success)
95.83%
23 / 24
90.91% covered (success)
90.91%
10 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
TypeDef
95.83% covered (success)
95.83%
23 / 24
90.91% covered (success)
90.91%
10 / 11
15
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 supportsArrays
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 failure
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
4
 failureMessage
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 getValue
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 validate
n/a
0 / 0
n/a
0 / 0
0
 normalizeSettings
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 checkSettings
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getEnumValues
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 stringifyValue
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getParamInfo
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getHelpInfo
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace Wikimedia\ParamValidator;
4
5use Wikimedia\Message\DataMessageValue;
6use Wikimedia\Message\MessageValue;
7
8/**
9 * Base definition for ParamValidator types.
10 *
11 * Most methods in this class accept an "options array". This is just the `$options`
12 * passed to ParamValidator::getValue(), ParamValidator::validateValue(), and the like
13 * and is intended for communication of non-global state to the Callbacks.
14 *
15 * @since 1.34
16 * @unstable for use in extensions. Intended to become stable to extend, at
17 *           least for use in MediaWiki, which already defines some subclasses.
18 */
19abstract class TypeDef {
20
21    /** @var Callbacks */
22    protected $callbacks;
23
24    /**
25     * @stable to call
26     *
27     * @param Callbacks $callbacks
28     */
29    public function __construct( Callbacks $callbacks ) {
30        $this->callbacks = $callbacks;
31    }
32
33    /**
34     * Whether the value may be an array.
35     * Note that this is different from multi-value.
36     * This should only return true if each value can be an array.
37     * @since 1.41
38     * @stable to override
39     * @return bool
40     */
41    public function supportsArrays() {
42        return false;
43    }
44
45    /**
46     * Record a failure message
47     *
48     * Depending on `$fatal`, this will either throw a ValidationException or
49     * call $this->callbacks->recordCondition().
50     *
51     * Note that parameters for `$name` and `$value` are always added as `$1`
52     * and `$2`.
53     *
54     * @param DataMessageValue|string $failure Failure code or message.
55     * @param string $name Parameter name being validated.
56     * @param mixed $value Value being validated.
57     * @param array $settings Parameter settings array.
58     * @param array $options Options array.
59     * @param bool $fatal Whether the failure is fatal
60     */
61    protected function failure(
62        $failure, $name, $value, array $settings, array $options, $fatal = true
63    ) {
64        if ( !is_string( $value ) ) {
65            $value = (string)$this->stringifyValue( $name, $value, $settings, $options );
66        }
67
68        if ( is_string( $failure ) ) {
69            $mv = $this->failureMessage( $failure )
70                ->plaintextParams( $name, $value );
71        } else {
72            $mv = DataMessageValue::new( $failure->getKey(), [], $failure->getCode(), $failure->getData() )
73                ->plaintextParams( $name, $value )
74                ->params( ...$failure->getParams() );
75        }
76
77        if ( $fatal ) {
78            throw new ValidationException( $mv, $name, $value, $settings );
79        }
80        $this->callbacks->recordCondition( $mv, $name, $value, $settings, $options );
81    }
82
83    /**
84     * Create a DataMessageValue representing a failure
85     *
86     * The message key will be "paramvalidator-$code" or "paramvalidator-$code-$suffix".
87     *
88     * Use DataMessageValue's param mutators to add additional MessageParams.
89     * Note that `failure()` will prepend parameters for `$name` and `$value`.
90     *
91     * @param string $code Failure code.
92     * @param array|null $data Failure data.
93     * @param string|null $suffix Suffix to append when producing the message key
94     * @return DataMessageValue
95     */
96    protected function failureMessage( $code, array $data = null, $suffix = null ): DataMessageValue {
97        return DataMessageValue::new(
98            "paramvalidator-$code" . ( $suffix !== null ? "-$suffix" : '' ),
99            [], $code, $data
100        );
101    }
102
103    /**
104     * Get the value from the request
105     * @stable to override
106     *
107     * @note Only override this if you need to use something other than
108     *  $this->callbacks->getValue() to fetch the value. Reformatting from a
109     *  string should typically be done by self::validate().
110     * @note Handling of ParamValidator::PARAM_DEFAULT should be left to ParamValidator,
111     *  as should PARAM_REQUIRED and the like.
112     *
113     * @param string $name Parameter name being fetched.
114     * @param array $settings Parameter settings array.
115     * @param array $options Options array.
116     * @return null|mixed Return null if the value wasn't present, otherwise a
117     *  value to be passed to self::validate().
118     */
119    public function getValue( $name, array $settings, array $options ) {
120        return $this->callbacks->getValue( $name, null, $options );
121    }
122
123    /**
124     * Validate the value
125     *
126     * When ParamValidator is processing a multi-valued parameter, this will be
127     * called once for each of the supplied values. Which may mean zero calls.
128     *
129     * When getValue() returned null, this will not be called.
130     *
131     * @param string $name Parameter name being validated.
132     * @param mixed $value Value to validate, from getValue().
133     * @param array $settings Parameter settings array.
134     * @param array $options Options array. Note the following values that may be set
135     *  by ParamValidator:
136     *   - is-default: (bool) If present and true, the value was taken from PARAM_DEFAULT rather
137     *     that being supplied by the client.
138     *   - values-list: (string[]) If defined, values of a multi-valued parameter are being processed
139     *     (and this array holds the full set of values).
140     * @return mixed Validated value
141     * @throws ValidationException if the value is invalid
142     */
143    abstract public function validate( $name, $value, array $settings, array $options );
144
145    /**
146     * Normalize a settings array
147     * @stable to override
148     * @param array $settings
149     * @return array
150     */
151    public function normalizeSettings( array $settings ) {
152        return $settings;
153    }
154
155    /**
156     * Validate a parameter settings array
157     *
158     * This is intended for validation of parameter settings during unit or
159     * integration testing, and should implement strict checks.
160     *
161     * The rest of the code should generally be more permissive.
162     *
163     * @see ParamValidator::checkSettings()
164     * @stable to override
165     *
166     * @param string $name Parameter name
167     * @param array|mixed $settings Default value or an array of settings
168     *  using PARAM_* constants.
169     * @param array $options Options array, passed through to the TypeDef and Callbacks.
170     * @param array $ret
171     *  - 'issues': (string[]) Errors detected in $settings, as English text. If the settings
172     *    are valid, this will be the empty array. Keys on input are ParamValidator constants,
173     *    allowing the typedef to easily override core validation; this need not be preserved
174     *    when returned.
175     *  - 'allowedKeys': (string[]) ParamValidator keys that are allowed in `$settings`.
176     *  - 'messages': (MessageValue[]) Messages to be checked for existence.
177     * @return array $ret, with any relevant changes.
178     */
179    public function checkSettings( string $name, $settings, array $options, array $ret ): array {
180        return $ret;
181    }
182
183    /**
184     * Get the values for enum-like parameters
185     *
186     * This is primarily intended for documentation and implementation of
187     * PARAM_ALL; it is the responsibility of the TypeDef to ensure that validate()
188     * accepts the values returned here.
189     * @stable to override
190     *
191     * @param string $name Parameter name being validated.
192     * @param array $settings Parameter settings array.
193     * @param array $options Options array.
194     * @return array|null All possible enumerated values, or null if this is
195     *  not an enumeration.
196     */
197    public function getEnumValues( $name, array $settings, array $options ) {
198        return null;
199    }
200
201    /**
202     * Convert a value to a string representation.
203     *
204     * This is intended as the inverse of getValue() and validate(): this
205     * should accept anything returned by those methods or expected to be used
206     * as PARAM_DEFAULT, and if the string from this method is passed in as client
207     * input or PARAM_DEFAULT it should give equivalent output from validate().
208     *
209     * @param string $name Parameter name being converted.
210     * @param mixed $value Parameter value being converted. Do not pass null.
211     * @param array $settings Parameter settings array.
212     * @param array $options Options array.
213     * @return string|null Return null if there is no representation of $value
214     *  reasonably satisfying the description given.
215     */
216    public function stringifyValue( $name, $value, array $settings, array $options ) {
217        return (string)$value;
218    }
219
220    /**
221     * Describe parameter settings in a machine-readable format.
222     *
223     * Keys should be short strings using lowercase ASCII letters. Values
224     * should generally be values that could be encoded in JSON or the like.
225     *
226     * This is intended to handle PARAM constants specific to this class. It
227     * generally shouldn't handle constants defined on ParamValidator itself.
228     * @stable to override
229     *
230     * @param string $name Parameter name.
231     * @param array $settings Parameter settings array.
232     * @param array $options Options array.
233     * @return array
234     */
235    public function getParamInfo( $name, array $settings, array $options ) {
236        return [];
237    }
238
239    /**
240     * Describe parameter settings in human-readable format
241     *
242     * Keys in the returned array should generally correspond to PARAM
243     * constants.
244     *
245     * If relevant, a MessageValue describing the type itself should be
246     * returned with key ParamValidator::PARAM_TYPE.
247     *
248     * The default messages for other ParamValidator-defined PARAM constants
249     * may be suppressed by returning null as the value for those constants, or
250     * replaced by returning a replacement MessageValue. Normally, however,
251     * the default messages should not be changed.
252     *
253     * MessageValues describing any other constraints applied via PARAM
254     * constants specific to this class should also be returned.
255     * @stable to override
256     *
257     * @param string $name Parameter name being described.
258     * @param array $settings Parameter settings array.
259     * @param array $options Options array.
260     * @return (MessageValue|null)[]
261     */
262    public function getHelpInfo( $name, array $settings, array $options ) {
263        return [];
264    }
265
266}