Request::fullUrl()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 6
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 10
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 ?interfaces\Route $route = null;
19
    /**
20
     * @var null|interfaces\Session
21
     */
22
    protected ?interfaces\Session $session = null;
23
    /** @var array<string, mixed> */
24
    protected array $parameters = [];
25
    /** @var array */
26
    protected array $request = [];
27
    /** @var array */
28
    protected array $server = [];
29
    /** @var array */
30
    protected array $get = [];
31
    /** @var array */
32
    protected array $post = [];
33
    /** @var string */
34
    protected string $content_type = ''; // Type of the REQUEST BODY, not response
35
    /** @var string */
36
    protected string $accept_type = Http::CONTENT_HTML;
37
    /** @var array */
38
    protected array $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) && is_array($data)) {
0 ignored issues
show
introduced by
The condition is_array($data) is always false.
Loading history...
60
                // Cache the json body in the post array
61
                $this->post = $data;
62
            }
63
            if (is_array($data) && isset($data[$name])) {
0 ignored issues
show
introduced by
The condition is_array($data) is always false.
Loading history...
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<string, mixed> $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<string, mixed>
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<string, mixed> $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<string, mixed>
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<string, mixed> $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<string, mixed>
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<string, mixed> $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<string, mixed>
237
     */
238
    public function getGetData(): array
239
    {
240
        return $this->get;
241
    }
242
243
    /**
244
     * Alias of `getGetData`
245
     *
246
     * @return array<string, mixed>
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<string, mixed> $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<string, mixed>
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<string, mixed>
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
     * @param array<string, mixed> $vars
329
     * @return Request
330
     */
331
    public function withPageVars(array $vars): Request
332
    {
333
        $new = clone $this;
334
        $new->page_vars = $vars;
335
        return $new;
336
    }
337
338
    /**
339
     * Overwrites Message::content to grab POST data
340
     *
341
     * @return null|string|array<mixed>|\SimpleXMLElement|\DOMDocument body converted from raw format
342
     */
343
    public function content()
344
    {
345
        if ($this->contentType() === Http::CONTENT_FORM) {
346
            return $this->post;
347
        }
348
        return parent::content();
349
    }
350
351
    /**
352
     * Returns the session var at $key or the Session object
353
     *
354
     * First call to this method will initiate the session
355
     *
356
     * @param string $key Dot notation for deeper values, i.e. `user.email`
357
     * @return mixed|interfaces\Session
358
     */
359
    public function session(?string $key = null)
360
    {
361
        if (is_null($this->session)) {
362
            throw new \Exception("No Session object in Request");
363
        }
364
        if (is_null($key)) {
365
            $this->session->startIfNotStarted();
366
            return $this->session;
367
        }
368
        return $this->session->get($key);
369
    }
370
371
    /**
372
     * Redirect NOW the request to $url
373
     *
374
     * Method includes usage of the `exit` php command
375
     *
376
     * @codeCoverageIgnore
377
     * @param string $url
378
     */
379
    public function redirect($url): void
380
    {
381
        // @TODO add support for reverse route match
382
        header("Location: " . $url);
383
        exit;
384
    }
385
}
386