Skip to content

Commit

Permalink
[Internal BWC Break] Add better ability to inject namespaces
Browse files Browse the repository at this point in the history
Adds a new `registerNamespace` method to the client builder, and supporting infrastructure
to use newly registered namespaces in the client.  It was previously possible to do this
via the `setEndpoint()` method... but it was very difficult and not pleasant to use.

Now, users can implement the `NamespaceBuilderInterface` interface, which is registered into
the client build and used to instantiate user-defined namespaces when the client is built.
Those namespaces are then automatically used by the client as if they were built-in.

Note: namespaces cannot conflict with existing namespaces (if they do, they will never be called
since this uses the __call dynamic method, which will defer to explicit method names first).
Also note that two registered namespaces with the same name will results in a
last-register-wins situation (e.g. they are stored in a map), so avoid conflicts :)
  • Loading branch information
polyfractal committed Jul 7, 2016
1 parent ecd454c commit b1a27b7
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 5 deletions.
25 changes: 24 additions & 1 deletion src/Elasticsearch/Client.php
Expand Up @@ -2,6 +2,7 @@

namespace Elasticsearch;

use Elasticsearch\Common\Exceptions\BadMethodCallException;
use Elasticsearch\Common\Exceptions\InvalidArgumentException;
use Elasticsearch\Common\Exceptions\Missing404Exception;
use Elasticsearch\Common\Exceptions\TransportException;
Expand All @@ -10,6 +11,7 @@
use Elasticsearch\Namespaces\ClusterNamespace;
use Elasticsearch\Namespaces\IndicesNamespace;
use Elasticsearch\Namespaces\IngestNamespace;
use Elasticsearch\Namespaces\NamespaceBuilderInterface;
use Elasticsearch\Namespaces\NodesNamespace;
use Elasticsearch\Namespaces\SnapshotNamespace;
use Elasticsearch\Namespaces\BooleanRequestWrapper;
Expand Down Expand Up @@ -74,13 +76,17 @@ class Client
/** @var callback */
protected $endpoints;

/** @var NamespaceBuilderInterface[] */
protected $registeredNamespaces = [];

/**
* Client constructor
*
* @param Transport $transport
* @param callable $endpoint
* @param AbstractNamespace[] $registeredNamespaces
*/
public function __construct(Transport $transport, callable $endpoint)
public function __construct(Transport $transport, callable $endpoint, array $registeredNamespaces)
{
$this->transport = $transport;
$this->endpoints = $endpoint;
Expand All @@ -91,6 +97,7 @@ public function __construct(Transport $transport, callable $endpoint)
$this->cat = new CatNamespace($transport, $endpoint);
$this->ingest = new IngestNamespace($transport, $endpoint);
$this->tasks = new TasksNamespace($transport, $endpoint);
$this->registeredNamespaces = $registeredNamespaces;
}

/**
Expand Down Expand Up @@ -1298,6 +1305,22 @@ public function tasks()
return $this->tasks;
}

/**
* Catchall for registered namespaces
*
* @param $name
* @param $arguments
* @return Object
* @throws BadMethodCallException if the namespace cannot be found
*/
public function __call($name, $arguments)
{
if (isset($this->registeredNamespaces[$name])) {
return $this->registeredNamespaces[$name];
}
throw new BadMethodCallException("Namespace [$name] not found");
}

/**
* @param array $params
* @param string $arg
Expand Down
29 changes: 25 additions & 4 deletions src/Elasticsearch/ClientBuilder.php
Expand Up @@ -10,6 +10,7 @@
use Elasticsearch\Connections\Connection;
use Elasticsearch\Connections\ConnectionFactory;
use Elasticsearch\Connections\ConnectionFactoryInterface;
use Elasticsearch\Namespaces\NamespaceBuilderInterface;
use Elasticsearch\Serializers\SerializerInterface;
use Elasticsearch\ConnectionPool\Selectors;
use Elasticsearch\Serializers\SmartSerializer;
Expand Down Expand Up @@ -39,6 +40,9 @@ class ClientBuilder
/** @var callback */
private $endpoint;

/** @var NamespaceBuilderInterface[] */
private $registeredNamespacesBuilders = [];

/** @var ConnectionFactoryInterface */
private $connectionFactory;

Expand Down Expand Up @@ -230,6 +234,17 @@ public function setEndpoint($endpoint)
return $this;
}

