/** * Process an incoming request. * Determine the appropriate route for the request using a Router, and then * execute the resource method to obtain and return a result. * * @param \Sonno\Http\Request\RequestInterface $request The incoming request * @throws MalformedResourceRepresentationException * @throws \Sonno\Http\Exception\NotAcceptableException * @return \Sonno\Http\Response\Response */ public function run(RequestInterface $request) { $selectedVariant = $result = null; try { // attempt to find routes that match the current request $router = new Router($this->_config); $routes = $router->match($request, $pathParams); // construct a hash map of Variants based on Routes $variantMap = array(); // variant hash => <Sonno\Http\Variant> $variants = array(); // array<Sonno\Http\Variant> /** @var $route \Sonno\Configuration\Route */ foreach ($routes as $route) { $routeProduces = $route->getProduces(); foreach ($routeProduces as $produces) { $variant = new Variant(null, null, $produces); $variantHash = spl_object_hash($variant); $variantMap[$variantHash] = $route; $variants[] = $variant; } } // select a Variant and find the corresponding route $selectedVariant = $request->selectVariant($variants); if (null == $selectedVariant) { throw new NotAcceptableException(); } $selectedVariantHash = spl_object_hash($selectedVariant); $selectedRoute = $variantMap[$selectedVariantHash]; // maintain URI information for resource class context injection $uriInfo = new UriInfo($this->_config, $request, $selectedRoute); $uriInfo->setPathParameters($pathParams); $uriInfo->setQueryParameters($request->getQueryParams()); // execute the resource class method and obtain the result $dispatcher = $this->getDispatcher(); $dispatcher->setRequest($request); $dispatcher->setUriInfo($uriInfo); $result = $dispatcher->dispatch($selectedRoute); } catch (MethodNotAllowedException $e) { // rewrite the response as a 200 OK when the request is OPTIONS if ('OPTIONS' == $request->getMethod()) { $e->getResponse()->setStatusCode(200); } $result = $e->getResponse(); } catch (WebApplicationException $e) { $result = $e->getResponse(); } // object is a scalar value: construct a new Response if (is_scalar($result)) { $response = new Response(200, $result); // object is already a Response } else { if ($result instanceof Response) { $response = $result; // object implements the Renderable interface: construct a Response // using the representation produced by render() } else { if ($result instanceof Renderable) { $response = new Response(200, $result->render($selectedVariant)); // cannot determine how to handle the object returned } else { throw new MalformedResourceRepresentationException(); } } } // ensure a Content-Type header is present if (!$response->hasHeader('Content-Type') && $response->getStatusCode() < 300 && $response->getContent()) { $response->setHeaders(array('Content-Type' => $selectedVariant->getMediaType())); } // ensure a Content-Length header is present if (!$response->hasHeader('Content-Length')) { $response->setHeaders(array('Content-Length' => strlen($response->getContent()))); } // process any HTTP status filter callbacks $statusCode = $response->getStatusCode(); if (isset($this->_responseFilters[$statusCode])) { foreach ($this->_responseFilters[$statusCode] as $filterCallback) { $filterCallback($request, $response); } } $response->sendResponse(); return $response; }
/** * Test matching two paths that match, with a RegExp-constrained Path * parameter, but fail because the parameter value doesn't match the * regular expression. * * @return void * @expectedException \Sonno\Http\Exception\NotFoundException */ public function testFailedPathMatchWithConstrainedParameters() { $route = $this->getMockBuilder('Sonno\\Configuration\\Route')->disableOriginalConstructor()->getMock(); $route->expects($this->any())->method('getPath')->will($this->returnValue('/users/{id: \\d+}')); $config = $this->getMockBuilder('Sonno\\Configuration\\Configuration')->disableOriginalConstructor()->getMock(); $config->expects($this->any())->method('getRoutes')->will($this->returnValue(array($route))); $request = $this->buildMockRequest('GET', '/users/abc'); $router = new Router($config); $router->match($request, $params); }