Completed
Pull Request — master (#87)
by Tobias
08:58
created

HttplugExtension::configureAutoDiscoveryClients()   D

Complexity

Conditions 10
Paths 18

Size

Total Lines 34
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 110

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 34
rs 4.8196
ccs 0
cts 0
cp 0
cc 10
eloc 19
nc 18
nop 2
crap 110

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Http\HttplugBundle\DependencyInjection;
4
5
use Http\Client\Common\FlexibleHttpClient;
6
use Http\Client\Common\HttpMethodsClient;
7
use Http\Client\Common\Plugin\AuthenticationPlugin;
8
use Http\Client\Common\PluginClient;
9
use Http\Discovery\HttpAsyncClientDiscovery;
10
use Http\Discovery\HttpClientDiscovery;
11
use Http\HttplugBundle\ClientFactory\DummyClient;
12
use Http\HttplugBundle\Collector\DebugPlugin;
13
use Http\Message\Authentication\BasicAuth;
14
use Http\Message\Authentication\Bearer;
15
use Http\Message\Authentication\Wsse;
16
use Symfony\Component\Config\FileLocator;
17
use Symfony\Component\DependencyInjection\ContainerBuilder;
18
use Symfony\Component\DependencyInjection\Definition;
19
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
20
use Symfony\Component\DependencyInjection\Reference;
21
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
22
23
/**
24
 * @author David Buchmann <[email protected]>
25
 * @author Tobias Nyholm <[email protected]>
26
 */
27
class HttplugExtension extends Extension
28
{
29 3
    /**
30
     * {@inheritdoc}
31 3
     */
32 3
    public function load(array $configs, ContainerBuilder $container)
33
    {
34 3
        $configuration = $this->getConfiguration($configs, $container);
35
        $config = $this->processConfiguration($configuration, $configs);
0 ignored issues
show
Documentation introduced by
$configuration is of type object|null, but the function expects a object<Symfony\Component...ConfigurationInterface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
36 3
37 3
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
38
39 3
        $loader->load('services.xml');
40 3
        $loader->load('plugins.xml');
41
42
        $enabled = is_bool($config['toolbar']['enabled']) ? $config['toolbar']['enabled'] : $container->hasParameter('kernel.debug') && $container->getParameter('kernel.debug');
43
        if ($enabled) {
44
            $loader->load('data-collector.xml');
45
            $config['_inject_collector_plugin'] = true;
46
47
            if (!empty($config['toolbar']['formatter'])) {
48
                // Add custom formatter
49
                $container->getDefinition('httplug.collector.debug_collector')
50 3
                    ->replaceArgument(0, new Reference($config['toolbar']['formatter']));
51 3
            }
52 1
53 1
            $container->getDefinition('httplug.formatter.full_http_message')
54 3
                ->addArgument($config['toolbar']['captured_body_length']);
55
        }
56
57 3
        foreach ($config['classes'] as $service => $class) {
58 3
            if (!empty($class)) {
59 3
                $container->register(sprintf('httplug.%s.default', $service), $class);
60
            }
61 3
        }
62 3
63 3
        // Set main aliases
64
        foreach ($config['main_alias'] as $type => $id) {
65
            $container->setAlias(sprintf('httplug.%s', $type), $id);
66
        }
67
68
        $this->configurePlugins($container, $config['plugins']);
69
        $this->configureClients($container, $config);
70
        $this->configureAutoDiscoveryClients($container, $config);
71 3
    }
72
73
    /**
74 3
     * Configure client services.
75
     *
76 3
     * @param ContainerBuilder $container
77
     * @param array            $config
78
     */
79
    private function configureClients(ContainerBuilder $container, array $config)
80
    {
81
        // If we have a client named 'default'
82
        $first = isset($config['clients']['default']) ? 'default' : null;
83
84
        foreach ($config['clients'] as $name => $arguments) {
85
            if ($first === null) {
86
                // Save the name of the first configurated client.
87 3
                $first = $name;
88
            }
89
90 3
            $this->configureClient($container, $name, $arguments, $config['_inject_collector_plugin']);
91
        }
92
93
        // If we have clients configured
94
        if ($first !== null) {
95 3
            if ($first !== 'default') {
96
                // Alias the first client to httplug.client.default
97
                $container->setAlias('httplug.client.default', 'httplug.client.'.$first);
98
            }
99
        } elseif (isset($config['_inject_collector_plugin'])) {
100
            $serviceIdDebugPlugin = $this->registerDebugPlugin($container, 'default');
101
            // No client was configured. Make sure to configure the auto discovery client with the PluginClient.
102
            $container->register('httplug.client', PluginClient::class)
103
                ->addArgument(new Reference('httplug.client.default'))
104
                ->addArgument([])
105
                ->addArgument(['debug_plugins' => [new Reference($serviceIdDebugPlugin)]]);
106
        }
107
    }
108
109
    /**
110
     * @param ContainerBuilder $container
111
     * @param array            $config
112
     */
113
    private function configurePlugins(ContainerBuilder $container, array $config)
114
    {
115
        if (!empty($config['authentication'])) {
116
            $this->configureAuthentication($container, $config['authentication']);
117
        }
118
        unset($config['authentication']);
119
120
        foreach ($config as $name => $pluginConfig) {
121
            $pluginId = 'httplug.plugin.'.$name;
122
123
            if ($pluginConfig['enabled']) {
124
                $def = $container->getDefinition($pluginId);
125
                $this->configurePluginByName($name, $def, $pluginConfig);
126
            } else {
127
                $container->removeDefinition($pluginId);
128
            }
129
        }
130
    }
131
132
    /**
133
     * @param string     $name
134
     * @param Definition $definition
135
     * @param array      $config
136
     */
137
    private function configurePluginByName($name, Definition $definition, array $config)
138
    {
139
        switch ($name) {
140
            case 'cache':
141
                $definition
142
                    ->replaceArgument(0, new Reference($config['cache_pool']))
143
                    ->replaceArgument(1, new Reference($config['stream_factory']))
144
                    ->replaceArgument(2, $config['config']);
145
                break;
146
            case 'cookie':
147
                $definition->replaceArgument(0, new Reference($config['cookie_jar']));
148
                break;
149
            case 'decoder':
150
                $definition->addArgument($config['use_content_encoding']);
151
                break;
152
            case 'history':
153
                $definition->replaceArgument(0, new Reference($config['journal']));
154
                break;
155
            case 'logger':
156
                $definition->replaceArgument(0, new Reference($config['logger']));
157
                if (!empty($config['formatter'])) {
158
                    $definition->replaceArgument(1, new Reference($config['formatter']));
159
                }
160
                break;
161
            case 'redirect':
162
                $definition
163
                    ->addArgument($config['preserve_header'])
164
                    ->addArgument($config['use_default_for_multiple']);
165
                break;
166
            case 'retry':
167
                $definition->addArgument($config['retry']);
168
                break;
169
            case 'stopwatch':
170
                $definition->replaceArgument(0, new Reference($config['stopwatch']));
171
                break;
172
        }
173
    }
174
175
    /**
176
     * @param ContainerBuilder $container
177
     * @param array            $config
178
     */
179
    private function configureAuthentication(ContainerBuilder $container, array $config)
180
    {
181
        foreach ($config as $name => $values) {
182
            $authServiceKey = sprintf('httplug.plugin.authentication.%s.auth', $name);
183
            switch ($values['type']) {
184
                case 'bearer':
185
                    $container->register($authServiceKey, Bearer::class)
186
                        ->addArgument($values['token']);
187
                    break;
188
                case 'basic':
189
                    $container->register($authServiceKey, BasicAuth::class)
190
                        ->addArgument($values['username'])
191
                        ->addArgument($values['password']);
192
                    break;
193
                case 'wsse':
194
                    $container->register($authServiceKey, Wsse::class)
195
                        ->addArgument($values['username'])
196
                        ->addArgument($values['password']);
197
                    break;
198
                case 'service':
199
                    $authServiceKey = $values['service'];
200
                    break;
201
                default:
202
                    throw new \LogicException(sprintf('Unknown authentication type: "%s"', $values['type']));
203
            }
204
205
            $container->register('httplug.plugin.authentication.'.$name, AuthenticationPlugin::class)
206
                ->addArgument(new Reference($authServiceKey));
207
        }
208
    }
209
210
    /**
211
     * @param ContainerBuilder $container
212
     * @param string           $name
213
     * @param array            $arguments
214
     * @param bool             $enableCollector
215
     */
216
    private function configureClient(ContainerBuilder $container, $name, array $arguments, $enableCollector)
217
    {
218
        $serviceId = 'httplug.client.'.$name;
219
        $def = $container->register($serviceId, DummyClient::class);
220
221
        // If there is no plugins nor should we use the data collector
222
        if (empty($arguments['plugins']) && !$enableCollector) {
223
            $def->setFactory([new Reference($arguments['factory']), 'createClient'])
224
                ->addArgument($arguments['config']);
225
        } else {
226
            $serviceIdDebugPlugin = $this->registerDebugPlugin($container, $name);
227
228
            $def->setFactory('Http\HttplugBundle\ClientFactory\PluginClientFactory::createPluginClient')
229
                ->addArgument(
230
                    array_map(
231
                        function ($id) {
232
                            return new Reference($id);
233
                        },
234
                        $arguments['plugins']
235
                    )
236
                )
237
                ->addArgument(new Reference($arguments['factory']))
238
                ->addArgument($arguments['config'])
239
                ->addArgument(['debug_plugins' => [new Reference($serviceIdDebugPlugin)]]);
240
241
            // tell the plugin journal what plugins we used
242
            $container->getDefinition('httplug.collector.plugin_journal')
243
                ->addMethodCall('setPlugins', [$name, $arguments['plugins']]);
244
        }
245
246
        /*
247
         * Decorate the client with clients from client-common
248
         */
249
250 View Code Duplication
        if ($arguments['flexible_client']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
251
            $container->register($serviceId.'.flexible', FlexibleHttpClient::class)
252
                ->addArgument(new Reference($serviceId.'.flexible.inner'))
253
                ->setPublic(false)
254
                ->setDecoratedService($serviceId);
255
        }
256
257 View Code Duplication
        if ($arguments['http_methods_client']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
258
            $container->register($serviceId.'.http_methods', HttpMethodsClient::class)
259
                ->setArguments([new Reference($serviceId.'.http_methods.inner'), new Reference('httplug.message_factory')])
260
                ->setPublic(false)
261
                ->setDecoratedService($serviceId);
262
        }
263
    }
264
265
    /**
266
     * Create a new plugin service for this client.
267
     *
268
     * @param ContainerBuilder $container
269
     * @param string           $name
270
     *
271
     * @return string
272
     */
273
    private function registerDebugPlugin(ContainerBuilder $container, $name)
274
    {
275
        $serviceIdDebugPlugin = 'httplug.client.'.$name.'.debug_plugin';
276
        $container->register($serviceIdDebugPlugin, DebugPlugin::class)
277
            ->addArgument(new Reference('httplug.collector.debug_collector'))
278
            ->addArgument($name)
279
            ->setPublic(false);
280
281
        return $serviceIdDebugPlugin;
282
    }
283
284
    /**
285
     * Make sure we inject the debug plugin for clients found by auto discovery.
286
     *
287
     * @param ContainerBuilder $container
288
     * @param array            $config
289
     */
290
    private function configureAutoDiscoveryClients(ContainerBuilder $container, array $config)
291
    {
292
        $httpClient = null;
293
        $asyncHttpClient = null;
294
295
        // Verify if any clients were specifucally set to function as auto discoverable.
296
        foreach ($config['clients'] as $name => $arguments) {
297
            if ($arguments['use_with_discovery'] === 'http_client') {
298
                if ($httpClient !== null) {
299
                    throw new \LogicException('Only one client can configured with "use_with_discovery: http_client".');
300
                }
301
                $httpClient = new Reference('http.client.'.$name);
302
            } elseif ($arguments['use_with_discovery'] === 'async_client') {
303
                if ($asyncHttpClient !== null) {
304
                    throw new \LogicException('Only one client can be configured with "use_with_discovery: async_client".');
305
                }
306
                $asyncHttpClient = new Reference('http.client.'.$name);
307
            }
308
        }
309
310
        if ($httpClient === null && $config['toolbar']['inject_debugger_for_discovered_http_client']) {
311
            // Use auto discovery
312
            $httpClient = $this->registerAutoDiscoverableClientWithDebugPlugin($container, HttpClientDiscovery::class, 'client');
313
        }
314
315
        if ($asyncHttpClient === null && $config['toolbar']['inject_debugger_for_discovered_async_client']) {
316
            // Use auto discovery
317
            $asyncHttpClient = $this->registerAutoDiscoverableClientWithDebugPlugin($container, HttpAsyncClientDiscovery::class, 'async_client');
318
        }
319
320
        $container->getDefinition('httplug.strategy')
321
            ->addArgument($httpClient)
322
            ->addArgument($asyncHttpClient);
323
    }
324
325
    /**
326
     * @param ContainerBuilder $container
327
     * @param $name
328
     *
329
     * @return Reference
330
     */
331
    private function registerAutoDiscoverableClientWithDebugPlugin(ContainerBuilder $container, $class, $name)
332
    {
333
        $definition = $container->register('httplug.auto_discovery_'.$name.'.pure', DummyClient::class);
334
        $definition
335
            ->setPublic(false)
336
            ->setFactory([$class, 'find']);
337
338
        $serviceIdDebugPlugin = $this->registerDebugPlugin($container, 'auto_discovery_'.$name);
339
        $container->register('httplug.auto_discovery_'.$name.'.plugin', PluginClient::class)
340
            ->setPublic(false)
341
            ->addArgument(new Reference('httplug.auto_discovery_'.$name.'.pure'))
342
            ->addArgument([])
343
            ->addArgument(['debug_plugins' => [new Reference($serviceIdDebugPlugin)]]);
344
345
        return new Reference('httplug.auto_discovery_'.$name.'.plugin');
346
    }
347
}
348