staticRouteMap = $data->getStaticRoutes(); $this->variableRouteData = $data->getVariableRoutes(); $this->filters = $data->getFilters(); if ($resolver === null) { $this->handlerResolver = new HandlerResolver(); } else { $this->handlerResolver = $resolver; } } /** * Dispatch a route for the given HTTP Method / URI. * * @param $httpMethod * @param $uri * @return mixed|null */ public function dispatch($httpMethod, $uri) { list($handler, $filters, $vars) = $this->dispatchRoute($httpMethod, trim($uri, '/')); list($beforeFilter, $afterFilter) = $this->parseFilters($filters); if(($response = $this->dispatchFilters($beforeFilter)) !== null) { return $response; } $resolvedHandler = $this->handlerResolver->resolve($handler); $response = call_user_func_array($resolvedHandler, $vars); return $this->dispatchFilters($afterFilter, $response); } /** * Dispatch a route filter. * * @param $filters * @param null $response * @return mixed|null */ private function dispatchFilters($filters, $response = null) { while($filter = array_shift($filters)) { $handler = $this->handlerResolver->resolve($filter['closure']); $params = array_merge([$response], $filter['params']); if(($filteredResponse = call_user_func_array($handler, $params)) !== null) { return $filteredResponse; } } return $response; } /** * Normalise the array filters attached to the route and merge with any global filters. * * @param $filters * @return array */ private function parseFilters($filters) { $beforeFilter = array(); $afterFilter = array(); if(isset($filters[Route::BEFORE])) { foreach ($filters[Route::BEFORE] as $filter){ if(array_key_exists($filter['name'], $this->filters)){ $beforeFilter[] = array_merge($filter, ['closure' => $this->filters[$filter['name']]]); } } //$beforeFilter = array_intersect_key($this->filters, array_flip((array) $filters[Route::BEFORE])); } if(isset($filters[Route::AFTER])) { foreach ($filters[Route::AFTER] as $filter){ if(array_key_exists($filter['name'], $this->filters)){ $afterFilter[] = array_merge($filter, ['closure' => $this->filters[$filter['name']]]); } } //$afterFilter = array_intersect_key($this->filters, array_flip((array) $filters[Route::AFTER])); } return array($beforeFilter, $afterFilter); } /** * Perform the route dispatching. Check static routes first followed by variable routes. * * @param $httpMethod * @param $uri * @throws Exception\HttpRouteNotFoundException */ private function dispatchRoute($httpMethod, $uri) { if (isset($this->staticRouteMap[$uri])) { return $this->dispatchStaticRoute($httpMethod, $uri); } return $this->dispatchVariableRoute($httpMethod, $uri); } /** * Handle the dispatching of static routes. * * @param $httpMethod * @param $uri * @return mixed * @throws Exception\HttpMethodNotAllowedException */ private function dispatchStaticRoute($httpMethod, $uri) { $routes = $this->staticRouteMap[$uri]; if (!isset($routes[$httpMethod])) { $httpMethod = $this->checkFallbacks($routes, $httpMethod); } return $routes[$httpMethod]; } /** * Check fallback routes: HEAD for GET requests followed by the ANY attachment. * * @param $routes * @param $httpMethod * @throws Exception\HttpMethodNotAllowedException */ private function checkFallbacks($routes, $httpMethod) { $additional = array(Route::ANY); if($httpMethod === Route::HEAD) { $additional[] = Route::GET; } foreach($additional as $method) { if(isset($routes[$method])) { return $method; } } $this->matchedRoute = $routes; throw new HttpMethodNotAllowedException('Allow: ' . implode(', ', array_keys($routes))); } /** * Handle the dispatching of variable routes. * * @param $httpMethod * @param $uri * @throws Exception\HttpMethodNotAllowedException * @throws Exception\HttpRouteNotFoundException */ private function dispatchVariableRoute($httpMethod, $uri) { foreach ($this->variableRouteData as $data) { if (!preg_match($data['regex'], $uri, $matches)) { continue; } $count = count($matches); while(!isset($data['routeMap'][$count++])); $routes = $data['routeMap'][$count - 1]; if (!isset($routes[$httpMethod])) { $httpMethod = $this->checkFallbacks($routes, $httpMethod); } foreach (array_values($routes[$httpMethod][2]) as $i => $varName) { if(!isset($matches[$i + 1]) || $matches[$i + 1] === '') { unset($routes[$httpMethod][2][$varName]); } else { $routes[$httpMethod][2][$varName] = $matches[$i + 1]; } } return $routes[$httpMethod]; } throw new HttpRouteNotFoundException('Route ' . $uri . ' does not exist'); } }