/** * Creation d'un nouveau dispatcher * @param null|Request $request */ public function __construct(\Router\Request $request = null) { if ($request === null) { require_once __DIR__ . "/Request.php"; $request = new \Router\Request(); } $this->request = $request; $this->method = $request->getMethod(); }
/** * @param $key * * @return Cookie */ public function getCookie($key) { if ($cookieValue = $this->request->cookies()->get($key)) { $cookie = new Cookie(); $cookie->setName($key); $cookie->setValue($cookieValue); return $cookie; } return null; }
/** * On lance le dispatch de la requete avec les routes inséré * @param Response $response * @return bool */ public function perform(\Router\Response $response) { // ajout de la route global si existe $aApplyRoute = $this->routes['ANY']; if (isset($this->routes[$this->method])) { $aApplyRoute = array_merge($this->routes[$this->method], $aApplyRoute); } if (!empty($aApplyRoute)) { require_once __DIR__ . "/Route.php"; foreach ($aApplyRoute as $route) { // récuperation des params de la route et creation de l'objet pour test list($pattern_uri, $callback, $filters) = $route; $oRoute = new \Router\Route($pattern_uri, array_merge($this->filters, $filters)); if (false === ($params = $oRoute->match($this->request->getRequestUri()))) { continue; } // insert des params dans le request foreach ($params as $key => $value) { $this->request->setParam($key, $value); } // appel du callback si c'est possible if (is_callable($callback) === true) { ob_start(); call_user_func_array($callback, array($this->request, $response)); $response->appendBody(ob_get_contents()); ob_end_clean(); } return true; } unset($oRoute); } // renvoi false si aucune regle n'est passé return false; }
/** * Create a new mock request * * @param string $uri * @param string $req_method * @param array $parameters * @param array $cookies * @param array $server * @param array $files * @param string $body * @return void */ public static function create($uri = '/', $req_method = 'GET', $parameters = array(), $cookies = array(), $server = array(), $files = array(), $body = null) { // Create a new Request object $request = new Request(array(), array(), $cookies, $server, $files, $body); // Reformat $req_method = strtoupper(trim($req_method)); // Set its URI and Method $request->server()->set('REQUEST_URI', $uri); $request->server()->set('REQUEST_METHOD', $req_method); // Set our parameters switch ($req_method) { case 'POST': case 'PUT': case 'PATCH': case 'DELETE': $request->paramsPost()->replace($parameters); break; default: $request->paramsGet()->replace($parameters); break; } return $request; }
/** * @return Request * @deprecated */ public function getRequest() { if (!($request = $this->getContainer()->get('request'))) { $request = Request::createFromGlobals(); $this->getContainer()->set('request', $request); } return $request; }
public function testId() { // Create two requests $request_one = new Request(); $request_two = new Request(); // Make sure the ID's aren't null $this->assertNotNull($request_one->id()); $this->assertNotNull($request_two->id()); // Make sure that multiple calls yield the same result $this->assertSame($request_one->id(), $request_one->id()); $this->assertSame($request_one->id(), $request_one->id()); $this->assertSame($request_two->id(), $request_two->id()); $this->assertSame($request_two->id(), $request_two->id()); // Make sure the ID's are unique to each request $this->assertNotSame($request_one->id(), $request_two->id()); }
/** * Dispatch the request to the appropriate route(s) * * Dispatch with optionally injected dependencies * This DI allows for easy testing, object mocking, or class extension * * @param Request $request The request object to give to each callback * @param AbstractResponse $response The response object to give to each callback * @param boolean $send_response Whether or not to "send" the response after the last route has been matched * @param int $capture Specify a DISPATCH_* constant to change the output capturing behavior * @return void|string */ public function dispatch(Request $request = null, AbstractResponse $response = null, $send_response = true, $capture = self::DISPATCH_NO_CAPTURE) { // Set/Initialize our objects to be sent in each callback $this->request = $request ?: Request::createFromGlobals(); $this->response = $response ?: new Response(); // Prepare any named routes $this->routes->prepareNamed(); // Grab some data from the request $uri = $this->request->pathname(); $req_method = $this->request->method(); // Set up some variables for matching $skip_num = 0; $matched = $this->routes->cloneEmpty(); // Get a clone of the routes collection, as it may have been injected $methods_matched = array(); $params = array(); $apc = function_exists('apc_fetch'); ob_start(); try { foreach ($this->routes as $route) { // Are we skipping any matches? if ($skip_num > 0) { $skip_num--; continue; } // Grab the properties of the route handler $method = $route->getMethod(); $path = $route->getPath(); $count_match = $route->getCountMatch(); // Keep track of whether this specific request method was matched $method_match = null; // Was a method specified? If so, check it against the current request method if (is_array($method)) { foreach ($method as $test) { if (strcasecmp($req_method, $test) === 0) { $method_match = true; } elseif (strcasecmp($req_method, 'HEAD') === 0 && (strcasecmp($test, 'HEAD') === 0 || strcasecmp($test, 'GET') === 0)) { // Test for HEAD request (like GET) $method_match = true; } } if (null === $method_match) { $method_match = false; } } elseif (null !== $method && strcasecmp($req_method, $method) !== 0) { $method_match = false; // Test for HEAD request (like GET) if (strcasecmp($req_method, 'HEAD') === 0 && (strcasecmp($method, 'HEAD') === 0 || strcasecmp($method, 'GET') === 0)) { $method_match = true; } } elseif (null !== $method && strcasecmp($req_method, $method) === 0) { $method_match = true; } // If the method was matched or if it wasn't even passed (in the route callback) $possible_match = null === $method_match || $method_match; // ! is used to negate a match if (isset($path[0]) && $path[0] === '!') { $negate = true; $i = 1; } else { $negate = false; $i = 0; } // Check for a wildcard (match all) if ($path === '*') { $match = true; } elseif ($path === '404' && $matched->isEmpty() && count($methods_matched) <= 0 || $path === '405' && $matched->isEmpty() && count($methods_matched) > 0) { // Warn user of deprecation trigger_error('Use of 404/405 "routes" is deprecated. Use $klein->onHttpError() instead.', E_USER_DEPRECATED); // TODO: Possibly remove in future, here for backwards compatibility $this->onHttpError($route); continue; } elseif (isset($path[$i]) && $path[$i] === '@') { // @ is used to specify custom regex $match = preg_match('`' . substr($path, $i + 1) . '`', $uri, $params); } else { // Compiling and matching regular expressions is relatively // expensive, so try and match by a substring first $expression = null; $regex = false; $j = 0; $n = isset($path[$i]) ? $path[$i] : null; // Find the longest non-regex substring and match it against the URI while (true) { if (!isset($path[$i])) { break; } elseif (false === $regex) { $c = $n; $regex = $c === '[' || $c === '(' || $c === '.'; if (false === $regex && false !== isset($path[$i + 1])) { $n = $path[$i + 1]; $regex = $n === '?' || $n === '+' || $n === '*' || $n === '{'; } if (false === $regex && $c !== '/' && (!isset($uri[$j]) || $c !== $uri[$j])) { continue 2; } $j++; } $expression .= $path[$i++]; } try { // Check if there's a cached regex string if (false !== $apc) { $regex = apc_fetch("route:{$expression}"); if (false === $regex) { $regex = $this->compileRoute($expression); apc_store("route:{$expression}", $regex); } } else { $regex = $this->compileRoute($expression); } } catch (RegularExpressionCompilationException $e) { throw RoutePathCompilationException::createFromRoute($route, $e); } $match = preg_match($regex, $uri, $params); } if (isset($match) && $match ^ $negate) { if ($possible_match) { if (!empty($params)) { /** * URL Decode the params according to RFC 3986 * @link http://www.faqs.org/rfcs/rfc3986 * * Decode here AFTER matching as per @chriso's suggestion * @link https://github.com/chriso/klein.php/issues/117#issuecomment-21093915 */ $params = array_map('rawurldecode', $params); $this->getRequest()->setAttributes($params); $this->request->paramsNamed()->merge($params); } // Handle our response callback try { $this->handleRouteCallback($route, $matched, $methods_matched); } catch (DispatchHaltedException $e) { switch ($e->getCode()) { case DispatchHaltedException::SKIP_THIS: continue 2; break; case DispatchHaltedException::SKIP_NEXT: $skip_num = $e->getNumberOfSkips(); break; case DispatchHaltedException::SKIP_REMAINING: break 2; default: throw $e; } } if ($path !== '*') { $count_match && $matched->add($route); } } // Don't bother counting this as a method match if the route isn't supposed to match anyway if ($count_match) { // Keep track of possibly matched methods $methods_matched = array_merge($methods_matched, (array) $method); $methods_matched = array_filter($methods_matched); $methods_matched = array_unique($methods_matched); } } } // Handle our 404/405 conditions if ($matched->isEmpty() && count($methods_matched) > 0) { // Add our methods to our allow header $this->response->header('Allow', implode(', ', $methods_matched)); if (strcasecmp($req_method, 'OPTIONS') !== 0) { throw HttpException::createFromCode(405); } } elseif ($matched->isEmpty()) { throw HttpException::createFromCode(404); } } catch (HttpExceptionInterface $e) { // Grab our original response lock state $locked = $this->response->isLocked(); // Call our http error handlers $this->httpError($e, $matched, $methods_matched); // Make sure we return our response to its original lock state if (!$locked) { $this->response->unlock(); } } catch (Exception $e) { $this->error($e); } try { if ($this->response->chunked) { $this->response->chunk(); } else { // Output capturing behavior switch ($capture) { case self::DISPATCH_CAPTURE_AND_RETURN: $buffed_content = null; if (ob_get_level()) { $buffed_content = ob_get_clean(); } return $buffed_content; break; case self::DISPATCH_CAPTURE_AND_REPLACE: if (ob_get_level()) { $this->response->body(ob_get_clean()); } break; case self::DISPATCH_CAPTURE_AND_PREPEND: if (ob_get_level()) { $this->response->prepend(ob_get_clean()); } break; case self::DISPATCH_CAPTURE_AND_APPEND: if (ob_get_level()) { $this->response->append(ob_get_clean()); } break; case self::DISPATCH_NO_CAPTURE: default: if (ob_get_level()) { ob_end_flush(); } } } // Test for HEAD request (like GET) if (strcasecmp($req_method, 'HEAD') === 0) { // HEAD requests shouldn't return a body $this->response->body(''); if (ob_get_level()) { ob_clean(); } } } catch (LockedResponseException $e) { // Do nothing, since this is an automated behavior } // Run our after dispatch callbacks $this->callAfterDispatchCallbacks(); if ($send_response && !$this->response->isSent()) { $this->response->send(); } }
/** * Cette fonction est lancé par le routeur et permet de lancer l'action qui convient * selon les paramètre recu dans $request * @param \Router\Request $request * @param \Router\Response $response * @return mixed */ public function dispatch(Router\Request $request, Router\Response $response) { $sControllerName = $request->getParam('controller', $this->default['controller']); $sActionName = $request->getParam('action', $this->default['action']); // appel de l'action requise $output = $this->launch($sControllerName, $sActionName, array($request, $response)); // ajout du contenu dans le body de la response $response->appendBody($output); return $output; }