diff --git a/src/PluginClientBuilder.php b/src/PluginClientBuilder.php new file mode 100644 index 0000000..c1012df --- /dev/null +++ b/src/PluginClientBuilder.php @@ -0,0 +1,71 @@ + + */ +final class PluginClientBuilder +{ + /** @var Plugin[][] List of plugins ordered by priority [priority => Plugin[]]). */ + private $plugins = []; + + /** @var array Array of options to give to the plugin client */ + private $options = []; + + /** + * @param int $priority Priority of the plugin. The higher comes first. + */ + public function addPlugin(Plugin $plugin, int $priority = 0): self + { + $this->plugins[$priority][] = $plugin; + + return $this; + } + + public function setOption(string $name, $value): self + { + $this->options[$name] = $value; + + return $this; + } + + public function removeOption(string $name): self + { + unset($this->options[$name]); + + return $this; + } + + /** + * @param ClientInterface | HttpAsyncClient $client + */ + public function createClient($client): PluginClient + { + if (!$client instanceof ClientInterface && !$client instanceof HttpAsyncClient) { + throw new \RuntimeException('You must provide a valid http client'); + } + + $plugins = $this->plugins; + + if (0 === count($plugins)) { + $plugins[] = []; + } + + krsort($plugins); + $plugins = array_merge(...$plugins); + + return new PluginClient( + $client, + array_values($plugins), + $this->options + ); + } +} diff --git a/tests/PluginClientBuilderTest.php b/tests/PluginClientBuilderTest.php new file mode 100644 index 0000000..190c4a5 --- /dev/null +++ b/tests/PluginClientBuilderTest.php @@ -0,0 +1,80 @@ + $this->prophesize(Plugin::class)->reveal(), + -10 => $this->prophesize(Plugin::class)->reveal(), + 0 => $this->prophesize(Plugin::class)->reveal(), + ]; + + foreach ($plugins as $priority => $plugin) { + $builder->addPlugin($plugin, $priority); + } + + $client = $this->prophesize($client)->reveal(); + $client = $builder->createClient($client); + + $closure = Closure::bind( + function (): array { + return $this->plugins; + }, + $client, + PluginClient::class + ); + + $plugged = $closure(); + + $expected = $plugins; + krsort($expected); + $expected = array_values($expected); + + $this->assertSame($expected, $plugged); + } + + /** @dataProvider clientProvider */ + public function testOptions(string $client): void + { + $builder = new PluginClientBuilder(); + $builder->setOption('max_restarts', 5); + + $client = $this->prophesize($client)->reveal(); + $client = $builder->createClient($client); + + $closure = Closure::bind( + function (): array { + return $this->options; + }, + $client, + PluginClient::class + ); + + $options = $closure(); + + $this->assertArrayHasKey('max_restarts', $options); + $this->assertSame(5, $options['max_restarts']); + } + + public function clientProvider(): iterable + { + yield 'sync\'d http client' => [HttpClient::class]; + yield 'async\'d http client' => [HttpAsyncClient::class]; + } +}