private function routeRequest(Request $request, Service $service) { $desired_method = String::underscoreToCamelCase($request->getMethod()); $requested_method = $request->getRequestMethod() . $desired_method; $method = $requested_method; $arguments = $request->getArguments(); if (!method_exists($service, $method)) { $method = $request->getRequestMethod() . 'Router'; if (!method_exists($service, $method)) { throw new MethodNotSupported($request->getService(), $requested_method); } array_splice($arguments, 0, 0, array($request->getMethod())); } $output = call_user_func_array(array($service, $method), $arguments); $this->response->setResponse($output); }
public function handleRequest() { $request = new Request($_SERVER); // OPTIONS is used by cors for the preflight, so it must be accepted if ($request->getMethod() != 'OPTIONS') { // See if service is specified if ($request->getService()) { $service = $this->findService($request); if ($service !== NULL) { $method = $this->findMethod($service, $request); if ($method !== NULL) { // Check for use of annotation @Authenticated if (!$method->requiresAuthentication() || $method->requiresAuthentication() && $this->isAuthenticated()) { // Check for use of annotation @AccessLevel if ($this->getAccessLevel() >= $method->requiredAccessLevel()) { $result = NULL; // Analyze the service method and invoke it "the best way"(tm) $parameters = $method->getParameters(); if (count($parameters) > 0) { $data = $request->getData(); $paramClass = $parameters[0]->getClass(); /* If the method takes a special object, we try to create an * object of this kind and fill it with data from the request * * We don't try to fit anonymous arguments to service * methods that uses classes */ if ($paramClass !== NULL) { $paramClassName = $paramClass->name; $requestObj = new $paramClassName(); $classVars = get_class_vars($paramClassName); // Request ex: {"user":{"name":"a","pass":"******"}} $arrayValues = array_values($data); if (count($data) === 1 && is_array($arrayValues[0])) { $data = array_pop($data); } if (is_array($data)) { $data = array_change_key_case($data); foreach ($classVars as $attr => $defaultVal) { if (isset($data[strtolower($attr)])) { $requestObj->{$attr} = $data[strtolower($attr)]; } } } // Combine object and anonymous data (for subroutes) $input = array_merge(array($requestObj), $request->getAnonymousData()); try { $result = $method->invokeArgs($service, $input); } catch (Exception $e) { $result = $e; } /* If no object, we try to rearrange the request data to * match paramter names in the method */ } else { // Try to make each param come in right order $input = array(); foreach ($parameters as $param) { if (isset($data[strtolower($param->name)])) { $input[] = $data[strtolower($param->name)]; } else { /* Where we don't have arguments available, we put * NULLs so that we can find these holes later and * use anonymous arguments to fill them */ $input[] = NULL; } } // Try to fill in the blanks with unnamed request data $data = $request->getAnonymousData(); foreach ($input as $key => &$inputData) { if ($inputData === NULL) { $anonymous = array_shift($data); if ($anonymous !== NULL) { $inputData = $anonymous; } else { /* We are out of anonymous data to use, but perhaps * the parameter is optional with a default value * and we don't have to send in NULL */ if ($parameters[$key]->isOptional()) { $inputData = $parameters[$key]->getDefaultValue(); } } } } try { $result = $method->invokeArgs($service, $input); } catch (Exception $e) { $result = $e; } } } else { try { $result = $method->invoke($service); } catch (Exception $e) { $result = $e; } } if ($result instanceof Exception) { if ($result instanceof ServiceException) { $this->response->setHttpStatus($result->getCode()); $this->response->setContent($result->getMessage()); } else { $this->response->setHttpStatus(HttpStatus::INTERNAL_SERVER_ERROR); $this->response->setContent($result->getMessage()); } } else { $this->response->setContentType($method->getContentType()); if ($result !== NULL) { $this->response->setContent($result); } } } else { $this->response->setHttpStatus(HttpStatus::METHOD_NOT_ALLOWED); } } else { $this->response->setHttpStatus(HttpStatus::UNAUTHORIZED); } } else { $this->response->setHttpStatus(HttpStatus::NOT_IMPLEMENTED); } } else { $this->response->setHttpStatus(HttpStatus::NOT_FOUND); } } else { $this->response->setContentType('text/html'); $this->response->setContent($this->createIndex()); } } $this->sendResponse(); }