From a633b0fbc15fc90c5dca3a2f973e88beeac68647 Mon Sep 17 00:00:00 2001 From: Tobias Nyholm Date: Fri, 25 Dec 2015 00:36:18 +0100 Subject: [PATCH] Make sure you can configure clients and register them as services --- .travis.yml | 23 ++++---- ClientFactory/ClientFactoryInterface.php | 18 +++++++ ClientFactory/DummyClient.php | 12 +++++ ClientFactory/Guzzle5Factory.php | 26 ++++++++++ ClientFactory/Guzzle6Factory.php | 23 ++++++++ DependencyInjection/Configuration.php | 26 +++++++++- DependencyInjection/HttplugExtension.php | 19 +++++++ Exception/InvalidConfiguration.php | 7 +++ HttplugBundle.php | 1 + README.md | 52 ++++++++++++++++--- Resources/config/discovery.xml | 4 ++ Resources/config/services.xml | 12 +++++ Tests/Resources/Fixtures/config/full.php | 8 +-- Tests/Resources/Fixtures/config/full.xml | 9 ++-- Tests/Resources/Fixtures/config/full.yml | 8 +-- .../DependencyInjection/ConfigurationTest.php | 12 +++-- .../HttplugExtensionTest.php | 14 +++-- composer.json | 17 ++++-- 18 files changed, 246 insertions(+), 45 deletions(-) create mode 100644 ClientFactory/ClientFactoryInterface.php create mode 100644 ClientFactory/DummyClient.php create mode 100644 ClientFactory/Guzzle5Factory.php create mode 100644 ClientFactory/Guzzle6Factory.php create mode 100644 Exception/InvalidConfiguration.php create mode 100644 Resources/config/services.xml diff --git a/.travis.yml b/.travis.yml index 7f39f3b2..e4079d6e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: php php: - - 5.4 - 5.5 - 5.6 - 7.0 @@ -10,25 +9,22 @@ php: env: global: - TEST_COMMAND="composer test" + matrix: + - SYMFONY_VERSION=3.0.* + - SYMFONY_VERSION=2.8.* - SYMFONY_VERSION=2.7.* matrix: - allow_failures: - - php: 7.0 fast_finish: true - include: - - php: 5.4 - env: - - COMPOSER_FLAGS="--prefer-stable --prefer-lowest" - - COVERAGE=true - - TEST_COMMAND="composer test-ci" - - php: 5.6 - env: SYMFONY_VERSION=2.8.* - - php: 5.6 - env: SYMFONY_VERSION=3.0.* + allow_failures: + - php: hhvm + - env: SYMFONY_VERSION=3.0.* + - php: 5.5 + env: COMPOSER_FLAGS="--prefer-stable --prefer-lowest" && COVERAGE=true && TEST_COMMAND="composer test-ci" && SYMFONY_VERSION=2.7.* before_install: - travis_retry composer self-update + - wget https://github.com/puli/cli/releases/download/1.0.0-beta9/puli.phar && chmod +x puli.phar install: - composer require symfony/symfony:${SYMFONY_VERSION} --no-update @@ -40,4 +36,3 @@ script: after_success: - if [[ "$COVERAGE" = true ]]; then wget https://scrutinizer-ci.com/ocular.phar; fi - if [[ "$COVERAGE" = true ]]; then php ocular.phar code-coverage:upload --format=php-clover build/coverage.xml; fi - diff --git a/ClientFactory/ClientFactoryInterface.php b/ClientFactory/ClientFactoryInterface.php new file mode 100644 index 00000000..d0e8a35d --- /dev/null +++ b/ClientFactory/ClientFactoryInterface.php @@ -0,0 +1,18 @@ + + */ +interface ClientFactoryInterface +{ + /** + * Input an array of configuration to be able to create a HttpClient + * + * @param array $config + * + * @return \Http\Client\HttpClient + */ + public function createClient(array $config = array()); +} diff --git a/ClientFactory/DummyClient.php b/ClientFactory/DummyClient.php new file mode 100644 index 00000000..35e8fe90 --- /dev/null +++ b/ClientFactory/DummyClient.php @@ -0,0 +1,12 @@ + + */ +class DummyClient +{ +} diff --git a/ClientFactory/Guzzle5Factory.php b/ClientFactory/Guzzle5Factory.php new file mode 100644 index 00000000..c8aaaf3d --- /dev/null +++ b/ClientFactory/Guzzle5Factory.php @@ -0,0 +1,26 @@ + + */ +class Guzzle5Factory +{ + /** + * {@inheritdoc} + */ + public function createClient(array $config = []) + { + if (!class_exists('Http\Adapter\Guzzle5\Client')) { + throw new \LogicException('To use the Guzzle5 adapter you need to install the "php-http/guzzle5-adapter" package.'); + } + + $client = new Client($config); + + return new Adapter($client); + } +} diff --git a/ClientFactory/Guzzle6Factory.php b/ClientFactory/Guzzle6Factory.php new file mode 100644 index 00000000..2add9fa7 --- /dev/null +++ b/ClientFactory/Guzzle6Factory.php @@ -0,0 +1,23 @@ + + */ +class Guzzle6Factory implements ClientFactoryInterface +{ + public function createClient(array $config = []) + { + if (!class_exists('Http\Adapter\Guzzle6\Client')) { + throw new \LogicException('To use the Guzzle6 adapter you need to install the "php-http/guzzle6-adapter" package.'); + } + + $client = new Client($config); + + return new Adapter($client); + } +} diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 3ae60a81..54918b1a 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -2,12 +2,14 @@ namespace Http\HttplugBundle\DependencyInjection; +use Symfony\Component\Config\Definition\ArrayNode; +use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; /** - * This class contains the configuration information for the bundle + * This class contains the configuration information for the bundle. * * This information is solely responsible for how the different configuration * sections are normalized, and merged. @@ -24,12 +26,15 @@ public function getConfigTreeBuilder() $treeBuilder = new TreeBuilder(); $rootNode = $treeBuilder->root('httplug'); + $this->configureClients($rootNode); + $rootNode ->validate() ->ifTrue(function ($v) { return !empty($v['classes']['client']) || !empty($v['classes']['message_factory']) || !empty($v['classes']['uri_factory']) + || !empty($v['classes']['stream_factory']) ; }) ->then(function ($v) { @@ -54,6 +59,7 @@ public function getConfigTreeBuilder() ->scalarNode('client')->defaultValue('httplug.client.default')->end() ->scalarNode('message_factory')->defaultValue('httplug.message_factory.default')->end() ->scalarNode('uri_factory')->defaultValue('httplug.uri_factory.default')->end() + ->scalarNode('stream_factory')->defaultValue('httplug.stream_factory.default')->end() ->end() ->end() ->arrayNode('classes') @@ -63,6 +69,7 @@ public function getConfigTreeBuilder() ->scalarNode('client')->defaultNull()->end() ->scalarNode('message_factory')->defaultNull()->end() ->scalarNode('uri_factory')->defaultNull()->end() + ->scalarNode('stream_factory')->defaultNull()->end() ->end() ->end() ->end() @@ -70,4 +77,21 @@ public function getConfigTreeBuilder() return $treeBuilder; } + + protected function configureClients(ArrayNodeDefinition $root) + { + $root->children() + ->arrayNode('clients') + ->useAttributeAsKey('name') + ->prototype('array') + ->children() + ->scalarNode('factory') + ->isRequired() + ->cannotBeEmpty() + ->info('The service id of a factory to use when creating the adapter.') + ->end() + ->variableNode('config')->end() + ->end() + ->end(); + } } diff --git a/DependencyInjection/HttplugExtension.php b/DependencyInjection/HttplugExtension.php index 9c0bac7a..cf3b8c4c 100644 --- a/DependencyInjection/HttplugExtension.php +++ b/DependencyInjection/HttplugExtension.php @@ -2,9 +2,11 @@ namespace Http\HttplugBundle\DependencyInjection; +use Http\HttplugBundle\ClientFactory\DummyClient; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; +use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpKernel\DependencyInjection\Extension; /** @@ -22,6 +24,7 @@ public function load(array $configs, ContainerBuilder $container) $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); + $loader->load('services.xml'); $loader->load('discovery.xml'); foreach ($config['classes'] as $service => $class) { if (!empty($class)) { @@ -33,5 +36,21 @@ public function load(array $configs, ContainerBuilder $container) foreach ($config['main_alias'] as $type => $id) { $container->setAlias(sprintf('httplug.%s', $type), $id); } + + // Configure client services + $first = isset($config['clients']['default']) ? 'default' : null; + foreach ($config['clients'] as $name => $arguments) { + if ($first === null) { + $first = $name; + } + + $def = $container->register('httplug.client.'.$name, DummyClient::class); + $def->setFactory([new Reference($arguments['factory']), 'createClient']) + ->addArgument($arguments['config']); + } + + if ($first !== null) { + $container->setAlias('httplug.client.default', 'httplug.client.'.$first); + } } } diff --git a/Exception/InvalidConfiguration.php b/Exception/InvalidConfiguration.php new file mode 100644 index 00000000..b68d1782 --- /dev/null +++ b/Exception/InvalidConfiguration.php @@ -0,0 +1,7 @@ +container->get('httplug.client.my_guzzle5'); +$httpClient = $this->container->get('httplug.client.acme'); ``` ### Use for Reusable Bundles diff --git a/Resources/config/discovery.xml b/Resources/config/discovery.xml index bd95332c..0969e8ad 100644 --- a/Resources/config/discovery.xml +++ b/Resources/config/discovery.xml @@ -16,6 +16,10 @@ class="Http\Message\UriFactory"> + + + diff --git a/Resources/config/services.xml b/Resources/config/services.xml new file mode 100644 index 00000000..369e8902 --- /dev/null +++ b/Resources/config/services.xml @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/Tests/Resources/Fixtures/config/full.php b/Tests/Resources/Fixtures/config/full.php index b945392e..66aba790 100644 --- a/Tests/Resources/Fixtures/config/full.php +++ b/Tests/Resources/Fixtures/config/full.php @@ -5,10 +5,12 @@ 'client' => 'my_client', 'message_factory' => 'my_message_factory', 'uri_factory' => 'my_uri_factory', + 'stream_factory' => 'my_stream_factory', ), 'classes' => array( - 'client' => 'Http\Adapter\Guzzle6HttpAdapter', - 'message_factory' => 'Http\Discovery\MessageFactory\GuzzleFactory', - 'uri_factory' => 'Http\Discovery\UriFactory\GuzzleFactory', + 'client' => 'Http\Adapter\Guzzle6\Client', + 'message_factory' => 'Http\Message\MessageFactory\GuzzleMessageFactory', + 'uri_factory' => 'Http\Message\UriFactory\GuzzleUriFactory', + 'stream_factory' => 'Http\Message\StreamFactory\GuzzleStreamFactory', ), )); diff --git a/Tests/Resources/Fixtures/config/full.xml b/Tests/Resources/Fixtures/config/full.xml index 26e9fa2c..f3553a6f 100644 --- a/Tests/Resources/Fixtures/config/full.xml +++ b/Tests/Resources/Fixtures/config/full.xml @@ -6,12 +6,13 @@ my_client my_message_factory my_uri_factory + my_stream_factory - Http\Adapter\Guzzle6HttpAdapter - Http\Discovery\MessageFactory\GuzzleFactory - Http\Discovery\UriFactory\GuzzleFactory - + Http\Adapter\Guzzle6\Client + Http\Message\MessageFactory\GuzzleMessageFactory + Http\Message\UriFactory\GuzzleUriFactory + Http\Message\StreamFactory\GuzzleStreamFactory diff --git a/Tests/Resources/Fixtures/config/full.yml b/Tests/Resources/Fixtures/config/full.yml index f4e6faf6..881b62a9 100644 --- a/Tests/Resources/Fixtures/config/full.yml +++ b/Tests/Resources/Fixtures/config/full.yml @@ -3,7 +3,9 @@ httplug: client: my_client message_factory: my_message_factory uri_factory: my_uri_factory + stream_factory: my_stream_factory classes: - client: Http\Adapter\Guzzle6HttpAdapter - message_factory: Http\Discovery\MessageFactory\GuzzleFactory - uri_factory: Http\Discovery\UriFactory\GuzzleFactory + client: Http\Adapter\Guzzle6\Client + message_factory: Http\Message\MessageFactory\GuzzleMessageFactory + uri_factory: Http\Message\UriFactory\GuzzleUriFactory + stream_factory: Http\Message\StreamFactory\GuzzleStreamFactory \ No newline at end of file diff --git a/Tests/Unit/DependencyInjection/ConfigurationTest.php b/Tests/Unit/DependencyInjection/ConfigurationTest.php index 936451ae..295b6497 100644 --- a/Tests/Unit/DependencyInjection/ConfigurationTest.php +++ b/Tests/Unit/DependencyInjection/ConfigurationTest.php @@ -28,12 +28,15 @@ public function testEmptyConfiguration() 'client' => 'httplug.client.default', 'message_factory' => 'httplug.message_factory.default', 'uri_factory' => 'httplug.uri_factory.default', + 'stream_factory' => 'httplug.stream_factory.default', ), 'classes' => array( 'client' => null, 'message_factory' => null, 'uri_factory' => null, + 'stream_factory' => null, ), + 'clients'=>array(), ); $formats = array_map(function ($path) { @@ -56,12 +59,15 @@ public function testSupportsAllConfigFormats() 'client' => 'my_client', 'message_factory' => 'my_message_factory', 'uri_factory' => 'my_uri_factory', + 'stream_factory' => 'my_stream_factory', ), 'classes' => array( - 'client' => 'Http\Adapter\Guzzle6HttpAdapter', - 'message_factory' => 'Http\Discovery\MessageFactory\GuzzleFactory', - 'uri_factory' => 'Http\Discovery\UriFactory\GuzzleFactory', + 'client' => 'Http\Adapter\Guzzle6\Client', + 'message_factory' => 'Http\Message\MessageFactory\GuzzleMessageFactory', + 'uri_factory' => 'Http\Message\UriFactory\GuzzleUriFactory', + 'stream_factory' => 'Http\Message\StreamFactory\GuzzleStreamFactory', ), + 'clients'=>array(), ); $formats = array_map(function ($path) { diff --git a/Tests/Unit/DependencyInjection/HttplugExtensionTest.php b/Tests/Unit/DependencyInjection/HttplugExtensionTest.php index a81cbadb..0eac034f 100644 --- a/Tests/Unit/DependencyInjection/HttplugExtensionTest.php +++ b/Tests/Unit/DependencyInjection/HttplugExtensionTest.php @@ -21,30 +21,32 @@ public function testConfigLoadDefault() { $this->load(); - foreach (['client', 'message_factory', 'uri_factory'] as $type) { + foreach (['client', 'message_factory', 'uri_factory', 'stream_factory'] as $type) { $this->assertContainerBuilderHasAlias("httplug.$type", "httplug.$type.default"); } $this->assertContainerBuilderHasService('httplug.client.default', 'Http\Client\HttpClient'); $this->assertContainerBuilderHasService('httplug.message_factory.default', 'Http\Message\MessageFactory'); $this->assertContainerBuilderHasService('httplug.uri_factory.default', 'Http\Message\UriFactory'); + $this->assertContainerBuilderHasService('httplug.stream_factory.default', 'Http\Message\StreamFactory'); } public function testConfigLoadClass() { $this->load(array( 'classes' => array( - 'client' => 'Http\Adapter\Guzzle6HttpAdapter' + 'client' => 'Http\Adapter\Guzzle6\Client' ), )); - foreach (['client', 'message_factory', 'uri_factory'] as $type) { + foreach (['client', 'message_factory', 'uri_factory', 'stream_factory'] as $type) { $this->assertContainerBuilderHasAlias("httplug.$type", "httplug.$type.default"); } - $this->assertContainerBuilderHasService('httplug.client.default', 'Http\Adapter\Guzzle6HttpAdapter'); + $this->assertContainerBuilderHasService('httplug.client.default', 'Http\Adapter\Guzzle6\Client'); $this->assertContainerBuilderHasService('httplug.message_factory.default', 'Http\Message\MessageFactory'); $this->assertContainerBuilderHasService('httplug.uri_factory.default', 'Http\Message\UriFactory'); + $this->assertContainerBuilderHasService('httplug.stream_factory.default', 'Http\Message\StreamFactory'); } public function testConfigLoadService() @@ -54,15 +56,17 @@ public function testConfigLoadService() 'client' => 'my_client_service', 'message_factory' => 'my_message_factory_service', 'uri_factory' => 'my_uri_factory_service', + 'stream_factory' => 'my_stream_factory_service', ), )); - foreach (['client', 'message_factory', 'uri_factory'] as $type) { + foreach (['client', 'message_factory', 'uri_factory', 'stream_factory'] as $type) { $this->assertContainerBuilderHasAlias("httplug.$type", "my_{$type}_service"); } $this->assertContainerBuilderHasService('httplug.client.default', 'Http\Client\HttpClient'); $this->assertContainerBuilderHasService('httplug.message_factory.default', 'Http\Message\MessageFactory'); $this->assertContainerBuilderHasService('httplug.uri_factory.default', 'Http\Message\UriFactory'); + $this->assertContainerBuilderHasService('httplug.stream_factory.default', 'Http\Message\StreamFactory'); } } diff --git a/composer.json b/composer.json index ccd7bab1..ed906aa3 100644 --- a/composer.json +++ b/composer.json @@ -14,22 +14,31 @@ "minimum-stability": "dev", "prefer-stable": true, "require": { - "php-http/discovery": "^0.2.0", + "php": ">=5.5", + "php-http/discovery": "^0.6.3", "php-http/client-implementation": "^1.0", - "php-http/message-factory": "^0.2.0", + "php-http/message-factory": "^1.0", + "php-http/plugins": "dev-master", "symfony/framework-bundle": "^2.7|^3.0" }, "require-dev": { + "phpunit/phpunit": "^4.4", + "php-http/guzzle6-adapter": "^0.3.1", + "php-http/message": "^0.2.1", + "php-http/client-common": "^0.1.1", "symfony/symfony": "^2.7|^3.0", - "php-http/guzzle6-adapter": "^0.2", "polishsymfonycommunity/symfony-mocker-container": "~1.0", - "matthiasnoback/symfony-dependency-injection-test": "0.*" + "matthiasnoback/symfony-dependency-injection-test": "^0.7" }, "autoload": { "psr-4": { "Http\\HttplugBundle\\": "" } }, + "scripts": { + "test": "vendor/bin/phpunit", + "test-ci": "vendor/bin/phpunit --coverage-text --coverage-clover=build/coverage.xml" + }, "extra": { "branch-alias": { "dev-master": "1.0-dev"