Skip to content

Commit b1a27b7

Browse files
committed
[Internal BWC Break] Add better ability to inject namespaces
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 :)
1 parent ecd454c commit b1a27b7

File tree

4 files changed

+151
-5
lines changed

4 files changed

+151
-5
lines changed

src/Elasticsearch/Client.php

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Elasticsearch;
44

5+
use Elasticsearch\Common\Exceptions\BadMethodCallException;
56
use Elasticsearch\Common\Exceptions\InvalidArgumentException;
67
use Elasticsearch\Common\Exceptions\Missing404Exception;
78
use Elasticsearch\Common\Exceptions\TransportException;
@@ -10,6 +11,7 @@
1011
use Elasticsearch\Namespaces\ClusterNamespace;
1112
use Elasticsearch\Namespaces\IndicesNamespace;
1213
use Elasticsearch\Namespaces\IngestNamespace;
14+
use Elasticsearch\Namespaces\NamespaceBuilderInterface;
1315
use Elasticsearch\Namespaces\NodesNamespace;
1416
use Elasticsearch\Namespaces\SnapshotNamespace;
1517
use Elasticsearch\Namespaces\BooleanRequestWrapper;
@@ -74,13 +76,17 @@ class Client
7476
/** @var callback */
7577
protected $endpoints;
7678

79+
/** @var NamespaceBuilderInterface[] */
80+
protected $registeredNamespaces = [];
81+
7782
/**
7883
* Client constructor
7984
*
8085
* @param Transport $transport
8186
* @param callable $endpoint
87+
* @param AbstractNamespace[] $registeredNamespaces
8288
*/
83-
public function __construct(Transport $transport, callable $endpoint)
89+
public function __construct(Transport $transport, callable $endpoint, array $registeredNamespaces)
8490
{
8591
$this->transport = $transport;
8692
$this->endpoints = $endpoint;
@@ -91,6 +97,7 @@ public function __construct(Transport $transport, callable $endpoint)
9197
$this->cat = new CatNamespace($transport, $endpoint);
9298
$this->ingest = new IngestNamespace($transport, $endpoint);
9399
$this->tasks = new TasksNamespace($transport, $endpoint);
100+
$this->registeredNamespaces = $registeredNamespaces;
94101
}
95102

96103
/**
@@ -1298,6 +1305,22 @@ public function tasks()
12981305
return $this->tasks;
12991306
}
13001307

1308+
/**
1309+
* Catchall for registered namespaces
1310+
*
1311+
* @param $name
1312+
* @param $arguments
1313+
* @return Object
1314+
* @throws BadMethodCallException if the namespace cannot be found
1315+
*/
1316+
public function __call($name, $arguments)
1317+
{
1318+
if (isset($this->registeredNamespaces[$name])) {
1319+
return $this->registeredNamespaces[$name];
1320+
}
1321+
throw new BadMethodCallException("Namespace [$name] not found");
1322+
}
1323+
13011324
/**
13021325
* @param array $params
13031326
* @param string $arg

src/Elasticsearch/ClientBuilder.php

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Elasticsearch\Connections\Connection;
1111
use Elasticsearch\Connections\ConnectionFactory;
1212
use Elasticsearch\Connections\ConnectionFactoryInterface;
13+
use Elasticsearch\Namespaces\NamespaceBuilderInterface;
1314
use Elasticsearch\Serializers\SerializerInterface;
1415
use Elasticsearch\ConnectionPool\Selectors;
1516
use Elasticsearch\Serializers\SmartSerializer;
@@ -39,6 +40,9 @@ class ClientBuilder
3940
/** @var callback */
4041
private $endpoint;
4142

43+
/** @var NamespaceBuilderInterface[] */
44+
private $registeredNamespacesBuilders = [];
45+
4246
/** @var ConnectionFactoryInterface */
4347
private $connectionFactory;
4448

@@ -230,6 +234,17 @@ public function setEndpoint($endpoint)
230234
return $this;
231235
}
232236

