summaryrefslogtreecommitdiff
path: root/lib/prado/framework/Util/TRpcClient.php
diff options
context:
space:
mode:
Diffstat (limited to 'lib/prado/framework/Util/TRpcClient.php')
-rw-r--r--lib/prado/framework/Util/TRpcClient.php357
1 files changed, 357 insertions, 0 deletions
diff --git a/lib/prado/framework/Util/TRpcClient.php b/lib/prado/framework/Util/TRpcClient.php
new file mode 100644
index 0000000..c8920a2
--- /dev/null
+++ b/lib/prado/framework/Util/TRpcClient.php
@@ -0,0 +1,357 @@
+<?php
+
+/**
+ * @author Robin J. Rogge <rrogge@bigpoint.net>
+ * @link https://github.com/pradosoft/prado
+ * @copyright 2010 Bigpoint GmbH
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @since 3.2
+ * @package System.Util
+ */
+
+/**
+ * TRpcClient class
+ *
+ * Note: When using setIsNotification(true), *every* following request is also
+ * considered to be a notification until you use setIsNotification(false).
+ *
+ * Usage:
+ *
+ * First, you can use the factory:
+ * <pre>
+ * $_rpcClient = TRpcClient::create('xml', 'http://host/server');
+ * $_result = $_rpcClient->remoteMethodName($param, $otherParam);
+ * </pre>
+ *
+ * or as oneliner:
+ * <pre>
+ * $_result = TRpcClient::create('json', 'http://host/server')->remoteMethod($param, ...);
+ * </pre>
+ *
+ * Second, you can also use the specific implementation directly:
+ * <pre>
+ * $_rpcClient = new TXmlRpcClient('http://host/server');
+ * $_result = $_rpcClient->remoteMethod($param, ...);
+ * </pre>
+ *
+ * or as oneliner:
+ * <pre>
+ * $_result = TXmlRpcClient('http://host/server')->hello();
+ * </pre>
+ *
+ * @author Robin J. Rogge <rrogge@bigpoint.net>
+ * @version $Id$
+ * @package System.Util
+ * @since 3.2
+ */
+
+class TRpcClient extends TApplicationComponent
+{
+ /**
+ * @var string url of the RPC server
+ */
+ private $_serverUrl;
+
+ /**
+ * @var boolean whether the request is a notification and therefore should not care about the result (default: false)
+ */
+ private $_isNotification = false;
+
+ // magics
+
+ /**
+ * @param string url to RPC server
+ * @param boolean whether requests are considered to be notifications (completely ignoring the response) (default: false)
+ */
+ public function __construct($serverUrl, $isNotification = false)
+ {
+ $this->_serverUrl = $serverUrl;
+ $this->_isNotification = TPropertyValue::ensureBoolean($isNotification);
+ }
+
+ // methods
+
+ /**
+ * Creates an instance of the requested RPC client type
+ * @return TRpcClient instance
+ * @throws TApplicationException if an unsupported RPC client type was specified
+ */
+ public static function create($type, $serverUrl, $isNotification = false)
+ {
+ if(($_handler = constant('TRpcClientTypesEnumerable::'.strtoupper($type))) === null)
+ throw new TApplicationException('rpcclient_unsupported_handler');
+
+ return new $_handler($serverUrl, $isNotification);
+ }
+
+ /**
+ * Creates a stream context resource
+ * @param mixed $content
+ * @param string $contentType mime type
+ */
+ protected function createStreamContext($content, $contentType)
+ {
+ return stream_context_create(array(
+ 'http' => array(
+ 'method' => 'POST',
+ 'header' => "Content-Type: {$contentType}",
+ 'content' => $content
+ )
+ ));
+ }
+
+ /**
+ * Performs the actual request
+ * @param string RPC server URL
+ * @param array payload data
+ * @param string request mime type
+ */
+ protected function performRequest($serverUrl, $payload, $mimeType)
+ {
+ if(($_response = @file_get_contents($serverUrl, false, $this->createStreamContext($payload, $mimeType))) === false)
+ throw new TRpcClientRequestException('Request failed ("'.$http_response_header[0].'")');
+
+ return $_response;
+ }
+
+ // getter/setter
+
+ /**
+ * @return boolean whether requests are considered to be notifications (completely ignoring the response)
+ */
+ public function getIsNotification()
+ {
+ return $this->_isNotification;
+ }
+
+ /**
+ * @param string boolean whether the requests are considered to be notifications (completely ignoring the response) (default: false)
+ */
+ public function setIsNotification($bool)
+ {
+ $this->_isNotification = TPropertyValue::ensureBoolean($bool);
+ }
+
+ /**
+ * @return string url of the RPC server
+ */
+ public function getServerUrl()
+ {
+ return $this->_serverUrl;
+ }
+
+ /**
+ * @param string url of the RPC server
+ */
+ public function setServerUrl($value)
+ {
+ $this->_serverUrl = $value;
+ }
+}
+
+/**
+ * TRpcClientTypesEnumerable class
+ *
+ * @author Robin J. Rogge <rrogge@bigpoint.net>
+ * @version $Id$
+ * @package System.Util
+ * @since 3.2
+ */
+
+class TRpcClientTypesEnumerable extends TEnumerable
+{
+ const JSON = 'TJsonRpcClient';
+ const XML = 'TXmlRpcClient';
+}
+
+/**
+ * TRpcClientRequestException class
+ *
+ * This Exception is fired if the RPC request fails because of transport problems e.g. when
+ * there is no RPC server responding on the given remote host.
+ *
+ * @author Robin J. Rogge <rrogge@bigpoint.net>
+ * @version $Id$
+ * @package System.Util
+ * @since 3.2
+ */
+
+class TRpcClientRequestException extends TApplicationException
+{
+}
+
+/**
+ * TRpcClientResponseException class
+ *
+ * This Exception is fired when the
+ *
+ * @author Robin J. Rogge <rrogge@bigpoint.net>
+ * @version $Id$
+ * @package System.Util
+ * @since 3.2
+ */
+
+class TRpcClientResponseException extends TApplicationException
+{
+ /**
+ * @param string error message
+ * @param integer error code (optional)
+ */
+ public function __construct($errorMessage, $errorCode = null)
+ {
+ $this->setErrorCode($errorCode);
+
+ parent::__construct($errorMessage);
+ }
+}
+
+/**
+ * TJsonRpcClient class
+ *
+ * Note: When using setIsNotification(true), *every* following request is also
+ * considered to be a notification until you use setIsNotification(false).
+ *
+ * Usage:
+ * <pre>
+ * $_rpcClient = new TJsonRpcClient('http://host/server');
+ * $_result = $_rpcClient->remoteMethod($param, $otherParam);
+ * // or
+ * $_result = TJsonRpcClient::create('http://host/server')->remoteMethod($param, $otherParam);
+ * </pre>
+ *
+ * @author Robin J. Rogge <rrogge@bigpoint.net>
+ * @version $Id$
+ * @package System.Util
+ * @since 3.2
+ */
+
+class TJsonRpcClient extends TRpcClient
+{
+ // magics
+
+ /**
+ * @param string RPC method name
+ * @param array RPC method parameters
+ * @return mixed RPC request result
+ * @throws TRpcClientRequestException if the client fails to connect to the server
+ * @throws TRpcClientResponseException if the response represents an RPC fault
+ */
+ public function __call($method, $parameters)
+ {
+ // send request
+ $_response = $this->performRequest($this->getServerUrl(), $this->encodeRequest($method, $parameters), 'application/json');
+
+ // skip response handling if the request was just a notification request
+ if($this->isNotification)
+ return true;
+
+ // decode response
+ if(($_response = json_decode($_response, true)) === null)
+ throw new TRpcClientResponseException('Empty response received');
+
+ // handle error response
+ if(!is_null($_response['error']))
+ throw new TRpcClientResponseException($_response['error']);
+
+ return $_response['result'];
+ }
+
+ // methods
+
+ /**
+ * @param string method name
+ * @param array method parameters
+ */
+ public function encodeRequest($method, $parameters)
+ {
+ static $_requestId;
+ $_requestId = ($_requestId === null) ? 1 : $_requestId + 1;
+
+ return json_encode(array(
+ 'method' => $method,
+ 'params' => $parameters,
+ 'id' => $this->isNotification ? null : $_requestId
+ ));
+ }
+
+ /**
+ * Creates an instance of TJsonRpcClient
+ * @param string url of the rpc server
+ * @param boolean whether the requests are considered to be notifications (completely ignoring the response) (default: false)
+ */
+ public static function create($type, $serverUrl, $isNotification = false)
+ {
+ return new self($serverUrl, $isNotification);
+ }
+}
+
+/**
+ * TXmlRpcClient class
+ *
+ * Note: When using setIsNotification(true), *every* following request is also
+ * considered to be a notification until you use setIsNotification(false).
+ *
+ * Usage:
+ * <pre>
+ * $_rpcClient = new TXmlRpcClient('http://remotehost/rpcserver');
+ * $_rpcClient->remoteMethod($param, $otherParam);
+ * </pre>
+ *
+ * @author Robin J. Rogge <rrogge@bigpoint.net>
+ * @version $Id$
+ * @package System.Util
+ * @since 3.2
+ */
+
+class TXmlRpcClient extends TRpcClient
+{
+ // magics
+
+ /**
+ * @param string RPC method name
+ * @param array RPC method parameters
+ * @return mixed RPC request result
+ * @throws TRpcClientRequestException if the client fails to connect to the server
+ * @throws TRpcClientResponseException if the response represents an RPC fault
+ */
+ public function __call($method, $parameters)
+ {
+ // send request
+ $_response = $this->performRequest($this->getServerUrl(), $this->encodeRequest($method, $parameters), 'text/xml');
+
+ // skip response handling if the request was just a notification request
+ if($this->isNotification)
+ return true;
+
+ // decode response
+ if(($_response = xmlrpc_decode($_response)) === null)
+ throw new TRpcClientResponseException('Empty response received');
+
+ // handle error response
+ if(xmlrpc_is_fault($_response))
+ throw new TRpcClientResponseException($_response['faultString'], $_response['faultCode']);
+
+ return $_response;
+ }
+
+ // methods
+
+ /**
+ * @param string method name
+ * @param array method parameters
+ */
+ public function encodeRequest($method, $parameters)
+ {
+ return xmlrpc_encode_request($method, $parameters);
+ }
+
+ /**
+ * Creates an instance of TXmlRpcClient
+ * @param string url of the rpc server
+ * @param boolean whether the requests are considered to be notifications (completely ignoring the response) (default: false)
+ */
+ public static function create($type, $serverUrl, $isNotification = false)
+ {
+ return new self($serverUrl, $isNotification);
+ }
+}