Passed
Push — master ( 2c3fac...66aab6 )
by Robson
02:18
created

Dispatch::current()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 0
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace CoffeeCode\Router;
4
5
/**
6
 * Class CoffeeCode Dispatch
7
 *
8
 * @author Robson V. Leite <https://github.com/robsonvleite>
9
 * @package CoffeeCode\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->path = rtrim((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 ? trim($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 object|null
100
     */
101
    public function current(): ?object
102
    {
103
        return (object)array_merge([
104
            "namespace" => $this->namespace,
105
            "group" => $this->group,
106
            "path" => $this->path
107
        ], $this->route);
0 ignored issues
show
Bug introduced by
It seems like $this->route can also be of type null; however, parameter $arrays of array_merge() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

107
        ], /** @scrutinizer ignore-type */ $this->route);
Loading history...
108
    }
109
110
    /**
111
     * @return null|int
112
     */
113
    public function error(): ?int
114
    {
115
        return $this->error;
116
    }
117
118
    /**
119
     * @return bool
120
     */
121
    public function dispatch(): bool
122
    {
123
        if (empty($this->routes) || empty($this->routes[$this->httpMethod])) {
124
            $this->error = self::NOT_IMPLEMENTED;
125
            return false;
126
        }
127
128
        $this->route = null;
129
        foreach ($this->routes[$this->httpMethod] as $key => $route) {
130
            if (preg_match("~^" . $key . "$~", $this->path, $found)) {
131
                $this->route = $route;
132
            }
133
        }
134
135
        return $this->execute();
136
    }
137
138
    /**
139
     * @return bool
140
     */
141
    private function execute()
142
    {
143
        if ($this->route) {
144
            if (is_callable($this->route['handler'])) {
145
                call_user_func($this->route['handler'], ($this->route['data'] ?? []));
146
                return true;
147
            }
148
149
            $controller = $this->route['handler'];
150
            $method = $this->route['action'];
151
152
            if (class_exists($controller)) {
153
                $newController = new $controller($this);
154
                if (method_exists($controller, $method)) {
155
                    $newController->$method(($this->route['data'] ?? []));
156
                    return true;
157
                }
158
159
                $this->error = self::METHOD_NOT_ALLOWED;
160
                return false;
161
            }
162
163
            $this->error = self::BAD_REQUEST;
164
            return false;
165
        }
166
167
        $this->error = self::NOT_FOUND;
168
        return false;
169
    }
170
171
    /**
172
     * httpMethod form spoofing
173
     */
174
    protected function formSpoofing(): void
175
    {
176
        $post = filter_input_array(INPUT_POST, FILTER_DEFAULT);
177
178
        if (!empty($post['_method']) && in_array($post['_method'], ["PUT", "PATCH", "DELETE"])) {
179
            $this->httpMethod = $post['_method'];
180
            $this->data = $post;
181
182
            unset($this->data["_method"]);
183
            return;
184
        }
185
186
        if ($this->httpMethod == "POST") {
187
            $this->data = filter_input_array(INPUT_POST, FILTER_DEFAULT);
188
189
            unset($this->data["_method"]);
190
            return;
191
        }
192
193
        if (in_array($this->httpMethod, ["PUT", "PATCH", "DELETE"]) && !empty($_SERVER['CONTENT_LENGTH'])) {
194
            parse_str(file_get_contents('php://input', false, null, 0, $_SERVER['CONTENT_LENGTH']), $putPatch);
195
            $this->data = $putPatch;
196
197
            unset($this->data["_method"]);
198
            return;
199
        }
200
201
        $this->data = [];
202
    }
203
}