237+
/**
238+
* @param NamespaceBuilderInterface $namespaceBuilder
239+
* @return $this
240+
*/
241+
public function registerNamespace(NamespaceBuilderInterface $namespaceBuilder)
242+
{
243+
$this->registeredNamespacesBuilders[] = $namespaceBuilder;
244+
245+
return $this;
246+
}
247+
233248
/**
234249
* @param \Elasticsearch\Transport $transport
235250
* @return $this
@@ -427,7 +442,6 @@ public function build()
427442
$this->buildTransport();
428443

429444
if (is_null($this->endpoint)) {
430-
$transport = $this->transport;
431445
$serializer = $this->serializer;
432446

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

443-
return $this->instantiate($this->transport, $this->endpoint);
457+
$registeredNamespaces = [];
458+
foreach ($this->registeredNamespacesBuilders as $builder) {
459+
/** @var $builder NamespaceBuilderInterface */
460+
$registeredNamespaces[$builder->getName()] = $builder->getObject($this->transport, $this->serializer);
461+
}
462+
463+
return $this->instantiate($this->transport, $this->endpoint, $registeredNamespaces);
444464
}
445465

446466
/**
447467
* @param Transport $transport
448468
* @param callable $endpoint
469+
* @param Object[] $registeredNamespaces
449470
* @return Client
450471
*/
451-
protected function instantiate(Transport $transport, callable $endpoint)
472+
protected function instantiate(Transport $transport, callable $endpoint, array $registeredNamespaces)
452473
{
453-
return new Client($transport, $endpoint);
474+
return new Client($transport, $endpoint, $registeredNamespaces);
454475
}
455476

456477
private function buildLoggers()
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
/**
3+
* Class RegisteredNamespaceInterface
4+
*
5+
* @category Elasticsearch
6+
* @package Elasticsearch\Namespaces
7+
* @author Zachary Tong <zach@elastic.co>
8+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache2
9+
* @link http://elastic.co
10+
*/
11+
12+
namespace Elasticsearch\Namespaces;
13+
14+
15+
use Elasticsearch\Serializers\SerializerInterface;
16+
use Elasticsearch\Transport;
17+
18+
interface NamespaceBuilderInterface
19+
{
20+
/**
21+
* Returns the name of the namespace. This is what users will call, e.g. the name
22+
* "foo" will be invoked by the user as `$client->foo()`
23+
* @return string
24+
*/
25+
public function getName();
26+
27+
/**
28+
* Returns the actual namespace object which contains your custom methods. The transport
29+
* and serializer objects are provided so that your namespace may do whatever custom
30+
* logic is required.
31+
*
32+
* @param Transport $transport
33+
* @param SerializerInterface $serializer
34+
* @return Object
35+
*/
36+
public function getObject(Transport $transport, SerializerInterface $serializer);
37+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
namespace Elasticsearch\Tests;
4+
5+
use Elasticsearch;
6+
use Elasticsearch\ClientBuilder;
7+
use Elasticsearch\Serializers\SerializerInterface;
8+
use Elasticsearch\Transport;
9+
use Mockery as m;
10+
11+
/**
12+
* Class RegisteredNamespaceTest
13+
*
14+
* @category Tests
15+
* @package Elasticsearch
16+
* @subpackage Tests
17+
* @author Zachary Tong <zachary.tong@elasticsearch.com>
18+
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache2
19+
* @link http://elasticsearch.org
20+
*/
21+
class RegisteredNamespaceTest extends \PHPUnit_Framework_TestCase
22+
{
23+
public function tearDown()
24+
{
25+
m::close();
26+
}
27+
28+
public function testRegisteringNamespace()
29+
{
30+
$builder = new FooNamespaceBuilder();
31+
$client = ClientBuilder::create()->registerNamespace($builder)->build();
32+
$this->assertEquals("123", $client->foo()->fooMethod());
33+
}
34+
35+
/**
36+
* @expectedException \Elasticsearch\Common\Exceptions\BadMethodCallException
37+
*/
38+
public function testNonExistingNamespace()
39+
{
40+
$builder = new FooNamespaceBuilder();
41+
$client = ClientBuilder::create()->registerNamespace($builder)->build();
42+
$this->assertEquals("123", $client->bar()->fooMethod());
43+
}
44+
}
45+
46+
class FooNamespaceBuilder implements Elasticsearch\Namespaces\NamespaceBuilderInterface
47+
{
48+
public function getName()
49+
{
50+
return "foo";
51+
}
52+
53+
public function getObject(Transport $transport, SerializerInterface $serializer)
54+
{
55+
return new FooNamespace();
56+
}
57+
}
58+
59+
class FooNamespace
60+
{
61+
public function fooMethod()
62+
{
63+
return "123";
64+
}
65+
}

0 commit comments

Comments
 (0)