/** * Construct a flat array of method arguments for the resource method. * * @param Route $route The route being processed. * @param ReflectionMethod $method The resource class method that arguments * are needed for. * * @return array */ protected function _getResourceMethodArguments(Route $route, ReflectionMethod $method) { $clsRenderable = 'Sonno\\Application\\Renderable'; $pathParamValues = $this->_uriInfo->getPathParameters(); $queryParamValues = $this->_uriInfo->getQueryParameters(); $headerParamValues = $this->_request->getHeaders(); $pathParams = $route->getPathParams() ?: array(); $queryParams = $route->getQueryParams() ?: array(); $headerParams = $route->getHeaderParams() ?: array(); $formParams = $route->getFormParams() ?: array(); $resourceMethodArgs = array(); parse_str($this->_request->getRequestBody(), $formParamValues); foreach ($method->getParameters() as $idx => $reflParam) { $parameterName = $reflParam->getName(); $parameterClass = $reflParam->getClass(); // if the parameter is a type that implements Renderable, use the // implementation's unrender() function to generate an instance // of the class from the request body as the parameter value if (null !== $parameterClass && $parameterClass->implementsInterface($clsRenderable)) { $parameterClassName = $parameterClass->getName(); $parameterValue = $parameterClassName::unrender($this->_request->getRequestBody(), new Variant(null, null, $this->_request->getContentType())); $resourceMethodArgs[$idx] = $parameterValue; } // search for an argument value in the Path parameter collection if (in_array($parameterName, $pathParams) && isset($pathParamValues[$parameterName])) { $resourceMethodArgs[$idx] = $pathParamValues[$parameterName]; } // search for an argument value in the Query parameter collection if (in_array($parameterName, $queryParams) && isset($queryParamValues[$parameterName])) { $resourceMethodArgs[$idx] = $queryParamValues[$parameterName]; } // search for an argument value in the Header parameter collection if (in_array($parameterName, $headerParams) && isset($headerParamValues[$parameterName])) { $resourceMethodArgs[$idx] = $headerParamValues[$parameterName]; } // search for an argument value in the Form parameter collection if (in_array($parameterName, $formParams) && isset($formParamValues[$parameterName])) { $resourceMethodArgs[$idx] = $formParamValues[$parameterName]; } } return $resourceMethodArgs; }
/** * 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; }
public function testUriInfoInjection() { return $this->_uriInfo->getAbsolutePath(); }