Passed
Push — master ( 0cf092...c3363c )
by Alexander
02:29
created

Request::content()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 6
rs 10
1
<?php
2
3
namespace alkemann\h2l;
4
5
use alkemann\h2l\util\Http;
6
7
/**
8
 * Class Request
9
 *
10
 * @TODO : $locale = Locale::acceptFromHttp($_SERVER['HTTP_ACCEPT_LANGUAGE']);
11
 * @package alkemann\h2l
12
 */
13
class Request extends Message
14
{
15
    /**
16
     * @var null|interfaces\Route
17
     */
18
    protected $route = null;
19
    /**
20
     * @var null|interfaces\Session
21
     */
22
    protected $session = null;
23
    /** @var array */
24
    protected $parameters = [];
25
    /** @var array */
26
    protected $request = [];
27
    /** @var array */
28
    protected $server = [];
29
    /** @var array */
30
    protected $get = [];
31
    /** @var array */
32
    protected $post = [];
33
    /** @var string */
34
    protected $content_type = ''; // Type of the REQUEST BODY, not response
35
    /** @var string */
36
    protected $accept_type = Http::CONTENT_HTML;
37
    /** @var array */
38
    protected $page_vars = [];
39
40
    /**
41
     * Get request parameters from url as url params, get queries or post, in that order
42
     *
43
     * @param string $name the name of the parameter
44
     * @return mixed|null the value or null if not set
45
     */
46
    public function param(string $name)
47
    {
48
        if (isset($this->parameters[$name])) {
49
            return $this->parameters[$name];
50
        }
51
        if (isset($this->get[$name])) {
52
            return $this->get[$name];
53
        }
54
        if (isset($this->post[$name])) {
55
            return $this->post[$name];
56
        }
57
        if ($this->contentType() == Http::CONTENT_JSON) {
58
            $data = $this->content();
59
            if (empty($this->post)) {
60
                // Cache the json body in the post array
61
                $this->post = $data;
62
            }
63
            if (isset($data[$name])) {
64
                return $data[$name];
65
            }
66
        }
67
        return null;
68
    }
69
70
    /**
71
     * Returns the full url (with domain) of the request, alternatively for the provided path
72
     *
73
     * Alternative usage is for creating full urls, i.e. reverse routing
74
     *
75
     * @param null|string $path
76
     * @return string
77
     */
78
    public function fullUrl(?string $path = null): string
79
    {
80
        $path = $path ?? $this->url();
81
        if ($path && $path[0] != '/') {
82
            $path = '/' . $path;
83
        }
84
85
        $scheme = $this->getServerParam('REQUEST_SCHEME') ?? 'http';
86
        $domain = $this->getServerParam('HTTP_HOST') ?? 'localhost';
87
        return $scheme . '://' . $domain . $path;
88
    }
89
90
    /**
91
     * Recreate the `Request` with specified request parameters
92
     *
93
     * @param array $request_params
94
     * @return Request
95
     */
96
    public function withRequestParams(array $request_params): Request
97
    {
98
        $new = clone $this;
99
        $new->url = $request_params['url'] ?? '/';
100
        unset($request_params['url']);
101
        $new->request = $request_params;
102
        return $new;
103
    }
104
105
    /**
106
     * Returns the request parameters of the request
107
     *
108
     * @return array
109
     */
110
    public function getRequestParams(): array
111
    {
112
        return $this->request;
113
    }
114
115
    /**
116
     * Recreates the `Request` with specified server parameters
117
     *
118
     * @param array $server
119
     * @return Request
120
     */
121
    public function withServerParams(array $server): Request
122
    {
123
        $new = clone $this;
124
        $new->server = $server;
125
        $new->setContentTypeFromServerParams($server['HTTP_CONTENT_TYPE'] ?? '');
126
        $new->setAcceptTypeFromServerParams($server['HTTP_ACCEPT'] ?? '');
127
        $new->method = $server['REQUEST_METHOD'] ?? Http::GET;
128
        $new->headers = Http::getRequestHeadersFromServerArray($server);
129
        return $new;
130
    }
131
132
    private function setContentTypeFromServerParams(string $content_type): void
133
    {
134
        $known_content_types = [
135
            Http::CONTENT_JSON,
136
            Http::CONTENT_XML,
137
            Http::CONTENT_TEXT_XML,
138
            Http::CONTENT_FORM,
139
            Http::CONTENT_TEXT,
140
        ];
141
        foreach ($known_content_types as $t) {
142
            if (strpos($content_type, $t) !== false) {
143
                $this->content_type = $t;
144
                return;
145
            }
146
        }
147
    }
148
149
    private function setAcceptTypeFromServerParams(string $accept_type): void
150
    {
151
        $known_accept_types = [
152
            Http::CONTENT_JSON,
153
            Http::CONTENT_HTML,
154
            Http::CONTENT_XML,
155
            Http::CONTENT_TEXT_XML,
156
            Http::CONTENT_TEXT,
157
        ];
158
        foreach ($known_accept_types as $t) {
159
            if (strpos($accept_type, $t) !== false) {
160
                $this->accept_type = $t;
161
                return;
162
            }
163
        }
164
    }
165
166
    /**
167
     * Returns the header specified accept type(s) of the request
168
     *
169
     * @return string
170
     */
171
    public function acceptType(): string
172
    {
173
        return $this->accept_type;
174
    }
175
176
    /**
177
     * Returns the server parameters of the request
178
     *
179
     * @return array
180
     */
181
    public function getServerParams(): array
182
    {
183
        return $this->server;
184
    }
185
186
    /**
187
     * Returns the server parameter value of `$name` or null if not set
188
     *
189
     * @param string $name
190
     * @return null|string
191
     */
192
    public function getServerParam(string $name): ?string
193
    {
194
        return $this->server[$name] ?? null;
195
    }
196
197
    /**
198
     * Recreates the `Request` with the specified post data
199
     *
200
     * @param array $post
201
     * @return Request
202
     */
203
    public function withPostData(array $post): Request
204
    {
205
        $new = clone $this;
206
        $new->post = $post;
207
        return $new;
208
    }
209
210
    /**
211
     * Returns the post data of the request
212
     *
213
     * @return array
214
     */
215
    public function getPostData(): array
216
    {
217
        return $this->post;
218
    }
219
220
    /**
221
     * Recreates the `Request` with the specified get (quary) data
222
     *
223
     * @param array $get
224
     * @return Request
225
     */
226
    public function withGetData(array $get): Request
227
    {
228
        $new = clone $this;
229
        $new->get = $get;
230
        return $new;
231
    }
232
233
    /**
234
     * Returns the request data of the request
235
     *
236
     * @return array
237
     */
238
    public function getGetData(): array
239
    {
240
        return $this->get;
241
    }
242
243
    /**
244
     * Alias of `getGetData`
245
     *
246
     * @return array
247
     */
248
    public function query(): array
249
    {
250
        return $this->getGetData();
251
    }
252
253
    /**
254
     * Recreates the `Request` with the specified Url parameters
255
     *
256
     * Url parameters are extracted with dynamic routes, aka:
257
     * `/api/location/(?<city>\w+)/visit` the "city" part.
258
     *
259
     * @param array $parameters
260
     * @return Request
261
     */
262
    public function withUrlParams(array $parameters): Request
263
    {
264
        $new = clone $this;
265
        $new->parameters = $parameters;
266
        return $new;
267
    }
268
269
    /**
270
     * Returns the url parameters of the request
271
     *
272
     * @return array
273
     */
274
    public function getUrlParams(): array
275
    {
276
        return $this->parameters;
277
    }
278
279
    /**
280
     * Recreates the `Request` with the specified Route
281
     *
282
     * @param interfaces\Route $route
283
     * @return Request
284
     */
285
    public function withRoute(interfaces\Route $route): Request
286
    {
287
        $new = clone $this;
288
        $new->route = $route;
289
        $new->parameters = $route->parameters();
290
        return $new;
291
    }
292
293
    /**
294
     * Returns the `Route` of the request, if set, null if not.
295
     *
296
     * @return interfaces\Route|null
297
     */
298
    public function route(): ?interfaces\Route
299
    {
300
        return $this->route;
301
    }
302
303
    /**
304
     * Recreates the `Request` with the given `Session` object
305
     *
306
     * @param interfaces\Session $session
307
     * @return Request
308
     */
309
    public function withSession(interfaces\Session $session): Request
310
    {
311
        $new = clone $this;
312
        $new->session = $session;
313
        return $new;
314
    }
315
316
    /**
317
     * Returns the page variables (those variables to be injected into templates) of request
318
     *
319
     * @return array
320
     */
321
    public function pageVars(): array
322
    {
323
        return $this->page_vars;
324
    }
325
326
    /**
327
     * Recreates the `Request` with the given page variables
328
     */
329
    public function withPageVars(array $vars): Request
330
    {
331
        $new = clone $this;
332
        $new->page_vars = $vars;
333
        return $new;
334
    }
335
336
    /**
337
     * Overwrites Message::content to grab POST data
338
     *
339
     * @return null|string|array|\SimpleXMLElement|\DOMDocument body converted from raw format
340
     */
341
    public function content()
342
    {
343
        if ($this->contentType() === Http::CONTENT_FORM) {
344
            return $this->post;
345
        }
346
        return parent::content();
347
    }
348
349
    /**
350
     * Returns the session var at $key or the Session object
351
     *
352
     * First call to this method will initiate the session
353
     *
354
     * @param string $key Dot notation for deeper values, i.e. `user.email`
355
     * @return mixed|interfaces\Session
356
     */
357
    public function session(?string $key = null)
358
    {
359
        if (is_null($this->session)) {
360
            throw new \Exception("No Session object in Request");
361
        }
362
        if (is_null($key)) {
363
            $this->session->startIfNotStarted();
364
            return $this->session;
365
        }
366
        return $this->session->get($key);
367
    }
368
369
    /**
370
     * Redirect NOW the request to $url
371
     *
372
     * Method includes usage of the `exit` php command
373
     *
374
     * @codeCoverageIgnore
375
     * @param string $url
376
     */
377
    public function redirect($url): void
378
    {
379
        // @TODO add support for reverse route match
380
        header("Location: " . $url);
381
        exit;
382
    }
383
}
384