Location: PHPKode > projects > ArangoDB-PHP > ArangoDB-PHP-1.0.1/lib/triagens/ArangoDb/Connection.php
<?php

/**
 * ArangoDB PHP client: connection
 * 
 * @package ArangoDbPhpClient
 * @author Jan Steemann
 * @copyright Copyright 2012, triagens GmbH, Cologne, Germany
 */

namespace triagens\ArangoDb;

/**
 * Provides access to the ArangoDB server
 * As all access is done using HTTP, we do not need to establish a
 * persistent connection and keep its state.
 * Instead, connections are established on the fly for each request
 * and are destroyed afterwards.
 *
 * @package ArangoDbPhpClient
 */
class Connection {
  /**
   * Api Version
   * 
   * @var string
   */
  public static  $_apiVersion = '1.0.1';

  /**
   * Connection options
   * 
   * @var array 
   */
  private $_options;
  
  /**
   * Connection handle, used in case of keep-alive
   * 
   * @var resource
   */
  private $_handle;

  /**
   * Flag if keep-alive connections are used
   * 
   * @var bool
   */
  private $_useKeepAlive;

  /**
   * Set up the connection object, validate the options provided
   *
   * @throws Exception
   * @param array $options - initial connection options
   * @return void
   */
  public function __construct(array $options) {
    $this->_options = new ConnectionOptions($options);
    $this->_useKeepAlive = ($this->_options[ConnectionOptions::OPTION_CONNECTION] === 'Keep-Alive');
  }

  /**
   * Close existing connection handle if a keep-alive connection was used
   *
   * @return void
   */
  public function __destruct() {
    if ($this->_useKeepAlive && is_resource($this->_handle)) {
      @fclose($this->_handle);
    }
  }

  /**
   * Get an option set for the connection
   *
   * @throws ClientException
   * @param string name - name of option
   * @return mixed
   */
  public function getOption($name) {
    assert(is_string($name));

    return $this->_options[$name];
  }
  
  /**
   * Issue an HTTP GET request
   *
   * @throws Exception
   * @param string $url - GET URL
   * @return HttpResponse
   */
  public function get($url) {
    $response = $this->executeRequest(HttpHelper::METHOD_GET, $url, '');
    return $this->parseResponse($response);
  }
  
  /**
   * Issue an HTTP POST request with the data provided
   *
   * @throws Exception
   * @param string $url - POST URL
   * @param string $data - body to post
   * @return HttpResponse
   */
  public function post($url, $data) {
    $response = $this->executeRequest(HttpHelper::METHOD_POST, $url, $data);
    return $this->parseResponse($response);
  }

  /**
   * Issue an HTTP PUT request with the data provided
   *
   * @throws Exception
   * @param string $url - PUT URL
   * @param string $data - body to post
   * @return HttpResponse
   */
  public function put($url, $data) {
    $response = $this->executeRequest(HttpHelper::METHOD_PUT, $url, $data);
    return $this->parseResponse($response);
  }
  
  /**
   * Issue an HTTP PATCH request with the data provided
   *
   * @throws Exception
   * @param string $url - PATCH URL
   * @param string $data - patch body
   * @return HttpResponse
   */
  public function patch($url, $data) {
    $response = $this->executeRequest(HttpHelper::METHOD_PATCH, $url, $data);
    return $this->parseResponse($response);
  }
  
  /**
   * Issue an HTTP DELETE request with the data provided
   *
   * @throws Exception
   * @param string $url - DELETE URL
   * @return HttpResponse
   */
  public function delete($url) {
    $response = $this->executeRequest(HttpHelper::METHOD_DELETE, $url, '');
    return $this->parseResponse($response);
  }


  /**
   * Get a connection handle
   * 
   * If keep-alive connections are used, the handle will be stored and re-used
   *
   * @return resource - connection handle
   */
  private function getHandle() {
    if ($this->_useKeepAlive && $this->_handle && is_resource($this->_handle)) {
      // keep-alive and handle was created already
      $handle = $this->_handle;

      // check if connection is still valid
      if (!feof($handle)) {
        // connection still valid
        return $handle;
      }
      
      // close handle
      @fclose($this->_handle);
      $this->_handle = 0;

      if (!$this->_options[ConnectionOptions::OPTION_RECONNECT]) {
        // if reconnect option not set, this is the end
        throw new ClientException('Server has closed the connection already.');
      }
    }

    // no keep-alive or no handle available yet or a reconnect
    $handle = HttpHelper::createConnection($this->_options);

    if ($this->_useKeepAlive && is_resource($handle)) {
      $this->_handle = $handle; 
    }

    return $handle;
  }

  /**
   * Parse the response return the body values as an assoc array
   *
   * @throws Exception
   * @param HttpResponse $response - the response as supplied by the server
   * @return HttpResponse
   */
  private function parseResponse(HttpResponse $response) {
    $httpCode = $response->getHttpCode();

    if ($httpCode < 200 || $httpCode >= 400) {
      // failure on server
      $details = array();

      $body = $response->getBody();
      if ($body != '') {
        // check if we can find details in the response body
        $details = json_decode($body, true);
        if (is_array($details)) {
          // yes, we got details
          $exception = new ServerException($response->getResult(), $httpCode);
          $exception->setDetails($details);
          throw $exception;
        }
      }

      // no details found, throw normal exception
      throw new ServerException($response->getResult(), $httpCode);
    }

    return $response;
  }
  
  /**
   * Execute an HTTP request and return the results
   * 
   * This function will throw if no connection to the server can be established or if
   * there is a problem during data exchange with the server.
   * 
   * The function might temporarily alter the value of the php.ini value 'default_socket_timeout' but
   * will restore it.
   *
   * @throws Exception
   * @param string $method - HTTP request method
   * @param string $url - HTTP URL
   * @param string $data - data to post in body
   * @return HttpResponse
   */
  private function executeRequest($method, $url, $data) {
    HttpHelper::validateMethod($method);

    // create request data
    $request = HttpHelper::buildRequest($this->_options, $method, $url, $data);
    
    $traceFunc = $this->_options[ConnectionOptions::OPTION_TRACE];
    if ($traceFunc) {
      // call tracer func
      $traceFunc('send', $request);
    }

    // set socket timeout for this scope 
    $getFunc = function() {
      return ini_get('default_socket_timeout');
    };
    $setFunc = function($value) {
      ini_set('default_socket_timeout', $value);
    };

    $scope = new Scope($getFunc, $setFunc);
    $setFunc($this->_options[ConnectionOptions::OPTION_TIMEOUT]);

    // open the socket. note: this might throw if the connection cannot be established
    $handle = $this->getHandle();
    if ($handle) {
      // send data and get response back
      $result = HttpHelper::transfer($handle, $request);

      if (!$this->_useKeepAlive) {
        // must close the connection
        fclose($handle);
      }

      $scope->leave();
      
      if ($traceFunc) {
        // call tracer func
        $traceFunc('receive',$result);
      }

      return new HttpResponse($result);
    } 

    $scope->leave();
    throw new ClientException('Whoops, this should never happen');
  }

    /**
     * Get the client api version
     *
     * @return string
     */
    public static function getVersion() {
        return self::$_apiVersion;
    }
}
Return current item: ArangoDB-PHP