Passed
Pull Request — master (#6)
by
unknown
07:52
created

Dispatch::getRequestBody()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 17
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 8
c 1
b 0
f 0
nc 3
nop 0
dl 0
loc 17
rs 10
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 = $this->getRequestBody();
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 (in_array($this->httpMethod, ["POST", "PUT", "PATCH", "DELETE"])) {
175
			$this->data = $this->getRequestBody();
176
177
			unset($this->data["_method"]);
178
			return;
179
		}
180
181
		$this->data = [];
182
		return;
183
	}
184
185
	protected function getRequestBody(): ?array
186
	{
187
		$headers = getallheaders();
188
189
		if (isset($headers['Content-Type']) && $headers['Content-Type'] === 'application/json') {
190
			if (!isset($_SERVER['CONTENT_LENGTH'])) {
191
				return [];
192
			}
193
194
			$rawPost = file_get_contents("php://input", false, null, 0, $_SERVER['CONTENT_LENGTH']);
195
196
			$jsonData = json_decode($rawPost, true);
197
198
			return $jsonData;
199
		}
200
201
		return filter_input_array(INPUT_POST, FILTER_DEFAULT);
202
	}
203
}
204