Completed
Pull Request — master (#102)
by Tobias
05:57
created

HttplugExtension::configureClient()   B

Complexity

Conditions 4
Paths 8

Size

Total Lines 59
Code Lines 33

Duplication

Lines 12
Ratio 20.34 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 5
Bugs 1 Features 3
Metric Value
c 5
b 1
f 3
dl 12
loc 59
ccs 0
cts 0
cp 0
rs 8.9846
cc 4
eloc 33
nc 8
nop 4
crap 20

How to fix   Long Method   

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\Discovery\HttpAsyncClientDiscovery;
9
use Http\Discovery\HttpClientDiscovery;
10
use Http\HttplugBundle\ClientFactory\DummyClient;
11
use Http\HttplugBundle\ClientFactory\PluginClientFactory;
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
    /**
30
     * {@inheritdoc}
31
     */
32 8
    public function load(array $configs, ContainerBuilder $container)
33
    {
34 8
        $configuration = $this->getConfiguration($configs, $container);
35 8
        $config = $this->processConfiguration($configuration, $configs);
1 ignored issue
show
Bug introduced by
It seems like $configuration defined by $this->getConfiguration($configs, $container) on line 34 can be null; however, Symfony\Component\Depend...:processConfiguration() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
36
37 8
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
38
39 8
        $loader->load('services.xml');
40 8
        $loader->load('plugins.xml');
41
42
        // Register default services
43 8
        foreach ($config['classes'] as $service => $class) {
44 8
            if (!empty($class)) {
45 1
                $container->register(sprintf('httplug.%s.default', $service), $class);
46 1
            }
47 8
        }
48
49
        // Set main aliases
50 8
        foreach ($config['main_alias'] as $type => $id) {
51 8
            $container->setAlias(sprintf('httplug.%s', $type), $id);
52 8
        }
53
54
        // Configure toolbar
55 8
        if ($config['toolbar']['enabled']) {
56 5
            $loader->load('data-collector.xml');
57
58 5
            if (!empty($config['toolbar']['formatter'])) {
59
                // Add custom formatter
60
                $container
61
                    ->getDefinition('httplug.collector.debug_collector')
62
                    ->replaceArgument(0, new Reference($config['toolbar']['formatter']))
63
                ;
64
            }
65
66
            $container
67 5
                ->getDefinition('httplug.formatter.full_http_message')
68 5
                ->addArgument($config['toolbar']['captured_body_length'])
69
            ;
70 5
        }
71
72 8
        $this->configurePlugins($container, $config['plugins']);
73 8
        $this->configureClients($container, $config);
74 8
        $this->configureAutoDiscoveryClients($container, $config);
75 8
    }
76
77
    /**
78
     * Configure client services.
79
     *
80
     * @param ContainerBuilder $container
81
     * @param array            $config
82
     */
83 8
    private function configureClients(ContainerBuilder $container, array $config)
84
    {
85 8
        $first = null;
86
87 8
        foreach ($config['clients'] as $name => $arguments) {
88 3
            if ($first === null) {
89
                // Save the name of the first configurated client.
90 3
                $first = $name;
91 3
            }
92
93 3
            $this->configureClient($container, $name, $arguments, $config['toolbar']['enabled']);
94 8
        }
95
96
        // If we have clients configured
97 8
        if ($first !== null) {
98
            // If we do not have a client named 'default'
99 3
            if (!isset($config['clients']['default'])) {
100
                // Alias the first client to httplug.client.default
101 3
                $container->setAlias('httplug.client.default', 'httplug.client.'.$first);
102 3
            }
103 3
        }
104 8
    }
105
106
    /**
107
     * @param ContainerBuilder $container
108
     * @param array            $config
109
     */
110 8
    private function configurePlugins(ContainerBuilder $container, array $config)
111
    {
112 8
        if (!empty($config['authentication'])) {
113
            $this->configureAuthentication($container, $config['authentication']);
114
        }
115 8
        unset($config['authentication']);
116
117 8
        foreach ($config as $name => $pluginConfig) {
118 8
            $pluginId = 'httplug.plugin.'.$name;
119
120 8
            if ($pluginConfig['enabled']) {
121 8
                $def = $container->getDefinition($pluginId);
122 8
                $this->configurePluginByName($name, $def, $pluginConfig);
123 8
            } else {
124 8
                $container->removeDefinition($pluginId);
125
            }
126 8
        }
127 8
    }
128
129
    /**
130
     * @param string     $name
131
     * @param Definition $definition
132
     * @param array      $config
133
     */
134 8
    private function configurePluginByName($name, Definition $definition, array $config)
135
    {
136
        switch ($name) {
137 8
            case 'cache':
138
                $definition
139
                    ->replaceArgument(0, new Reference($config['cache_pool']))
140
                    ->replaceArgument(1, new Reference($config['stream_factory']))
141
                    ->replaceArgument(2, $config['config']);
142
                break;
143 8
            case 'cookie':
144
                $definition->replaceArgument(0, new Reference($config['cookie_jar']));
145
                break;
146 8
            case 'decoder':
147 8
                $definition->addArgument($config['use_content_encoding']);
148 8
                break;
149 8
            case 'history':
150
                $definition->replaceArgument(0, new Reference($config['journal']));
151
                break;
152 8
            case 'logger':
153 8
                $definition->replaceArgument(0, new Reference($config['logger']));
154 8
                if (!empty($config['formatter'])) {
155
                    $definition->replaceArgument(1, new Reference($config['formatter']));
156
                }
157 8
                break;
158 8
            case 'redirect':
159
                $definition
160 8
                    ->addArgument($config['preserve_header'])
161 8
                    ->addArgument($config['use_default_for_multiple']);
162 8
                break;
163 8
            case 'retry':
164 8
                $definition->addArgument($config['retry']);
165 8
                break;
166 8
            case 'stopwatch':
167 8
                $definition->replaceArgument(0, new Reference($config['stopwatch']));
168 8
                break;
169
        }
170 8
    }
171
172
    /**
173
     * @param ContainerBuilder $container
174
     * @param array            $config
175
     */
176
    private function configureAuthentication(ContainerBuilder $container, array $config)
177
    {
178
        foreach ($config as $name => $values) {
179
            $authServiceKey = sprintf('httplug.plugin.authentication.%s.auth', $name);
180
            switch ($values['type']) {
181
                case 'bearer':
182
                    $container->register($authServiceKey, Bearer::class)
183
                        ->addArgument($values['token']);
184
                    break;
185
                case 'basic':
186
                    $container->register($authServiceKey, BasicAuth::class)
187
                        ->addArgument($values['username'])
188
                        ->addArgument($values['password']);
189
                    break;
190
                case 'wsse':
191
                    $container->register($authServiceKey, Wsse::class)
192
                        ->addArgument($values['username'])
193
                        ->addArgument($values['password']);
194
                    break;
195
                case 'service':
196
                    $authServiceKey = $values['service'];
197
                    break;
198
                default:
199
                    throw new \LogicException(sprintf('Unknown authentication type: "%s"', $values['type']));
200
            }
201
202
            $container->register('httplug.plugin.authentication.'.$name, AuthenticationPlugin::class)
203
                ->addArgument(new Reference($authServiceKey));
204
        }
205
    }
206
207
    /**
208
     * @param ContainerBuilder $container
209
     * @param string           $name
210
     * @param array            $arguments
211
     * @param bool             $profiling
212
     */
213
    private function configureClient(ContainerBuilder $container, $name, array $arguments, $profiling)
214
    {
215
        $serviceId = 'httplug.client.'.$name;
216
217
        $pluginClientOptions = [];
218
219
        if ($profiling) {
220
            // Add the stopwatch plugin
221
            array_unshift($arguments['plugins'], 'httplug.plugin.stopwatch');
222
223
            // Tell the plugin journal what plugins we used
224
            $container
225
                ->getDefinition('httplug.collector.plugin_journal')
226
                ->addMethodCall('setPlugins', [$name, $arguments['plugins']])
227
            ;
228
229
            $debugPluginServiceId = $this->registerDebugPlugin($container, $serviceId);
230
231
            $pluginClientOptions['debug_plugins'] = [new Reference($debugPluginServiceId)];
232
        }
233
234
        $container
235
            ->register($serviceId, DummyClient::class)
236
            ->setFactory([PluginClientFactory::class, 'createPluginClient'])
237
            ->addArgument(
238
                array_map(
239
                    function ($id) {
240
                        return new Reference($id);
241
                    },
242
                    $arguments['plugins']
243
                )
244
            )
245
            ->addArgument(new Reference($arguments['factory']))
246
            ->addArgument($arguments['config'])
247
            ->addArgument($pluginClientOptions)
248
        ;
249
250
251
        /*
252
         * Decorate the client with clients from client-common
253
         */
254 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...
255
            $container
256
                ->register($serviceId.'.flexible', FlexibleHttpClient::class)
257
                ->addArgument(new Reference($serviceId.'.flexible.inner'))
258
                ->setPublic(false)
259
                ->setDecoratedService($serviceId)
260
            ;
261
        }
262
263 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...
264
            $container
265
                ->register($serviceId.'.http_methods', HttpMethodsClient::class)
266
                ->setArguments([new Reference($serviceId.'.http_methods.inner'), new Reference('httplug.message_factory')])
267
                ->setPublic(false)
268
                ->setDecoratedService($serviceId)
269
            ;
270
        }
