Completed
Pull Request — master (#87)
by Tobias
10:23
created

HttplugExtension::configureAutoDiscoveryClients()   D

Complexity

Conditions 10
Paths 38

Size

Total Lines 39
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 110

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 39
rs 4.8196
ccs 0
cts 0
cp 0
cc 10
eloc 21
nc 38
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\Client\HttpAsyncClient;
10
use Http\Client\HttpClient;
11
use Http\Discovery\HttpAsyncClientDiscovery;
12
use Http\Discovery\HttpClientDiscovery;
13
use Http\HttplugBundle\ClientFactory\DummyClient;
14
use Http\HttplugBundle\Collector\DebugPlugin;
15
use Http\Message\Authentication\BasicAuth;
16
use Http\Message\Authentication\Bearer;
17
use Http\Message\Authentication\Wsse;
18
use Symfony\Component\Config\FileLocator;
19
use Symfony\Component\DependencyInjection\ContainerBuilder;
20
use Symfony\Component\DependencyInjection\Definition;
21
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
22
use Symfony\Component\DependencyInjection\Reference;
23
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
24
25
/**
26
 * @author David Buchmann <[email protected]>
27
 * @author Tobias Nyholm <[email protected]>
28
 */
29 3
class HttplugExtension extends Extension
30
{
31 3
    /**
32 3
     * {@inheritdoc}
33
     */
34 3
    public function load(array $configs, ContainerBuilder $container)
35
    {
36 3
        $configuration = $this->getConfiguration($configs, $container);
37 3
        $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...
38
39 3
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
40 3
41
        $loader->load('services.xml');
42
        $loader->load('plugins.xml');
43
44
        $enabled = is_bool($config['toolbar']['enabled']) ? $config['toolbar']['enabled'] : $container->hasParameter('kernel.debug') && $container->getParameter('kernel.debug');
45
        if ($enabled) {
46
            $loader->load('data-collector.xml');
47
            $config['_inject_collector_plugin'] = true;
48
49
            if (!empty($config['toolbar']['formatter'])) {
50 3
                // Add custom formatter
51 3
                $container->getDefinition('httplug.collector.debug_collector')
52 1
                    ->replaceArgument(0, new Reference($config['toolbar']['formatter']));
53 1
            }
54 3
55
            $container->getDefinition('httplug.formatter.full_http_message')
56
                ->addArgument($config['toolbar']['captured_body_length']);
57 3
        }
58 3
59 3
        foreach ($config['classes'] as $service => $class) {
60
            if (!empty($class)) {
61 3
                $container->register(sprintf('httplug.%s.default', $service), $class);
62 3
            }
63 3
        }
64
65
        // Set main aliases
66
        foreach ($config['main_alias'] as $type => $id) {
67
            $container->setAlias(sprintf('httplug.%s', $type), $id);
68
        }
69
70
        $this->configurePlugins($container, $config['plugins']);
71 3
        $this->configureClients($container, $config);
72
        $this->configureAutoDiscoveryClients($container, $config);
73
    }
74 3
75
    /**
76 3
     * Configure client services.
77
     *
78
     * @param ContainerBuilder $container
79
     * @param array            $config
80
     */
81
    private function configureClients(ContainerBuilder $container, array $config)
82
    {
83
        // If we have a client named 'default'
84
        $first = isset($config['clients']['default']) ? 'default' : null;
85
86
        foreach ($config['clients'] as $name => $arguments) {
87 3
            if ($first === null) {
88
                // Save the name of the first configurated client.
89
                $first = $name;
90 3
            }
91
92
            $this->configureClient($container, $name, $arguments, $config['_inject_collector_plugin']);
93
        }
94
95 3
        // If we have clients configured
96
        if ($first !== null) {
97
            if ($first !== 'default') {
98
                // Alias the first client to httplug.client.default
99
                $container->setAlias('httplug.client.default', 'httplug.client.'.$first);
100
            }
101
        } elseif (isset($config['_inject_collector_plugin'])) {
102
            $serviceIdDebugPlugin = $this->registerDebugPlugin($container, 'default');
103
            // No client was configured. Make sure to configure the auto discovery client with the PluginClient.
104
            $container->register('httplug.client', PluginClient::class)
105
                ->addArgument(new Reference('httplug.client.default'))
106
                ->addArgument([])
107
                ->addArgument(['debug_plugins' => [new Reference($serviceIdDebugPlugin)]]);
108
        }
109
    }
110
111
    /**
112
     * @param ContainerBuilder $container
113
     * @param array            $config
114
     */
115
    private function configurePlugins(ContainerBuilder $container, array $config)
116
    {
117
        if (!empty($config['authentication'])) {
118
            $this->configureAuthentication($container, $config['authentication']);
119
        }
120
        unset($config['authentication']);
121
122
        foreach ($config as $name => $pluginConfig) {
123
            $pluginId = 'httplug.plugin.'.$name;
124
125
            if ($pluginConfig['enabled']) {
126
                $def = $container->getDefinition($pluginId);
127
                $this->configurePluginByName($name, $def, $pluginConfig);
128
            } else {
129
                $container->removeDefinition($pluginId);
130
            }
131
        }
132
    }
133
134
    /**
135
     * @param string     $name
136
     * @param Definition $definition
137
     * @param array      $config
138
     */
139
    private function configurePluginByName($name, Definition $definition, array $config)
140
    {
141
        switch ($name) {
142
            case 'cache':
143
                $definition
144
                    ->replaceArgument(0, new Reference($config['cache_pool']))
145
                    ->replaceArgument(1, new Reference($config['stream_factory']))
146
                    ->replaceArgument(2, $config['config']);
147
                break;
148
            case 'cookie':
149
                $definition->replaceArgument(0, new Reference($config['cookie_jar']));
150
                break;
151
            case 'decoder':
152
                $definition->addArgument($config['use_content_encoding']);
153
                break;
154
            case 'history':
155
                $definition->replaceArgument(0, new Reference($config['journal']));
156
                break;
157
            case 'logger':
158
                $definition->replaceArgument(0, new Reference($config['logger']));
159
                if (!empty($config['formatter'])) {
160
                    $definition->replaceArgument(1, new Reference($config['formatter']));
161
                }
162
                break;
163
            case 'redirect':
164
                $definition
165
                    ->addArgument($config['preserve_header'])
166
                    ->addArgument($config['use_default_for_multiple']);
167
                break;
168
            case 'retry':
169
                $definition->addArgument($config['retry']);
170
                break;
171
            case 'stopwatch':
172
                $definition->replaceArgument(0, new Reference($config['stopwatch']));
173
                break;
174
        }
175
    }
176
177
    /**
178
     * @param ContainerBuilder $container
179
     * @param array            $config
180
     */
181
    private function configureAuthentication(ContainerBuilder $container, array $config)
182
    {
183
        foreach ($config as $name => $values) {
184
            $authServiceKey = sprintf('httplug.plugin.authentication.%s.auth', $name);
185
            switch ($values['type']) {
186
                case 'bearer':
187
                    $container->register($authServiceKey, Bearer::class)
188
                        ->addArgument($values['token']);
189
                    break;
190
                case 'basic':
191
                    $container->register($authServiceKey, BasicAuth::class)
192
                        ->addArgument($values['username'])
193
                        ->addArgument($values['password']);
194
                    break;
195
                case 'wsse':
196
                    $container->register($authServiceKey, Wsse::class)
197
                        ->addArgument($values['username'])
198
                        ->addArgument($values['password']);
199
                    break;
200
                case 'service':
201
                    $authServiceKey = $values['service'];
202
                    break;
203
                default:
204
                    throw new \LogicException(sprintf('Unknown authentication type: "%s"', $values['type']));
205
            }
206
207
            $container->register('httplug.plugin.authentication.'.$name, AuthenticationPlugin::class)
208
                ->addArgument(new Reference($authServiceKey));
209
        }
210
    }
211
212
    /**
213
     * @param ContainerBuilder $container
214
     * @param string           $name
215
     * @param array            $arguments
216
     * @param bool             $enableCollector
217
     */
218
    private function configureClient(ContainerBuilder $container, $name, array $arguments, $enableCollector)
219
    {
220
        $serviceId = 'httplug.client.'.$name;
221
        $def = $container->register($serviceId, DummyClient::class);
222
223
        // If there is no plugins nor should we use the data collector
224
        if (empty($arguments['plugins']) && !$enableCollector) {
225
            $def->setFactory([new Reference($arguments['factory']), 'createClient'])
226
                ->addArgument($arguments['config']);
227
        } else {
228
            $serviceIdDebugPlugin = $this->registerDebugPlugin($container, $name);
229
230
            $def->setFactory('Http\HttplugBundle\ClientFactory\PluginClientFactory::createPluginClient')
231
                ->addArgument(
232
                    array_map(
233
                        function ($id) {
234
                            return new Reference($id);
235
                        },
236
                        $arguments['plugins']
237
                    )
238
                )
239
                ->addArgument(new Reference($arguments['factory']))
240
                ->addArgument($arguments['config'])
241
                ->addArgument(['debug_plugins' => [new Reference($serviceIdDebugPlugin)]]);
242
243
            // tell the plugin journal what plugins we used
244
            $container->getDefinition('httplug.collector.plugin_journal')
245
                ->addMethodCall('setPlugins', [$name, $arguments['plugins']]);
246
        }
247
248
249
        /*
250
         * Decorate the client with clients from client-common
251
         */
252
253 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...
254
            $container->register($serviceId.'.flexible', FlexibleHttpClient::class)
255
                ->addArgument(new Reference($serviceId.'.flexible.inner'))
256
                ->setPublic(false)
257
                ->setDecoratedService($serviceId);
258
        }
259
260 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...
261
            $container->register($serviceId.'.http_methods', HttpMethodsClient::class)
262
                ->setArguments([new Reference($serviceId.'.http_methods.inner'), new Reference('httplug.message_factory')])
263
                ->setPublic(false)
264
                ->setDecoratedService($serviceId);
265
        }
266
    }
