Skip to content

Commit

Permalink
Added service aliases to allow easier autowiring (#301)
Browse files Browse the repository at this point in the history
Added service aliases to allow easier autowiring
  • Loading branch information
tjveldhuizen authored Apr 13, 2020
1 parent fb0c746 commit cbb4c8d
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 5 deletions.
19 changes: 14 additions & 5 deletions src/DependencyInjection/EightPointsGuzzleExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use EightPoints\Bundle\GuzzleBundle\Log\Logger;
use EightPoints\Bundle\GuzzleBundle\Twig\Extension\DebugExtension;
use GuzzleHttp\ClientInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\Reference;
Expand Down Expand Up @@ -91,13 +92,21 @@ public function load(array $configs, ContainerBuilder $container)
// set service name based on client name
$serviceName = sprintf('%s.client.%s', $this->getAlias(), $name);
$container->setDefinition($serviceName, $client);

// Allowed only for Symfony 4.2+
if (method_exists($container, 'registerAliasForArgument')) {
if ('%eight_points_guzzle.http_client.class%' !== $options['class']) {
$container->registerAliasForArgument($serviceName, $options['class'], $name . 'Client');
}
$container->registerAliasForArgument($serviceName, ClientInterface::class, $name . 'Client');
}
}

$clientsWithLogging = array_filter($config['clients'], function ($options) use ($logging) {
$clientsWithLogging = array_filter($config['clients'], function($options) use ($logging) {
return $options['logging'] !== false && $logging !== false;
});

if (count($clientsWithLogging)>0) {
if (count($clientsWithLogging) > 0) {
$this->defineTwigDebugExtension($container);
$this->defineDataCollector($container, $config['slow_response_time'] / 1000);
$this->defineFormatter($container);
Expand Down Expand Up @@ -125,7 +134,7 @@ protected function createHandler(ContainerBuilder $container, string $clientName
$container->setDefinition($eventServiceName, $eventService);

// Create the event Dispatch Middleware
$eventExpression = new Expression(sprintf("service('%s').dispatchEvent()", $eventServiceName));
$eventExpression = new Expression(sprintf("service('%s').dispatchEvent()", $eventServiceName));

$handler = new Definition(HandlerStack::class);
$handler->setFactory([HandlerStack::class, 'create']);
Expand Down Expand Up @@ -173,7 +182,7 @@ protected function createHandler(ContainerBuilder $container, string $clientName
*/
private function convertLogMode($logMode) : int
{
if ($logMode === true){
if ($logMode === true) {
return Logger::LOG_MODE_REQUEST_AND_RESPONSE;
} elseif ($logMode === false) {
return Logger::LOG_MODE_NONE;
Expand Down Expand Up @@ -230,7 +239,7 @@ protected function defineLogger(ContainerBuilder $container, int $logMode, strin
protected function defineDataCollector(ContainerBuilder $container, float $slowResponseTime) : void
{
$dataCollectorDefinition = new Definition('%eight_points_guzzle.data_collector.class%');
$dataCollectorDefinition->addArgument(array_map(function ($loggerId) : Reference {
$dataCollectorDefinition->addArgument(array_map(function($loggerId) : Reference {
return new Reference($loggerId);
}, array_keys($container->findTaggedServiceIds('eight_points_guzzle.logger'))));

Expand Down
38 changes: 38 additions & 0 deletions src/Resources/doc/autowiring-clients.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,44 @@ Autowiring was introduced in Symfony 3.3 and let's read how [Symfony Documentati

> Autowiring allows you to manage services in the container with minimal configuration. It reads the type-hints on your constructor (or other methods) and automatically passes the correct services to each method. Symfony's autowiring is designed to be predictable: if it is not absolutely clear which dependency should be passed, you'll see an actionable exception.
## Symfony >= 4.2
In Symfony 4.2, it is made possible to [bind services by type and name](https://symfony.com/blog/new-in-symfony-4-2-autowiring-by-type-and-name). This feature makes using Guzzle clients a lot easier. Given the following configuration:

```yaml
eight_points_guzzle:
clients:
api_payment:
base_url: "http://api.domain1.tld"
api_crm:
class: App\Client\ApiCrmClient
base_url: "http://api.domain2.tld"
```
The clients can be autowired without further configuration (but mandatory variable names), like this:
```php
namespace App\Controller;

use GuzzleHttp\ClientInterface;
use App\Client\ApiCrmClient;

class FooController extends AbstractController
{
public function bar(ClientInterface $apiPaymentClient)
{
// Default Client class
}

public function baz(ApiCrmClient $apiCrmClient)
{
// Custom Client class (must extend GuzzleHttp\Client)
}
}
```

Autowiring takes place by the combination of the class name and the variable name, as described in [this blog].

## Symfony < 4.2

Getting in consideration, that Guzzle Bundle creates clients of same class, it becomes obvious that Symfony will not be able to guess what to inject.
With some small configurations we can help Symfony to do it.

Expand Down
12 changes: 12 additions & 0 deletions tests/DependencyInjection/EightPointsGuzzleExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ public function testGuzzleExtension()
$this->assertInstanceOf(Client::class, $testApi);
$this->assertEquals(new Uri('//api.domain.tld/path'), $testApi->getConfig('base_uri'));

if (method_exists($container, 'registerAliasForArgument')) {
$this->assertTrue($container->hasAlias(ClientInterface::class . ' $testApiClient'));
$this->assertSame($testApi, $container->get(ClientInterface::class . ' $testApiClient'));

$this->assertFalse($container->hasAlias('%eight_points_guzzle.http_client.class% $testApiClient'));
}

// test Services
$this->assertTrue($container->hasDefinition('eight_points_guzzle.middleware.event_dispatch.test_api'));

Expand All @@ -42,6 +49,11 @@ public function testGuzzleExtension()
$definition = $container->getDefinition('eight_points_guzzle.client.test_api_with_custom_class');
$this->assertSame(CustomClient::class, $definition->getClass());

if (method_exists($container, 'registerAliasForArgument')) {
$testApi = $container->get('eight_points_guzzle.client.test_api_with_custom_class');
$this->assertTrue($container->hasAlias(CustomClient::class . ' $testApiWithCustomClassClient'));
$this->assertSame($testApi, $container->get(ClientInterface::class . ' $testApiWithCustomClassClient'));
}

// test Client with custom handler
$this->assertTrue($container->hasDefinition('eight_points_guzzle.client.test_api_with_custom_handler'));
Expand Down

0 comments on commit cbb4c8d

Please sign in to comment.