Skip to content

Commit

Permalink
Merge branch 'feature/remote-object-merge-cleanups' - fixes #92
Browse files Browse the repository at this point in the history
  • Loading branch information
Ocramius committed Oct 20, 2013
2 parents bc77a58 + b19315a commit 9fa5bde
Show file tree
Hide file tree
Showing 44 changed files with 2,200 additions and 12 deletions.
23 changes: 22 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,28 @@ This feature [yet to be planned](https://github.com/Ocramius/ProxyManager/issues
A remote object proxy is an object that is located on a different system, but is used as if it was available locally.
There's various possible remote proxy implementations, which could be based on xmlrpc/jsonrpc/soap/dnode/etc.

This feature [yet to be planned](https://github.com/Ocramius/ProxyManager/issues/7).
This example uses the XML-RPC client of Zend Framework 2:

```php
interface FooServiceInterface
{
public function foo();
}

$factory = new \ProxyManager\Factory\RemoteObjectFactory(
new \ProxyManager\Factory\RemoteObject\Adapter\XmlRpc(
new \Zend\XmlRpc\Client('https://example.com/rpc-endpoint')
)
);

// proxy is your remote implementation
$proxy = $factory->createProxy('FooServiceInterface');

var_dump($proxy->foo());
```

See the [complete documentation about remote objects](https://github.com/Ocramius/ProxyManager/tree/master/docs/remote-object.md)
in the `docs/` directory.

## Contributing

Expand Down
5 changes: 4 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@
},
"suggest": {
"zendframework/zend-stdlib": "To use the hydrator proxy",
"ocramius/generated-hydrator": "To have very fast object to array to object conversion for ghost objects"
"ocramius/generated-hydrator": "To have very fast object to array to object conversion for ghost objects",
"zendframework/zend-xmlrpc": "To have the XmlRpc adapter (Remote Object feature)",
"zendframework/zend-json": "To have the JsonRpc adapter (Remote Object feature)",
"zendframework/zend-soap": "To have the Soap adapter (Remote Object feature)"
},
"autoload": {
"psr-0": {
Expand Down
113 changes: 113 additions & 0 deletions docs/remote-object.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Remote Object Proxy

The remote object implementation is a mechanism that enables an local object to control an other object on an other server.
Each call method on the local object will do a network call to get information or execute operations on the remote object.

## What is remote object proxy ?

A remote object is based on an interface. The remote interface defines the API that a consumer can call. This interface
must be implemented both by the client and the RPC server.

## Adapters

ZendFramework's RPC components (XmlRpc, JsonRpc & Soap) can be used easily with the remote object.
You will need to require the one you need via composer, though:

```sh
$ php composer.phar require zendframework/zend-xmlrpc:2.*
$ php composer.phar require zendframework/zend-json:2.*
$ php composer.phar require zendframework/zend-soap:2.*
```

ProxyManager comes with 3 adapters:

* `ProxyManager\Factory\RemoteObject\Adapter\XmlRpc`
* `ProxyManager\Factory\RemoteObject\Adapter\JsonRpc`
* `ProxyManager\Factory\RemoteObject\Adapter\Soap`

## Usage examples

RPC server side code (`xmlrpc.php` in your local webroot):

```php
interface FooServiceInterface
{
public function foo();
}

class Foo implements FooServiceInterface
{
/**
* Foo function
* @return string
*/
public function foo()
{
return 'bar remote';
}
}

$server = new Zend\XmlRpc\Server();
$server->setClass('Foo', 'FooServiceInterface'); // my FooServiceInterface implementation
$server->handle();
```

Client side code (proxy) :

```php

interface FooServiceInterface
{
public function foo();
}

class XmlRpcAdapter implements AdapterInterface
{
public function __construct($webservice)
{
$this->webservice = $webservice;
}

public function call($wrappedClass, $method, array $params = array())
{
$serviceName = wrappedClass . '.' . method;
$client = new \Zend\XmlRpc\Client($this->webservice);
return $client->call($serviceName, $params);
}
}

$factory = new \ProxyManager\Factory\RemoteObjectFactory(
new \ProxyManager\Factory\RemoteObject\Adapter\XmlRpc(
new \Zend\XmlRpc\Client('https://localhost/xmlrpc.php')
)
);

$proxy = $factory->createProxy('FooServiceInterface', $adapter);

var_dump($proxy->foo()); // "bar remote"
```

## Implementing custom adapters

Your adapters must implement `ProxyManager\Factory\RemoteObject\AdapterInterface` :

```php
interface AdapterInterface
{
/**
* Call remote object
*
* @param string $wrappedClass
* @param string $method
* @param array $params
*/
public function call($wrappedClass, $method, array $params = array());
}
```

It is very easy to create your own implementation (for RESTful web services, for example). Simply pass
your own adapter instance to your factory at construction time

## Tuning performance for production

See [Tuning ProxyManager for Production](https://github.com/Ocramius/ProxyManager/blob/master/docs/tuning-for-production.md).
36 changes: 36 additions & 0 deletions examples/remote-proxy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

require_once __DIR__ . '/../vendor/autoload.php';

use ProxyManager\Factory\RemoteObject\Adapter\XmlRpc;
use ProxyManager\Factory\RemoteObjectFactory;
use Zend\XmlRpc\Client;

if (! class_exists('Zend\XmlRpc\Client')) {
echo "This example needs Zend\\XmlRpc\\Client to run. \n In order to install it, "
. "please run following:\n\n"
. "\$ php composer.phar require zendframework/zend-xmlrpc:2.*\n\n";

exit(2);
}

class Foo
{
public function bar()
{
return 'bar local!';
}
}

$factory = new RemoteObjectFactory(
new XmlRpc(new Client('http://localhost:9876/remote-proxy/remote-proxy-server.php'))
);
$proxy = $factory->createProxy('Foo');

try {
var_dump($proxy->bar()); // bar remote !
} catch (\Zend\Http\Client\Adapter\Exception\RuntimeException $error) {
echo "To run this example, please following before:\n\n\$ php -S localhost:9876 -t \"" . __DIR__ . "\"\n";

exit(2);
}
20 changes: 20 additions & 0 deletions examples/remote-proxy/remote-proxy-server.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

use Zend\XmlRpc\Server;

require_once __DIR__ . '/../../vendor/autoload.php';

class Foo
{
public function bar()
{
return 'bar remote!';
}
}

$server = new Server();

$server->setClass(new Foo(), 'Foo');
$server->setReturnResponse(false);

$server->handle();
3 changes: 1 addition & 2 deletions src/ProxyManager/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,9 @@ class Configuration
protected $classNameInflector;

/**
* @param bool $autoGenerateProxies
* @deprecated deprecated since version 0.5
*/
public function setAutoGenerateProxies($autoGenerateProxies)
public function setAutoGenerateProxies()
{
}

Expand Down
2 changes: 0 additions & 2 deletions src/ProxyManager/Factory/AbstractLazyFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@

namespace ProxyManager\Factory;

use ProxyManager\Generator\ClassGenerator;
use ReflectionClass;
use Closure;

/**
Expand Down
3 changes: 2 additions & 1 deletion src/ProxyManager/Factory/LazyLoadingGhostFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

namespace ProxyManager\Factory;

use ProxyManager\Proxy\GhostObjectInterface;
use ProxyManager\ProxyGenerator\LazyLoadingGhostGenerator;

/**
Expand All @@ -26,7 +27,7 @@
* @author Marco Pivetta <[email protected]>
* @license MIT
*
* @method \ProxyManager\Proxy\GhostObjectInterface createProxy($className, \Closure $initializer)
* @method GhostObjectInterface createProxy($className, \Closure $initializer)
*/
class LazyLoadingGhostFactory extends AbstractLazyFactory
{
Expand Down
3 changes: 2 additions & 1 deletion src/ProxyManager/Factory/LazyLoadingValueHolderFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

namespace ProxyManager\Factory;

use ProxyManager\Proxy\VirtualProxyInterface;
use ProxyManager\ProxyGenerator\LazyLoadingValueHolderGenerator;

/**
Expand All @@ -26,7 +27,7 @@
* @author Marco Pivetta <[email protected]>
* @license MIT
*
* @method \ProxyManager\Proxy\VirtualProxyInterface createProxy($className, \Closure $initializer)
* @method VirtualProxyInterface createProxy($className, \Closure $initializer)
*/
class LazyLoadingValueHolderFactory extends AbstractLazyFactory
{
Expand Down
81 changes: 81 additions & 0 deletions src/ProxyManager/Factory/RemoteObject/Adapter/BaseAdapter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license.
*/

namespace ProxyManager\Factory\RemoteObject\Adapter;

use ProxyManager\Factory\RemoteObject\AdapterInterface;
use Zend\Server\Client;

/**
* Remote Object base adapter
*
* @author Vincent Blanchon <[email protected]>
* @license MIT
*/
abstract class BaseAdapter implements AdapterInterface
{
/**
* Adapter client
*
* @var \Zend\Server\Client
*/
protected $client;

/**
* Service name mapping
*
* @var string[]
*/
protected $map = array();

/**
* Constructor
*
* @param Client $client
* @param array $map map of service names to their aliases
*/
public function __construct(Client $client, array $map = array())
{
$this->client = $client;
$this->map = $map;
}

/**
* {@inheritDoc}
*/
public function call($wrappedClass, $method, array $params = array())
{
$serviceName = $this->getServiceName($wrappedClass, $method);

if (isset($this->map[$serviceName])) {
$serviceName = $this->map[$serviceName];
}

return $this->client->call($serviceName, $params);
}

/**
* Get the service name will be used by the adapter
*
* @param string $wrappedClass
* @param string $method
*
* @return string Service name
*/
abstract protected function getServiceName($wrappedClass, $method);
}
36 changes: 36 additions & 0 deletions src/ProxyManager/Factory/RemoteObject/Adapter/JsonRpc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license.
*/

namespace ProxyManager\Factory\RemoteObject\Adapter;

/**
* Remote Object JSON RPC adapter
*
* @author Vincent Blanchon <[email protected]>
* @license MIT
*/
class JsonRpc extends BaseAdapter
{
/**
* {@inheritDoc}
*/
protected function getServiceName($wrappedClass, $method)
{
return $wrappedClass . '.' . $method;
}
}
Loading

0 comments on commit 9fa5bde

Please sign in to comment.