You are here

public function RESTServer::handle in Services 6.3

Same name and namespace in other branches
  1. 7.3 servers/rest_server/includes/RESTServer.inc \RESTServer::handle()

Handles the call to the REST server

Parameters

string $canonical_path:

string $endpoint_path:

Return value

void

File

servers/rest_server/includes/RESTServer.inc, line 18
Class for handling REST calls.

Class

RESTServer
@file Class for handling REST calls.

Code

public function handle($canonical_path, $endpoint_path) {
  $this->endpoint_path = $endpoint_path;
  services_set_server_info('resource_uri_formatter', array(
    &$this,
    'uri_formatter',
  ));

  // Determine the request method
  $method = $_SERVER['REQUEST_METHOD'];
  if ($method == 'POST' && isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) {
    $method = $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'];
  }
  if ($method == 'POST' && (isset($_GET['_method']) && $_GET['_method'])) {
    $method = $_GET['_method'];
  }
  if (isset($_GET['_method'])) {
    unset($_GET['_method']);
  }

  // Extract response format info from the canonical path.
  $matches = array();
  $response_format = '';
  if (preg_match('/^(.+)\\.([^\\.^\\/]+)$/', $canonical_path, $matches)) {
    $canonical_path = $matches[1];
    $response_format = $matches[2];
  }

  // Prepare $path array and $resource_name.
  $path = explode('/', $canonical_path);
  $resource_name = array_shift($path);

  // Response will vary with accept headers
  // if no format was supplied as path suffix
  if (empty($response_format)) {
    drupal_set_header('Vary: Accept');
  }
  $endpoint = services_get_server_info('endpoint', '');
  $endpoint_definition = services_endpoint_load($endpoint);
  $this->endpoint = $endpoint_definition;

  // Get the server settings from the endpoint.
  $this->settings = !empty($endpoint_definition->server_settings['rest_server']) ? $endpoint_definition->server_settings['rest_server'] : array();

  // Normalize the settings so that we get the expected structure
  // and sensible defaults.
  $this->settings = rest_server_setup_settings($this->settings);
  $resources = services_get_resources($endpoint);
  $controller = FALSE;
  if (!empty($resource_name) && isset($resources[$resource_name])) {
    $resource = $resources[$resource_name];

    // Get the operation and fill with default values
    $controller = $this
      ->resolveController($resource, $method, $path);
  }
  else {

    //This will stop the 404 from happening when you request just the endpoint.
    if ($endpoint_definition->path == $resource_name) {
      $response = t('Services Endpoint "@name" has been setup successfully.', array(
        '@name' => $endpoint,
      ));
      drupal_alter('services_endpoint_response', $response);
      return $response;
    }
    return services_error(t('Could not find resource @name.', array(
      '@name' => $resource_name,
    )), 404);
  }
  if (!$controller) {
    return services_error(t('Could not find the controller.'), 404);
  }

  // Parse the request data
  $arguments = $this
    ->getControllerArguments($controller, $path, $method);

  // Any authentication needed for REST Server must be set in the cookies
  $auth_arguments = $_COOKIE;
  $formats = $this
    ->responseFormatters();

  // Negotiate response format based on accept-headers if we
  // don't have a response format
  if (empty($response_format)) {
    $mime_candidates = array();
    $mime_map = array();

    // Add all formatters that accepts raw data, or supports the format model
    foreach ($formats as $format => $formatter) {
      if (!isset($formatter['model']) || $this
        ->supportedControllerModel($controller, $formatter)) {
        foreach ($formatter['mime types'] as $m) {
          $mime_candidates[] = $m;
          $mime_map[$m] = $format;
        }
      }
    }

    // Get the best matching format, default to json
    $response_format = 'json';
    if (isset($_SERVER['HTTP_ACCEPT'])) {
      $mime = $this
        ->mimeParse();
      $mime_type = $mime
        ->best_match($mime_candidates, $_SERVER['HTTP_ACCEPT']);
      $response_format = $mime_map[$mime_type];
    }
  }

  // Check if we support the response format and determine the mime type
  if (empty($mime_type) && isset($formats[$response_format])) {
    $formatter = $formats[$response_format];
    if (!isset($formatter['model']) || $this
      ->supportedControllerModel($controller, $formatter)) {
      $mime_type = $formatter['mime types'][0];
    }
  }
  if (empty($response_format) || empty($mime_type)) {
    return services_error(t('Unknown or unsupported response format.'), 406);
  }

  // Give the model (if any) a opportunity to alter the arguments.
  // This might be needed for the model to ensure that all the required
  // information is requested.
  if (isset($formatter['model'])) {
    $cm =& $controller['models'][$formatter['model']];
    if (!isset($cm['arguments'])) {
      $cm['arguments'] = array();
    }

    // Check if any of the model arguments have been overridden
    if (isset($cm['allow_overrides'])) {
      foreach ($cm['allow_overrides'] as $arg) {
        if (isset($_GET[$formatter['model'] . ':' . $arg])) {
          $cm['arguments'][$arg] = $_GET[$formatter['model'] . ':' . $arg];
        }
      }
    }
    if (isset($cm['class']) && class_exists($cm['class'])) {
      if (method_exists($cm['class'], 'alterArguments')) {
        call_user_func_array($cm['class'] . '::alterArguments', array(
          &$arguments,
          $cm['arguments'],
        ));
      }
    }
  }
  try {
    $result = services_controller_execute($controller, $arguments);
  } catch (ServicesException $e) {
    $errors = $this
      ->handleException($e);
    drupal_alter('rest_server_execute_errors', $errors, $controller, $arguments);
    $result = $errors;
  }
  $formatter = $formats[$response_format];

  // Set the content type and render output
  drupal_set_header('Content-type: ' . $mime_type);
  return $this
    ->renderFormatterView($controller, $formatter, $result);
}