267
268
    /**
269
     * Create a new plugin service for this client.
270
     *
271
     * @param ContainerBuilder $container
272
     * @param string           $name
273
     *
274
     * @return string
275
     */
276
    private function registerDebugPlugin(ContainerBuilder $container, $name)
277
    {
278
        $serviceIdDebugPlugin = 'httplug.client.'.$name.'.debug_plugin';
279
        $container->register($serviceIdDebugPlugin, DebugPlugin::class)
280
            ->addArgument(new Reference('httplug.collector.debug_collector'))
281
            ->addArgument($name)
282
            ->setPublic(false);
283
284
        return $serviceIdDebugPlugin;
285
    }
286
287
    /**
288
     * Make sure we inject the debug plugin for clients found by auto discovery.
289
     *
290
     * @param ContainerBuilder $container
291
     * @param array $config
292
     */
293
    private function configureAutoDiscoveryClients(ContainerBuilder $container, array $config)
294
    {
295
        $httpClient = null;
296
        $asyncHttpClient = null;
297
298
        // Verify if any clients were specifucally set to function as auto discoverable.
299
        foreach ($config['clients'] as $name => $arguments) {
300
            if ($arguments['use_with_discovery'] === 'http_client') {
301
                if ($httpClient !== null) {
302
                    throw new \LogicException('Only one client can configured with "use_with_discovery: http_client".');
303
                }
304
                $httpClient = new Reference('httplug.client.'.$name);
305
            } elseif ($arguments['use_with_discovery'] === 'async_client') {
306
                if ($asyncHttpClient !== null) {
307
                    throw new \LogicException('Only one client can be configured with "use_with_discovery: async_client".');
308
                }
309
                $asyncHttpClient = new Reference('httplug.client.'.$name);
310
            }
311
        }
312
313
        if ($httpClient === null) {
314
            // Use auto discovery
315
            if ($config['toolbar']['profile_discovered_client']) {
316
                $httpClient = $this->registerAutoDiscoverableClientWithDebugPlugin($container, 'client');
317
            }
318
        }
319
320
        if ($asyncHttpClient === null) {
321
            // Use auto discovery
322
            if ($config['toolbar']['profile_discovered_async_client']) {
323
                $asyncHttpClient = $this->registerAutoDiscoverableClientWithDebugPlugin($container, 'async_client');
324
            }
325
        }
326
327
328
        $container->getDefinition('httplug.strategy')
329
            ->addArgument($httpClient)
330
            ->addArgument($asyncHttpClient);
331
    }
332
333
    /**
334
     * @param ContainerBuilder $container
335
     * @param $name
336
     *
337
     * @return Reference
338
     */
339
    private function registerAutoDiscoverableClientWithDebugPlugin(ContainerBuilder $container, $name)
340
    {
341
        $definition = $container->register('httplug.auto_discovery_'.$name.'.pure', DummyClient::class);
342
        $definition->setPublic(false);
343
        $definition->setFactory([HttpAsyncClientDiscovery::class, 'find']);
344
345
        $serviceIdDebugPlugin = $this->registerDebugPlugin($container, 'auto_discovery_'.$name);
346
        $container->register('httplug.auto_discovery_'.$name.'.plugin', PluginClient::class)
347
            ->setPublic(false)
348
            ->addArgument(new Reference('httplug.auto_discovery_'.$name.'.pure'))
349
            ->addArgument([])
350
            ->addArgument(['debug_plugins' => [new Reference($serviceIdDebugPlugin)]]);
351
352
        return new Reference('httplug.auto_discovery_'.$name.'.plugin');
353
    }
354
}
355