271
    }
272
273
    /**
274
     * Make the user can select what client is used for auto discovery. If none is provided, a service will be created
275
     * by finding a client using auto discovery.
276
     *
277
     * @param ContainerBuilder $container
278
     * @param array            $config
279
     */
280
    private function configureAutoDiscoveryClients(ContainerBuilder $container, array $config)
281
    {
282
        $httpClient = $config['discovery']['client'];
283
284 View Code Duplication
        if (!empty($httpClient)) {
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...
285
            if ($httpClient === 'auto') {
286
                $httpClient = $this->registerAutoDiscoverableClient(
287
                    $container,
288
                    'auto_discovered_client',
289
                    [HttpClientDiscovery::class, 'find'],
290
                    $config['toolbar']['enabled']
291
                );
292
            }
293
294
            $httpClient = new Reference($httpClient);
295
        }
296
297
        $asyncHttpClient = $config['discovery']['async_client'];
298
299 View Code Duplication
        if (!empty($asyncHttpClient)) {
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...
300
            if ($asyncHttpClient === 'auto') {
301
                $asyncHttpClient = $this->registerAutoDiscoverableClient(
302
                    $container,
303
                    'auto_discovered_async',
304
                    [HttpAsyncClientDiscovery::class, 'find'],
305
                    $config['toolbar']['enabled']
306
                );
307
            }
308
309
            $asyncHttpClient = new Reference($asyncHttpClient);
310
        }
311
312
        $container
313
            ->getDefinition('httplug.strategy')
314
            ->addArgument($httpClient)
315
            ->addArgument($asyncHttpClient)
316
        ;
317
    }