/**
* @param NamespaceBuilderInterface $namespaceBuilder
* @return $this
*/
public function registerNamespace(NamespaceBuilderInterface $namespaceBuilder)
{
$this->registeredNamespacesBuilders[] = $namespaceBuilder;

return $this;
}

/**
* @param \Elasticsearch\Transport $transport
* @return $this
Expand Down Expand Up @@ -427,7 +442,6 @@ public function build()
$this->buildTransport();

if (is_null($this->endpoint)) {
$transport = $this->transport;
$serializer = $this->serializer;

$this->endpoint = function ($class) use ($serializer) {
Expand All @@ -440,17 +454,24 @@ public function build()
};
}

return $this->instantiate($this->transport, $this->endpoint);
$registeredNamespaces = [];
foreach ($this->registeredNamespacesBuilders as $builder) {
/** @var $builder NamespaceBuilderInterface */
$registeredNamespaces[$builder->getName()] = $builder->getObject($this->transport, $this->serializer);
}

return $this->instantiate($this->transport, $this->endpoint, $registeredNamespaces);
}

/**
* @param Transport $transport
* @param callable $endpoint
* @param Object[] $registeredNamespaces
* @return Client
*/
protected function instantiate(Transport $transport, callable $endpoint)
protected function instantiate(Transport $transport, callable $endpoint, array $registeredNamespaces)
{
return new Client($transport, $endpoint);
return new Client($transport, $endpoint, $registeredNamespaces);
}

private function buildLoggers()
Expand Down
37 changes: 37 additions & 0 deletions src/Elasticsearch/Namespaces/NamespaceBuilderInterface.php
@@ -0,0 +1,37 @@
<?php
/**
* Class RegisteredNamespaceInterface
*
* @category Elasticsearch
* @package Elasticsearch\Namespaces
* @author Zachary Tong <zach@elastic.co>
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache2
* @link http://elastic.co
*/

namespace Elasticsearch\Namespaces;


use Elasticsearch\Serializers\SerializerInterface;
use Elasticsearch\Transport;

interface NamespaceBuilderInterface
{
/**
* Returns the name of the namespace. This is what users will call, e.g. the name
* "foo" will be invoked by the user as `$client->foo()`
* @return string
*/
public function getName();

/**
* Returns the actual namespace object which contains your custom methods. The transport
* and serializer objects are provided so that your namespace may do whatever custom
* logic is required.
*
* @param Transport $transport
* @param SerializerInterface $serializer
* @return Object
*/
public function getObject(Transport $transport, SerializerInterface $serializer);
}
65 changes: 65 additions & 0 deletions tests/Elasticsearch/Tests/RegisteredNamespaceTest.php
@@ -0,0 +1,65 @@
<?php

namespace Elasticsearch\Tests;

use Elasticsearch;
use Elasticsearch\ClientBuilder;
use Elasticsearch\Serializers\SerializerInterface;
use Elasticsearch\Transport;
use Mockery as m;

/**
* Class RegisteredNamespaceTest
*
* @category Tests
* @package Elasticsearch
* @subpackage Tests
* @author Zachary Tong <zachary.tong@elasticsearch.com>
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache2
* @link http://elasticsearch.org
*/
class RegisteredNamespaceTest extends \PHPUnit_Framework_TestCase
{
public function tearDown()
{
m::close();
}

public function testRegisteringNamespace()
{
$builder = new FooNamespaceBuilder();
$client = ClientBuilder::create()->registerNamespace($builder)->build();
$this->assertEquals("123", $client->foo()->fooMethod());
}

/**
* @expectedException \Elasticsearch\Common\Exceptions\BadMethodCallException
*/
public function testNonExistingNamespace()
{
$builder = new FooNamespaceBuilder();
$client = ClientBuilder::create()->registerNamespace($builder)->build();
$this->assertEquals("123", $client->bar()->fooMethod());
}
}

class FooNamespaceBuilder implements Elasticsearch\Namespaces\NamespaceBuilderInterface
{
public function getName()
{
return "foo";
}

public function getObject(Transport $transport, SerializerInterface $serializer)
{
return new FooNamespace();
}
}

class FooNamespace
{
public function fooMethod()
{
return "123";
}
}

0 comments on commit b1a27b7

Please sign in to comment.