Passed
Push — master ( b9a9b1...3110e0 )
by Robson
01:44
created

Dispatch   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 180
Duplicated Lines 0 %

Importance

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

9 Methods

Rating   Name   Duplication   Size   Complexity  
A namespace() 0 4 2
A formSpoofing() 0 29 6
A group() 0 4 2
A dispatch() 0 15 5
A execute() 0 28 5
A error() 0 3 1
A __debugInfo() 0 3 1
A data() 0 3 1
A __construct() 0 6 2
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->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;
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
}