318
319
    /**
320
     * Find a client with auto discovery and return a service Reference to it.
321
     *
322
     * @param ContainerBuilder $container
323
     * @param string           $name
324
     * @param callable         $factory
325
     * @param bool             $profiling
326
     *
327
     * @return string service id
328
     */
329
    private function registerAutoDiscoverableClient(ContainerBuilder $container, $name, $factory, $profiling)
330
    {
331
        $serviceId = 'httplug.auto_discovery.'.$name;
332
333
        $pluginClientOptions = [];
334
335
        if ($profiling) {
336
            // Tell the plugin journal what plugins we used
337
            $container
338
                ->getDefinition('httplug.collector.plugin_journal')
339
                ->addMethodCall('setPlugins', [$name, ['httplug.plugin.stopwatch']])
340
            ;
341
342
            $debugPluginServiceId = $this->registerDebugPlugin($container, $serviceId);
343
344
            $pluginClientOptions['debug_plugins'] = [new Reference($debugPluginServiceId)];
345
        }
346
347
        $container
348
            ->register($serviceId, DummyClient::class)
349
            ->setFactory([PluginClientFactory::class, 'createPluginClient'])
350
            ->setArguments([[new Reference('httplug.plugin.stopwatch')], $factory, [], $pluginClientOptions])
351
        ;
352
353
        return $serviceId;
354
    }
355
356
    /**
357
     * Create a new plugin service for this client.
358
     *
359
     * @param ContainerBuilder $container
360
     * @param string           $serviceId
361
     *
362
     * @return string
363
     */
364
    private function registerDebugPlugin(ContainerBuilder $container, $serviceId)
365
    {
366
        $serviceIdDebugPlugin = $serviceId.'.debug_plugin';
367
368
        $container
369
            ->register($serviceIdDebugPlugin, DebugPlugin::class)
370
            ->addArgument(new Reference('httplug.collector.debug_collector'))
371
            ->addArgument(substr($serviceId, strrpos($serviceId, '.') + 1))
372
            ->setPublic(false)
373
        ;
374
375
        return $serviceIdDebugPlugin;
376
    }
377
378
    /**
379
     * {@inheritdoc}
380
     */
381
    public function getConfiguration(array $config, ContainerBuilder $container)
382
    {
383
        return new Configuration($container->getParameter('kernel.debug'));
384
    }
385
}
386