Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
48 / 48
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
JsonBodyValidator
100.00% covered (success)
100.00%
48 / 48
100.00% covered (success)
100.00%
3 / 3
14
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 validateBody
100.00% covered (success)
100.00%
28 / 28
100.00% covered (success)
100.00%
1 / 1
8
 getOpenAPISpec
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
5
1<?php
2
3namespace MediaWiki\Rest\Validator;
4
5use MediaWiki\Json\FormatJson;
6use MediaWiki\Rest\LocalizedHttpException;
7use MediaWiki\Rest\RequestInterface;
8use Wikimedia\Message\ListParam;
9use Wikimedia\Message\ListType;
10use Wikimedia\Message\MessageValue;
11use Wikimedia\ParamValidator\ParamValidator;
12
13/**
14 * @deprecated since 1.43, return body properties from Handler::getParamSettings().
15 */
16class JsonBodyValidator implements BodyValidator {
17
18    /**
19     * @var array[]
20     */
21    private $bodyParamSettings;
22
23    /**
24     * @deprecated since 1.43, Return body parameters from getBodyParamSettings() instead.
25     * @param array[] $bodyParamSettings
26     */
27    public function __construct( array $bodyParamSettings ) {
28        wfDeprecatedMsg(
29            __CLASS__ . ' is deprecated.',
30            '1.43'
31        );
32        $this->bodyParamSettings = $bodyParamSettings;
33    }
34
35    /**
36     * @inheritDoc
37     * @return array
38     */
39    public function validateBody( RequestInterface $request ) {
40        $jsonStream = $request->getBody();
41        $status = FormatJson::parse( "$jsonStream", FormatJson::FORCE_ASSOC );
42
43        if ( !$status->isOK() ) {
44            throw new LocalizedHttpException(
45                new MessageValue( 'rest-json-body-parse-error', [ "$status" ] ),
46                400
47            );
48        }
49
50        $data = $status->value;
51
52        if ( !is_array( $data ) ) {
53            throw new LocalizedHttpException( new MessageValue( 'rest-bad-json-body' ), 400 );
54        }
55
56        $uncheckedBodyKeys = array_fill_keys( array_keys( $data ), true );
57        foreach ( $this->bodyParamSettings as $name => $settings ) {
58            if ( !empty( $settings[ParamValidator::PARAM_REQUIRED] ) && !isset( $data[$name] ) ) {
59                throw new LocalizedHttpException(
60                    new MessageValue( 'rest-missing-body-field', [ $name ] ), 400
61                );
62            }
63
64            if ( !isset( $data[$name] ) ) {
65                $data[$name] = $settings[ParamValidator::PARAM_DEFAULT] ?? null;
66            }
67
68            unset( $uncheckedBodyKeys[$name] );
69            // TODO: use a ParamValidator to check field value, etc!
70        }
71        if ( $uncheckedBodyKeys ) {
72            throw new LocalizedHttpException(
73                new MessageValue(
74                    'rest-extraneous-body-fields',
75                    [ new ListParam( ListType::COMMA, array_keys( $uncheckedBodyKeys ) ) ]
76                ),
77                400
78            );
79        }
80
81        return $data;
82    }
83
84    /**
85     * Returns an OpenAPI Schema Object specification structure as an associative array.
86     * @see https://swagger.io/specification/#schema-object
87     *
88     *
89     * This will contain information about the supported parameters.
90     *
91     * @return array
92     */
93    public function getOpenAPISpec(): array {
94        $body = [];
95        $required = [];
96
97        // XXX: Maybe we want to be able to define a spec file in the route definition?
98        // NOTE: the route definition may not be loaded when this is called before init()!
99
100        foreach ( $this->bodyParamSettings as $name => $paramSetting ) {
101            $param = Validator::getParameterSpec(
102                $name,
103                $paramSetting
104            );
105
106            $body['properties'][$name] = $param['schema'];
107
108            if ( isset( $param['description'] ) ) {
109                $body['properties'][$name]['description'] = $param['description'];
110            }
111
112            if ( $param['required'] ?? false ) {
113                $required[] = $param['name'];
114            }
115        }
116
117        if ( $required ) {
118            $body['required'] = $required;
119        }
120
121        return $body;
122    }
123}