Dispatch   A
last analyzed

Complexity

Total Complexity 25

Size/Duplication

Total Lines 180
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 67
c 1
b 0
f 0
dl 0
loc 180
rs 10
wmc 25

9 Methods

Rating   Name   Duplication   Size   Complexity  
A error() 0 3 1
A __debugInfo() 0 3 1
A namespace() 0 4 2
A formSpoofing() 0 29 6
A execute() 0 28 5
A data() 0 3 1
A dispatch() 0 15 5
A __construct() 0 6 2
A group() 0 4 2
1
<?php
2
3
namespace SimpSyst\Router;
4
5
/**
6
 * Class SimpSyst Dispatch
7
 *
8
 * @author Diego Matos <https://github.com/diegoamatos>
9
 * @package SimpSyst\Router
10
 */
11
abstract class Dispatch
12
{
13
    use RouterTrait;
14
15
    /** @var null|array */
16
    protected $route;
17
18
    /** @var bool|string */
19
    protected $projectUrl;
20
21
    /** @var string */
22
    protected $separator;
23
24
    /** @var null|string */
25
    protected $namespace;
26
27
    /** @var null|string */
28
    protected $group;
29
30
    /** @var null|array */
31
    protected $data;
32
33
    /** @var int */
34
    protected $error;
35
36
    /** @const int Bad Request */
37
    public const BAD_REQUEST = 400;
38
39
    /** @const int Not Found */
40
    public const NOT_FOUND = 404;
41
42
    /** @const int Method Not Allowed */
43
    public const METHOD_NOT_ALLOWED = 405;
44
45
    /** @const int Not Implemented */
46
    public const NOT_IMPLEMENTED = 501;
47
48
    /**
49
     * Dispatch constructor.
50
     *
51
     * @param string $projectUrl
52
     * @param null|string $separator
53
     */
54
    public function __construct(string $projectUrl, ?string $separator = ":")
55
    {
56
        $this->projectUrl = (substr($projectUrl, "-1") == "/" ? substr($projectUrl, 0, -1) : $projectUrl);
57
        $this->patch = (filter_input(INPUT_GET, "route", FILTER_DEFAULT) ?? "/");
58
        $this->separator = ($separator ?? ":");
59
        $this->httpMethod = $_SERVER['REQUEST_METHOD'];
60
    }
61
62
    /**
63
     * @return array
64
     */
65
    public function __debugInfo()
66
    {
67
        return $this->routes;
68
    }
69
70
    /**
71
     * @param null|string $namespace
72
     * @return Dispatch
73
     */
74
    public function namespace(?string $namespace): Dispatch
75
    {
76
        $this->namespace = ($namespace ? ucwords($namespace) : null);
77
        return $this;
78
    }
79
80
    /**
81
     * @param null|string $group
82
     * @return Dispatch
83
     */
84
    public function group(?string $group): Dispatch
85
    {
86
        $this->group = ($group ? str_replace("/", "", $group) : null);
87
        return $this;
88
    }
89
90
    /**
91
     * @return null|array
92
     */
93
    public function data(): ?array
94
    {
95
        return $this->data;
96
    }
97
98
    /**
99
     * @return null|int
100
     */
101
    public function error(): ?int
102
    {
103
        return $this->error;
104
    }
105
106
    /**
107
     * @return bool
108
     */
109
    public function dispatch(): bool
110
    {
111
        if (empty($this->routes) || empty($this->routes[$this->httpMethod])) {
112
            $this->error = self::NOT_IMPLEMENTED;
113
            return false;
114
        }
115
116
        $this->route = null;
117
        foreach ($this->routes[$this->httpMethod] as $key => $route) {
118
            if (preg_match("~^" . $key . "$~", $this->patch, $found)) {
119
                $this->route = $route;
120
            }
121
        }
122
123
        return $this->execute();
124
    }
125
126
    /**
127
     * @return bool
128
     */
129
    private function execute()
130
    {
131
        if ($this->route) {
132
            if (is_callable($this->route['handler'])) {
133
                call_user_func($this->route['handler'], ($this->route['data'] ?? []));
134
                return true;
135
            }
136
137
            $controller = $this->route['handler'];
138
            $method = $this->route['action'];
139
140
            if (class_exists($controller)) {
141
                $newController = new $controller($this);
142
                if (method_exists($controller, $method)) {
143
                    $newController->$method(($this->route['data'] ?? []));
144
                    return true;
145
                }
146
147
                $this->error = self::METHOD_NOT_ALLOWED;
148
                return false;
149
            }
150
151
            $this->error = self::BAD_REQUEST;
152
            return false;
153
        }
154
155
        $this->error = self::NOT_FOUND;
156
        return false;
157
    }
158
159
    /**
160
     * httpMethod form spoofing
161
     */
162
    protected function formSpoofing(): void
163
    {
164
        $post = filter_input_array(INPUT_POST, FILTER_DEFAULT);
165
166
        if (!empty($post['_method']) && in_array($post['_method'], ["PUT", "PATCH", "DELETE"])) {
167
            $this->httpMethod = $post['_method'];
168
            $this->data = $post;
0 ignored issues
show
Documentation Bug introduced by
It seems like $post can also be of type null. However, the property $data is declared as type array|null. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
169
170
            unset($this->data["_method"]);
171
            return;
172
        }
173
174
        if ($this->httpMethod == "POST") {
175
            $this->data = filter_input_array(INPUT_POST, FILTER_DEFAULT);
176
177
            unset($this->data["_method"]);
178
            return;
179
        }
180
181
        if (in_array($this->httpMethod, ["PUT", "PATCH", "DELETE"]) && !empty($_SERVER['CONTENT_LENGTH'])) {
182
            parse_str(file_get_contents('php://input', false, null, 0, $_SERVER['CONTENT_LENGTH']), $putPatch);
183
            $this->data = $putPatch;
184
185
            unset($this->data["_method"]);
186
            return;
187
        }
188
189
        $this->data = [];
190
        return;
191
    }
192
}