Merge "Add .pipeline/ with dev image variant"
[lhc/web/wiklou.git] / includes / Rest / Handler.php
1 <?php
2
3 namespace MediaWiki\Rest;
4
5 use MediaWiki\Rest\Validator\BodyValidator;
6 use MediaWiki\Rest\Validator\NullBodyValidator;
7 use MediaWiki\Rest\Validator\Validator;
8
9 abstract class Handler {
10
11 /**
12 * (string) ParamValidator constant to specify the source of the parameter.
13 * Value must be 'path', 'query', or 'post'.
14 */
15 const PARAM_SOURCE = 'rest-param-source';
16
17 /** @var Router */
18 private $router;
19
20 /** @var RequestInterface */
21 private $request;
22
23 /** @var array */
24 private $config;
25
26 /** @var ResponseFactory */
27 private $responseFactory;
28
29 /** @var array|null */
30 private $validatedParams;
31
32 /** @var mixed */
33 private $validatedBody;
34
35 /**
36 * Initialise with dependencies from the Router. This is called after construction.
37 * @internal
38 */
39 public function init( Router $router, RequestInterface $request, array $config,
40 ResponseFactory $responseFactory
41 ) {
42 $this->router = $router;
43 $this->request = $request;
44 $this->config = $config;
45 $this->responseFactory = $responseFactory;
46 }
47
48 /**
49 * Get the Router. The return type declaration causes it to raise
50 * a fatal error if init() has not yet been called.
51 */
52 protected function getRouter(): Router {
53 return $this->router;
54 }
55
56 /**
57 * Get the current request. The return type declaration causes it to raise
58 * a fatal error if init() has not yet been called.
59 *
60 * @return RequestInterface
61 */
62 public function getRequest(): RequestInterface {
63 return $this->request;
64 }
65
66 /**
67 * Get the configuration array for the current route. The return type
68 * declaration causes it to raise a fatal error if init() has not
69 * been called.
70 *
71 * @return array
72 */
73 public function getConfig(): array {
74 return $this->config;
75 }
76
77 /**
78 * Get the ResponseFactory which can be used to generate Response objects.
79 * This will raise a fatal error if init() has not been
80 * called.
81 *
82 * @return ResponseFactory
83 */
84 public function getResponseFactory(): ResponseFactory {
85 return $this->responseFactory;
86 }
87
88 /**
89 * Validate the request parameters/attributes and body. If there is a validation
90 * failure, a response with an error message should be returned or an
91 * HttpException should be thrown.
92 *
93 * @param Validator $restValidator
94 * @throws HttpException On validation failure.
95 */
96 public function validate( Validator $restValidator ) {
97 $validatedParams = $restValidator->validateParams( $this->getParamSettings() );
98 $validatedBody = $restValidator->validateBody( $this->request, $this );
99 $this->validatedParams = $validatedParams;
100 $this->validatedBody = $validatedBody;
101 }
102
103 /**
104 * Fetch ParamValidator settings for parameters
105 *
106 * Every setting must include self::PARAM_SOURCE to specify which part of
107 * the request is to contain the parameter.
108 *
109 * @return array[] Associative array mapping parameter names to
110 * ParamValidator settings arrays
111 */
112 public function getParamSettings() {
113 return [];
114 }
115
116 /**
117 * Fetch the BodyValidator
118 * @param string $contentType Content type of the request.
119 * @return BodyValidator
120 */
121 public function getBodyValidator( $contentType ) {
122 return new NullBodyValidator();
123 }
124
125 /**
126 * Fetch the validated parameters
127 *
128 * @return array|null Array mapping parameter names to validated values,
129 * or null if validateParams() was not called yet or validation failed.
130 */
131 public function getValidatedParams() {
132 return $this->validatedParams;
133 }
134
135 /**
136 * Fetch the validated body
137 * @return mixed Value returned by the body validator, or null if validateParams() was
138 * not called yet, validation failed, there was no body, or the body was form data.
139 */
140 public function getValidatedBody() {
141 return $this->validatedBody;
142 }
143
144 /**
145 * The subclass should override this to provide the maximum last modified
146 * timestamp for the current request. This is called before execute() in
147 * order to decide whether to send a 304.
148 *
149 * The timestamp can be in any format accepted by ConvertibleTimestamp, or
150 * null to indicate that the timestamp is unknown.
151 *
152 * @return bool|string|int|float|\DateTime|null
153 */
154 protected function getLastModified() {
155 return null;
156 }
157
158 /**
159 * The subclass should override this to provide an ETag for the current
160 * request. This is called before execute() in order to decide whether to
161 * send a 304.
162 *
163 * See RFC 7232 ยง 2.3 for semantics.
164 *
165 * @return string|null
166 */
167 protected function getETag() {
168 return null;
169 }
170
171 /**
172 * Indicates whether this route requires read rights.
173 *
174 * The handler should override this if it does not need to read from the
175 * wiki. This is uncommon, but may be useful for login and other account
176 * management APIs.
177 *
178 * @return bool
179 */
180 public function needsReadAccess() {
181 return true;
182 }
183
184 /**
185 * Indicates whether this route requires write access.
186 *
187 * The handler should override this if the route does not need to write to
188 * the database.
189 *
190 * This should return true for routes that may require synchronous database writes.
191 * Modules that do not need such writes should also not rely on master database access,
192 * since only read queries are needed and each master DB is a single point of failure.
193 *
194 * @return bool
195 */
196 public function needsWriteAccess() {
197 return true;
198 }
199
200 /**
201 * Execute the handler. This is called after parameter validation. The
202 * return value can either be a Response or any type accepted by
203 * ResponseFactory::createFromReturnValue().
204 *
205 * To automatically construct an error response, execute() should throw a
206 * RestException. Such exceptions will not be logged like a normal exception.
207 *
208 * If execute() throws any other kind of exception, the exception will be
209 * logged and a generic 500 error page will be shown.
210 *
211 * @return mixed
212 */
213 abstract public function execute();
214 }