RequestProcessTrait   A
last analyzed

Complexity

Total Complexity 40

Size/Duplication

Total Lines 232
Duplicated Lines 0 %

Importance

Changes 7
Bugs 0 Features 1
Metric Value
wmc 40
eloc 108
c 7
b 0
f 1
dl 0
loc 232
rs 9.2

12 Methods

Rating   Name   Duplication   Size   Complexity  
A processPost() 0 7 2
A init() 0 23 5
A setMethod() 0 14 3
A clearGlobals() 0 14 4
A setBody() 0 4 1
A sanitize() 0 10 3
A setPath() 0 16 2
A setFilename() 0 7 2
A processCli() 0 14 5
A process() 0 7 2
B processHttp() 0 49 8
A getQueryString() 0 9 3

How to fix   Complexity   

Complex Class

Complex classes like RequestProcessTrait often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use RequestProcessTrait, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace WebServCo\Framework\Traits;
6
7
use WebServCo\Framework\Http\Method;
8
9
trait RequestProcessTrait
10
{
11
    abstract public function clearData(): bool;
12
13
    /**
14
     * @param mixed $key Can be an array, a string,
15
     *                          or a special formatted string
16
     *                          (eg 'i18n/lang').
17
     * @param mixed $value The value to be stored.
18
     * @return bool True on success and false on failure.
19
     */
20
    abstract public function setData($key, $value): bool;
21
22
    /**
23
    * @param mixed $key Can be an array, a string,
24
    *                          or a special formatted string
25
    *                          (eg 'i18n/lang').
26
    * @param mixed $defaultValue
27
    * @return mixed
28
    */
29
    abstract public function setting($key, $defaultValue = null);
30
31
    /**
32
    * Data value can be another array, for example _SERVER in CLI ("argv" is an array)
33
    * Important: only first level is sanitized.
34
    *
35
    * @param array<string,array<int,string>|string> $data
36
    * @return array<string,array<int,string>|string>
37
    */
38
    public function sanitize(array $data): array
39
    {
40
        foreach ($data as $key => $value) {
41
            if (\is_string($value)) {
42
                // Sanitize only first level (prevents "argv" from being sanitized)
43
                $value = \WebServCo\Framework\Helpers\RequestHelper::sanitizeString($value);
44
            }
45
            $data[$key] = $value;
46
        }
47
        return $data;
48
    }
49
50
    /**
51
    * @param array<string,mixed> $server
52
    * @param array<string,string> $post
53
    */
54
    protected function init(array $server, array $post = []): bool
55
    {
56
        $this->server = $this->sanitize($server);
0 ignored issues
show
Bug Best Practice introduced by
The property server does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
57
58
        $this->setBody();
59
        $this->setMethod();
60
        $this->setFilename();
61
        $this->setPath();
62
63
        $this->process();
64
65
        switch ($this->method) {
66
            case Method::GET:
67
            case Method::HEAD:
68
                break;
69
            case Method::POST:
70
                $this->processPost($post);
71
                break;
72
        }
73
        if ($this->setting('clear_globals', false)) {
74
            $this->clearGlobals();
75
        }
76
        return true;
77
    }
78
79
    protected function setBody(): bool
80
    {
81
        $this->body = (string) \file_get_contents('php://input');
0 ignored issues
show
Bug Best Practice introduced by
The property body does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
82
        return true;
83
    }
84
85
    protected function setMethod(): bool
86
    {
87
        if (
88
            empty($this->server['REQUEST_METHOD']) ||
89
            !\in_array(
90
                $this->server['REQUEST_METHOD'],
91
                Method::getSupported(),
92
                true,
93
            )
94
        ) {
95
            return false;
96
        }
97
        $this->method = $this->server['REQUEST_METHOD'];
0 ignored issues
show
Bug Best Practice introduced by
The property method does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
98
        return true;
99
    }
100
101
    protected function setFilename(): bool
102
    {
103
        if (empty($this->server['SCRIPT_NAME'])) {
104
            return false;
105
        }
106
        $this->filename = \basename($this->server['SCRIPT_NAME']);
0 ignored issues
show
Bug Best Practice introduced by
The property filename does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
107
        return true;
108
    }
109
110
    protected function setPath(): bool
111
    {
112
        if (empty($this->server['SCRIPT_NAME'])) {
113
            return false;
114
        }
115
116
        $this->path = \rtrim(
0 ignored issues
show
Bug Best Practice introduced by
The property path does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
117
            \str_replace(
118
                $this->filename,
119
                '',
120
                $this->server['SCRIPT_NAME'],
121
            ),
122
            \DIRECTORY_SEPARATOR,
123
        );
124
125
        return true;
126
    }
127
128
    protected function clearGlobals(): bool
129
    {
130
        if (!empty($_GET)) {
131
            foreach ($_GET as $k => $v) {
132
                unset($_REQUEST[$k]);
133
            }
134
135
            $_GET = [];
136
        }
137
138
        if (!empty($_POST)) {
139
            $_POST = [];
140
        }
141
        return true;
142
    }
143
144
    /**
145
    * @param array<string,string> $post
146
    */
147
    protected function processPost(array $post = []): bool
148
    {
149
        $this->clearData();
150
        foreach ($post as $k => $v) {
151
            $this->setData(\WebServCo\Framework\Helpers\RequestHelper::sanitizeString((string) $k), $v);
152
        }
153
        return true;
154
    }
155
156
    protected function process(): bool
157
    {
158
        if (\WebServCo\Framework\Helpers\PhpHelper::isCli()) {
159
            return $this->processCli();
160
        }
161
162
        return $this->processHttp();
163
    }
164
165
    protected function processCli(): bool
166
    {
167
        if (isset($this->server['argv'][1])) {
168
            $this->target = $this->server['argv'][1];
0 ignored issues
show
Bug Best Practice introduced by
The property target does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
169
        }
170
        if (isset($this->server['argv'][2])) {
171
            foreach ($this->server['argv'] as $k => $v) {
172
                if (\in_array($k, [0, 1], true)) {
173
                    continue;
174
                }
175
                $this->args[] = \WebServCo\Framework\Helpers\RequestHelper::sanitizeString($v);
0 ignored issues
show
Bug Best Practice introduced by
The property args does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
176
            }
177
        }
178
        return true;
179
    }
180
181
    protected function processHttp(): bool
182
    {
183
        $string = null;
184
        switch (true) {
185
            case isset($this->server['REDIRECT_URL']):
186
                /**
187
                 * Specific situation:
188
                 * - rewrite is done in an external website,
189
                 * and current project is used a subfolder (symlink) of the main website.
190
                 * In that case the `REQUEST_URI` will contain the source (left part of the rewrite)
191
                 * and `REDIRECT_URL` will contain the actual target path (right part of the rewrite).
192
                 * So this needs to be before the `REQUEST_URI` check.
193
                 */
194
                $string = $this->server['REDIRECT_URL'];
195
                // Seems in this case the query string is not added, so check and added.
196
                if (!\strpos($string, '?')) {
197
                    $queryString = $this->getQueryString();
198
                    if ('' !== $queryString) {
199
                        $string = \sprintf('%s?%s', $string, $queryString);
200
                    }
201
                }
202
                break;
203
            case isset($this->server['REQUEST_URI']):
204
                $string = $this->server['REQUEST_URI'];
205
                break;
206
            case isset($this->server['PATH_INFO']):
207
                $string = $this->server['PATH_INFO'];
208
                break;
209
            case isset($this->server['ORIG_PATH_INFO']):
210
                $string = $this->server['ORIG_PATH_INFO'];
211
                break;
212
            case !empty($this->server['QUERY_STRING']):
213
                $string = $this->server['ORIG_PATH_INFO'];
214
                break;
215
            default:
216
                break;
217
        }
218
        [$target, $queryString, $suffix] = \WebServCo\Framework\Helpers\RequestHelper::parse(
219
            $string,
220
            $this->path,
221
            $this->filename,
222
            $this->setting('suffixes', []),
223
        );
224
        $this->target = \WebServCo\Framework\Helpers\RequestHelper::sanitizeString(\urldecode($target));
0 ignored issues
show
Bug Best Practice introduced by
The property target does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
225
        $this->query = \WebServCo\Framework\Helpers\RequestHelper::format(
0 ignored issues
show
Bug Best Practice introduced by
The property query does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
226
            \WebServCo\Framework\Helpers\RequestHelper::sanitizeString($queryString),
227
        );
228
        $this->suffix = $suffix;
0 ignored issues
show
Bug Best Practice introduced by
The property suffix does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
229
        return true;
230
    }
231
232
    private function getQueryString(): string
233
    {
234
        switch (true) {
235
            case isset($this->server['REDIRECT_QUERY_STRING']):
236
                return $this->server['REDIRECT_QUERY_STRING'];
237
            case isset($this->server['QUERY_STRING']):
238
                return $this->server['QUERY_STRING'];
239
            default:
240
                return '';
241
        }
242
    }
243
}
244