Skip to content

Commit 72bad26

Browse files
committed
Make sure you can configure clients and register them as services
1 parent 9a59cf5 commit 72bad26

File tree

12 files changed

+284
-0
lines changed

12 files changed

+284
-0
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace Http\HttplugBundle\ClientFactory;
4+
5+
use Http\Client\HttpClient;
6+
7+
/**
8+
* Interface ClientFactoryInterface.
9+
*/
10+
interface ClientFactoryInterface
11+
{
12+
/**
13+
* Configure and return a client.
14+
*
15+
* @param array $config
16+
*
17+
* @return HttpClient
18+
*/
19+
public function configure(array $config = array());
20+
21+
/**
22+
* Return the name of the client.
23+
*
24+
* @return string
25+
*/
26+
public function getName();
27+
}

ClientFactory/DummyFactory.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace Http\HttplugBundle\ClientFactory;
4+
5+
use Http\Client\HttpClient;
6+
7+
/**
8+
* This class is used with the dependency injection when we register the service. It acts like a place holder and
9+
* is needed for the framework to be able to bind method class to it.
10+
*
11+
* @author Tobias Nyholm <[email protected]>
12+
*/
13+
class DummyFactory implements ClientFactoryInterface
14+
{
15+
/**
16+
* Configure and return a client.
17+
*
18+
* @param array $config
19+
*
20+
* @return HttpClient
21+
*/
22+
public function configure(array $config = array())
23+
{
24+
return;
25+
}
26+
27+
/**
28+
* Return the name of the client.
29+
*
30+
* @return string
31+
*/
32+
public function getName()
33+
{
34+
return 'dummy';
35+
}
36+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
namespace Http\HttplugBundle\ClientFactory;
4+
5+
use Http\Client\HttpClient;
6+
7+
/**
8+
* This is a client factory that will help you instantiate any client.
9+
*
10+
* @author Tobias Nyholm <[email protected]>
11+
*/
12+
class GenericClientFactory
13+
{
14+
/**
15+
* @var ClientFactoryInterface[]
16+
*/
17+
private $clientFactories;
18+
19+
/**
20+
* @param string $adapter
21+
* @param array $config
22+
*
23+
* @return HttpClient
24+
*/
25+
public function getClient($adapter, array $config = [])
26+
{
27+
if (!isset($this->clientFactories[$adapter])) {
28+
throw new \InvalidArgumentException(sprintf('No configurator named %s was found.', $adapter));
29+
}
30+
31+
return $this->clientFactories[$adapter]->configure($config);
32+
}
33+
34+
/**
35+
* @param ClientFactoryInterface $factory
36+
*
37+
* @return $this
38+
*/
39+
public function addInstance(ClientFactoryInterface $factory)
40+
{
41+
$this->clientFactories[$factory->getName()] = $factory;
42+
43+
return $this;
44+
}
45+
}

ClientFactory/Guzzle5Factory.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
namespace Http\HttplugBundle\ClientFactory;
4+
5+
use GuzzleHttp\Client;
6+
use Http\Adapter\Guzzle5HttpAdapter;
7+
8+
/**
9+
* @author Tobias Nyholm <[email protected]>
10+
*/
11+
class Guzzle5Factory implements ClientFactoryInterface
12+
{
13+
/**
14+
* {@inheritdoc}
15+
*/
16+
public function configure(array $config = array())
17+
{
18+
$client = new Client($config);
19+
20+
return new Guzzle5HttpAdapter($client);
21+
}
22+
23+
/**
24+
* {@inheritdoc}
25+
*/
26+
public function getName()
27+
{
28+
return 'guzzle5';
29+
}
30+
}

ClientFactory/Guzzle6Factory.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
namespace Http\HttplugBundle\ClientFactory;
4+
5+
use GuzzleHttp\Client;
6+
use Http\Adapter\Guzzle6HttpAdapter;
7+
8+
/**
9+
* @author Tobias Nyholm <[email protected]>
10+
*/
11+
class Guzzle6Factory implements ClientFactoryInterface
12+
{
13+
public function configure(array $config = array())
14+
{
15+
$client = new Client($config);
16+
17+
return new Guzzle6HttpAdapter($client);
18+
}
19+
20+
public function getName()
21+
{
22+
return 'guzzle6';
23+
}
24+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
namespace Http\HttplugBundle\DependencyInjection\CompilerPass;
4+
5+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
6+
use Symfony\Component\DependencyInjection\ContainerBuilder;
7+
use Symfony\Component\DependencyInjection\Reference;
8+
9+
/**
10+
* @author Tobias Nyholm <[email protected]>
11+
*/
12+
class ClientFactoryPass implements CompilerPassInterface
13+
{
14+
/**
15+
* Make sure all services tagged with 'httplug.configurator' gets added to the ClientFactory.
16+
*
17+
* @param ContainerBuilder $container
18+
*/
19+
public function process(ContainerBuilder $container)
20+
{
21+
if (!$container->has('httplug.client.factory')) {
22+
return;
23+
}
24+
25+
$definition = $container->findDefinition('httplug.client.factory');
26+
27+
$taggedServices = $container->findTaggedServiceIds('httplug.client_factory');
28+
foreach ($taggedServices as $id => $tags) {
29+
$definition->addMethodCall('addInstance', [new Reference($id)]);
30+
}
31+
}
32+
}

DependencyInjection/Configuration.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
namespace Http\HttplugBundle\DependencyInjection;
44

5+
use Symfony\Component\Config\Definition\ArrayNode;
6+
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
7+
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
58
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
69
use Symfony\Component\Config\Definition\ConfigurationInterface;
710
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
@@ -24,6 +27,8 @@ public function getConfigTreeBuilder()
2427
$treeBuilder = new TreeBuilder();
2528
$rootNode = $treeBuilder->root('httplug');
2629

30+
$this->configureClients($rootNode);
31+
2732
$rootNode
2833
->validate()
2934
->ifTrue(function ($v) {
@@ -70,4 +75,20 @@ public function getConfigTreeBuilder()
7075

7176
return $treeBuilder;
7277
}
78+
79+
protected function configureClients(ArrayNodeDefinition $root)
80+
{
81+
$validAdapters = ['guzzle5', 'guzzle6'];
82+
83+
$root->children()
84+
->arrayNode('clients')
85+
->useAttributeAsKey('name')
86+
->prototype('array')
87+
->children()
88+
->enumNode('adapter')->values($validAdapters)->isRequired()->cannotBeEmpty()->end()
89+
->variableNode('config')->end()
90+
->end()
91+
->end();
92+
93+
}
7394
}

DependencyInjection/HttplugExtension.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
namespace Http\HttplugBundle\DependencyInjection;
44

5+
use Http\HttplugBundle\ClientFactory\DummyFactory;
56
use Symfony\Component\DependencyInjection\ContainerBuilder;
67
use Symfony\Component\Config\FileLocator;
78
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
9+
use Symfony\Component\DependencyInjection\Reference;
810
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
911

1012
/**
@@ -22,6 +24,7 @@ public function load(array $configs, ContainerBuilder $container)
2224

2325
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
2426

27+
$loader->load('services.xml');
2528
$loader->load('discovery.xml');
2629
foreach ($config['classes'] as $service => $class) {
2730
if (!empty($class)) {
@@ -33,5 +36,31 @@ public function load(array $configs, ContainerBuilder $container)
3336
foreach ($config['main_alias'] as $type => $id) {
3437
$container->setAlias(sprintf('httplug.%s', $type), $id);
3538
}
39+
40+
// Configure services
41+
foreach ($config['clients'] as $name => $arguments) {
42+
$this->verifyDependencies($arguments['adapter']);
43+
$def = $container->register('httplug.'.$name, DummyFactory::class);
44+
$def->setFactory([new Reference('httplug.client.factory'), 'getClient'])
45+
->addArgument($arguments['adapter'])
46+
->addArgument($arguments['config']);
47+
}
48+
}
49+
50+
/**
51+
* Make sure we got all the dependencies installed.
52+
*
53+
* @param $adapterName
54+
*/
55+
protected function verifyDependencies($adapterName)
56+
{
57+
$map = [
58+
'guzzle5'=>['package'=>'php-http/guzzle5-adapter', 'class'=>'Http\Adapter\Guzzle5HttpAdapter'],
59+
'guzzle6'=>['package'=>'php-http/guzzle6-adapter', 'class'=>'Http\Adapter\Guzzle6HttpAdapter'],
60+
];
61+
62+
if (!class_exists($map[$adapterName]['class'])) {
63+
throw new \LogicException(sprintf('In order to use %s adapter you need to install package %s', $adapterName, $map[$adapterName]['package']));
64+
}
3665
}
3766
}

HttplugBundle.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,22 @@
22

33
namespace Http\HttplugBundle;
44

5+
use Http\HttplugBundle\DependencyInjection\CompilerPass\ClientFactoryPass;
6+
use Symfony\Component\DependencyInjection\ContainerBuilder;
57
use Symfony\Component\HttpKernel\Bundle\Bundle;
68

79
/**
810
* @author David Buchmann <[email protected]>
911
*/
1012
class HttplugBundle extends Bundle
1113
{
14+
/**
15+
* {@inheritdoc}
16+
*/
17+
public function build(ContainerBuilder $container)
18+
{
19+
parent::build($container);
20+
$container->addCompilerPass(new ClientFactoryPass());
21+
22+
}
1223
}

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,17 @@ httplug:
6161
client: ~ # uses discovery if not specified
6262
message_factory: ~
6363
uri_factory: ~
64+
clients:
65+
acme:
66+
adapter: guzzle5
67+
config:
68+
timeout: 2
69+
verify: false
70+
```
71+
72+
```php
73+
74+
$httpClient = $this->container->get('httplug.acme');
6475
```
6576

6677
### Use for Reusable Bundles

Resources/config/services.xml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<container xmlns="http://symfony.com/schema/dic/services"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
5+
6+
<services>
7+
<service id="httplug.client.factory" class="Http\HttplugBundle\ClientFactory\GenericClientFactory" />
8+
9+
<!-- ClientFactories -->
10+
<service id="httplug.client.factory.guzzle5" class="Http\HttplugBundle\ClientFactory\Guzzle5Factory" public="false">
11+
<tag name="httplug.client_factory" />
12+
</service>
13+
<service id="httplug.client.factory.guzzle6" class="Http\HttplugBundle\ClientFactory\Guzzle6Factory" public="false">
14+
<tag name="httplug.client_factory" /></service>
15+
</services>
16+
</container>

Tests/Unit/DependencyInjection/ConfigurationTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public function testEmptyConfiguration()
3434
'message_factory' => null,
3535
'uri_factory' => null,
3636
),
37+
'clients'=>array(),
3738
);
3839

3940
$formats = array_map(function ($path) {
@@ -62,6 +63,7 @@ public function testSupportsAllConfigFormats()
6263
'message_factory' => 'Http\Discovery\MessageFactory\GuzzleFactory',
6364
'uri_factory' => 'Http\Discovery\UriFactory\GuzzleFactory',
6465
),
66+
'clients'=>array(),
6567
);
6668

6769
$formats = array_map(function ($path) {

0 commit comments

Comments
 (0)