routes; } /** * @param $middleware mixed */ public function addMiddleware($middleware) { if (is_string($middleware)) { $this->_middlewares[] = new LuMiddlewareDbo($middleware); } else if (is_array($middleware)) { $this->_middlewares[] = LuMiddlewareDbo::jsonDeserialize($middleware); } else { $this->_middlewares[] = $middleware; } } public function setup() { $routeCollector = new RouteCollector(new Std(), new DataGeneratorGroupCountBased()); $router = $this; foreach ($this->getRoutes() as $route) { $routeCollector->addRoute($route->getMethod(), $route->getUrl(), function($parameters) use($route, $router) { return $router->execute($route, $parameters); }); } $this->_dispatcher = new DispatcherGroupCountBased($routeCollector->getData()); } public function execute(LuRouteDbo $route, $parameters) { $middlewares = []; /** * @var $middlewareDbo LuMiddlewareDbo */ foreach (array_merge($this->_middlewares, $route->getMiddlewares()) as $middlewareDbo) { $middlewareName = $middlewareDbo->getMiddleware(); /** * @var $middleware LuAbstractMiddleware */ $middleware = new $middlewareName(); $parameters["_middleware"] = $middlewareDbo->getParameters(); foreach ($route->getParameters() as $key => $value) { $parameters["_middleware"][$key] = $value; } $parameters = $middleware->onBefore($route, $parameters); $middlewares[] = [ 'middleware' => $middleware, 'dbo' => $middlewareDbo ]; } unset($parameters["_middleware"]); $reflect = new \ReflectionMethod($route->getController(), $route->getAction()); $params = $reflect->getParameters(); $docs = new LuMethodDocParser($reflect->getDocComment()); $docs->parse(); $args = array(); foreach ($params as $param) { try { if ($param->isOptional()) { $value = null; if (array_key_exists($param->getName(), $parameters)) { $value = $this->getParam($param, $parameters[$param->getName()]); } else { $value = $param->getDefaultValue(); } } else { if (array_key_exists($param->getName(), $parameters)) { $value = $this->getParam($param, $parameters[$param->getName()]); } else { throw new LuDboDeserializeException("Missing parameter '" . $param->getName() . "'", 400); } } if (array_key_exists($param->getName(), $docs->getParams())) { $doc = $docs->getParams()[$param->getName()]; if (is_null($value) && $doc->isNotNull()) { throw new LuDboConstraintException("Parameter '" . $param->getName() . "' can not be null", 400); } if (!is_null($value)) { $value->checkConstraints($doc->getConstraints()); } } $args[$param->getName()] = $value; } catch (LuDboConstraintException $e) { $paramName = $param->getName(); throw new LuBusinessException("Invalid value for '${paramName}': " . $e->getMessage(), 400, $e); } catch (LuDboDeserializeException $e) { $paramName = $param->getName(); throw new LuBusinessException("Failed to deserialize '${paramName}': " . $e->getMessage(), 400, $e); } } $controller = $route->getController(); $controllerInstance = new $controller(); $result = call_user_func_array(array($controllerInstance, $route->getAction()), $args); foreach ($middlewares as $middlewareArray) { $middleware = $middlewareArray['middleware']; $middlewareDbo = $middlewareArray['dbo']; $parameters["_middleware"] = $middlewareDbo->getParameters(); foreach ($route->getParameters() as $key => $value) { $parameters["_middleware"][$key] = $value; } $result = $middleware->onAfter($route, $parameters, $result); } return $result; } public function dispatch(string $httpMethod, string $url, $parameters) { $routeInfo = $this->_dispatcher->dispatch($httpMethod, $url); if ($routeInfo[0] == Dispatcher::NOT_FOUND) { throw new LuBusinessException("Route not found", 404); } else if ($routeInfo[0] == Dispatcher::METHOD_NOT_ALLOWED) { throw new LuBusinessException("Method not allowed", 405); } else { $handler = $routeInfo[1]; $urlVars = $routeInfo[2]; $parameters = array_merge($parameters, $urlVars); return $handler($parameters); } } private function getClassName(\ReflectionParameter $param) { preg_match('/\[\s\<\w+?>\s([\w]+)/s', $param->__toString(), $matches); return isset($matches[1]) ? $matches[1] : null; } private function getParam(\ReflectionParameter $param, $value) { $typedValue = null; $className = $this->getClassName($param); if (is_null($className)) { $typedValue = $value; } else { $class = $param->getClass(); try { $json = json_decode($value, true); $typedValue = call_user_func_array(array($class->getName(), "jsonDeserialize"), array($json)); } catch (\Exception $e) { if ($e instanceof LuDboDeserializeException || $e instanceof LuDboConstraintException) { throw $e; } throw new LuBusinessException("Unable to parse JSON value for '" . $param->getName() . "'", 400, $e); } } return $typedValue; } public function addRoute2(LuRouteDbo $route) { $controller = $route->getController(); if (strpos($controller, "\\") === false) { $controller = "App\\Controller\\" . $controller . "Controller"; } $route->setController($controller); $this->routes[] = $route; } public function addRoute(string $httpMethod, string $url, string $controller, string $method, $parameters = array(), $middlewares = array()) { $middlewaresDbo = []; foreach ($middlewares as $middleware) { if (is_string($middleware)) { $middlewaresDbo[] = new LuMiddlewareDbo($middleware); } else if (is_array($middleware)) { $middlewaresDbo[] = LuMiddlewareDbo::jsonDeserialize($middleware); } else { $middlewaresDbo[] = $middleware; } } $route = new LuRouteDbo(); $route->setUrl($url); $route->setController($controller); $route->setAction($method); $route->setMiddlewares($middlewaresDbo); $route->setParameters($parameters); $route->setMethod($httpMethod); $this->addRoute2($route); } public function get(string $url, string $controller, string $method, $parameters = array(), $middleware = array()) { $this->addRoute("GET", $url, $controller, $method, $parameters, $middleware); } public function post(string $url, string $controller, string $method, $parameters = array(), $middleware = array()) { $this->addRoute("POST", $url, $controller, $method, $parameters, $middleware); } public function put(string $url, string $controller, string $method, $parameters = array(), $middleware = array()) { $this->addRoute("PUT", $url, $controller, $method, $parameters, $middleware); } public function delete(string $url, string $controller, string $method, $parameters = array(), $middleware = array()) { $this->addRoute("DELETE", $url, $controller, $method, $parameters, $middleware); } }