Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
69.44% covered (warning)
69.44%
25 / 36
37.50% covered (danger)
37.50%
3 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
ParamValidatorCallbacks
69.44% covered (warning)
69.44%
25 / 36
37.50% covered (danger)
37.50%
3 / 8
38.09
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getParamsFromSource
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
7
 hasParam
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getValue
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
7
 hasUpload
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 getUploadedFile
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 recordCondition
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 useHighLimits
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace MediaWiki\Rest\Validator;
4
5use InvalidArgumentException;
6use MediaWiki\Permissions\Authority;
7use MediaWiki\Rest\RequestInterface;
8use Psr\Http\Message\UploadedFileInterface;
9use UtfNormal\Validator;
10use Wikimedia\Message\DataMessageValue;
11use Wikimedia\ParamValidator\Callbacks;
12
13class ParamValidatorCallbacks implements Callbacks {
14
15    private RequestInterface $request;
16    private Authority $authority;
17
18    public function __construct(
19        RequestInterface $request,
20        Authority $authority
21    ) {
22        $this->request = $request;
23        $this->authority = $authority;
24    }
25
26    /**
27     * Get the raw parameters from a source in the request
28     * @param string $source 'path', 'query', 'post', 'body' or 'header'
29     * @return array
30     */
31    private function getParamsFromSource( $source ) {
32        // This switch block must match Validator::KNOWN_PARAM_SOURCES
33        switch ( $source ) {
34            case 'path':
35                return $this->request->getPathParams();
36
37            case 'query':
38                return $this->request->getQueryParams();
39
40            case 'post':
41                wfDeprecatedMsg( 'The "post" source is deprecated, use "body" instead', '1.43' );
42                return $this->request->getPostParams();
43
44            case 'body':
45                return $this->request->getParsedBody() ?? [];
46
47            case 'header':
48                return $this->request->getHeaders() ?? [];
49
50            default:
51                throw new InvalidArgumentException( __METHOD__ . ": Invalid source '$source'" );
52        }
53    }
54
55    /** @inheritDoc */
56    public function hasParam( $name, array $options ) {
57        $params = $this->getParamsFromSource( $options['source'] );
58        return isset( $params[$name] );
59    }
60
61    /** @inheritDoc */
62    public function getValue( $name, $default, array $options ) {
63        $params = $this->getParamsFromSource( $options['source'] );
64        $value = $params[$name] ?? $default;
65        if (
66            $options['source'] === 'header' &&
67            $options['type'] === 'string' &&
68            isset( $params[$name] )
69        ) {
70            $value = implode( ', ', $value );
71        }
72
73        // Normalisation for body is being handled in Handler::parseBodyData
74        if ( !isset( $options['raw'] ) && $options['source'] !== 'body' ) {
75            if ( is_string( $value ) ) {
76                // Normalize value to NFC UTF-8
77                $normalizedValue = Validator::cleanUp( $value );
78                // TODO: Warn if normalization was applied
79
80                $value = $normalizedValue;
81            }
82        }
83
84        return $value;
85    }
86
87    /** @inheritDoc */
88    public function hasUpload( $name, array $options ) {
89        if ( $options['source'] !== 'post' ) {
90            return false;
91        }
92        return $this->getUploadedFile( $name, $options ) !== null;
93    }
94
95    /** @inheritDoc */
96    public function getUploadedFile( $name, array $options ) {
97        if ( $options['source'] !== 'post' ) {
98            return null;
99        }
100        $upload = $this->request->getUploadedFiles()[$name] ?? null;
101        return $upload instanceof UploadedFileInterface ? $upload : null;
102    }
103
104    /** @inheritDoc */
105    public function recordCondition(
106        DataMessageValue $message, $name, $value, array $settings, array $options
107    ) {
108        // @todo Figure out how to handle warnings
109    }
110
111    /** @inheritDoc */
112    public function useHighLimits( array $options ) {
113        return $this->authority->isAllowed( 'apihighlimits' );
114    }
115
116}