Completed
Push — master ( b17853...f56531 )
by David
09:10
created

HttplugExtension   B

Complexity

Total Complexity 40

Size/Duplication

Total Lines 223
Duplicated Lines 5.38 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 54.35%

Importance

Changes 13
Bugs 2 Features 5
Metric Value
wmc 40
c 13
b 2
f 5
lcom 1
cbo 6
dl 12
loc 223
ccs 25
cts 46
cp 0.5435
rs 8.2608

6 Methods

Rating   Name   Duplication   Size   Complexity  
C load() 0 34 8
C configureClients() 0 28 8
A configurePlugins() 0 18 4
D configurePluginByName() 0 37 10
B configureAuthentication() 0 30 6
B configureClient() 12 41 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like HttplugExtension often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use HttplugExtension, and based on these observations, apply Extract Interface, too.

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\HttplugBundle\ClientFactory\DummyClient;
10
use Http\Message\Authentication\BasicAuth;
11
use Http\Message\Authentication\Bearer;
12
use Http\Message\Authentication\Wsse;
13
use Symfony\Component\Config\FileLocator;
14
use Symfony\Component\DependencyInjection\ContainerBuilder;
15
use Symfony\Component\DependencyInjection\Definition;
16
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
17
use Symfony\Component\DependencyInjection\Reference;
18
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
19
20
/**
21
 * @author David Buchmann <[email protected]>
22
 * @author Tobias Nyholm <[email protected]>
23
 */
24
class HttplugExtension extends Extension
25
{
26
    /**
27 3
     * {@inheritdoc}
28
     */
29 3
    public function load(array $configs, ContainerBuilder $container)
30 3
    {
31
        $configuration = $this->getConfiguration($configs, $container);
32 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...
33
34 3
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
35 3
36
        $loader->load('services.xml');
37 3
        $loader->load('plugins.xml');
38 3
39
        $enabled = is_bool($config['toolbar']['enabled']) ? $config['toolbar']['enabled'] : $container->hasParameter('kernel.debug') && $container->getParameter('kernel.debug');
40
        if ($enabled) {
41
            $loader->load('data-collector.xml');
42
            $config['_inject_collector_plugin'] = true;
43
44
            if (!empty($config['toolbar']['formatter'])) {
45
                $container->getDefinition('httplug.collector.message_journal')
46
                    ->replaceArgument(0, new Reference($config['toolbar']['formatter']));
47
            }
48 3
        }
49 3
50 1
        foreach ($config['classes'] as $service => $class) {
51 1
            if (!empty($class)) {
52 3
                $container->register(sprintf('httplug.%s.default', $service), $class);
53
            }
54 3
        }
55 3
56 3
        foreach ($config['main_alias'] as $type => $id) {
57
            $container->setAlias(sprintf('httplug.%s', $type), $id);
58 3
        }
59 3
60 3
        $this->configurePlugins($container, $config['plugins']);
61
        $this->configureClients($container, $config);
62
    }
63
64
    /**
65
     * Configure client services.
66
     *
67
     * @param ContainerBuilder $container
68 3
     * @param array            $config
69
     */
70 3
    private function configureClients(ContainerBuilder $container, array $config)
71 3
    {
72
        $first = isset($config['clients']['default']) ? 'default' : null;
73
        foreach ($config['clients'] as $name => $arguments) {
74
            if ($first === null) {
75
                $first = $name;
76
            }
77
78
            if (isset($config['_inject_collector_plugin'])) {
79
                array_unshift($arguments['plugins'], 'httplug.collector.history_plugin');
80
            }
81
82
            $this->configureClient($container, $name, $arguments);
83
        }
84
85
        // If we have clients configured
86
        if ($first !== null) {
87
            if ($first !== 'default') {
88
                // Alias the first client to httplug.client.default
89
                $container->setAlias('httplug.client.default', 'httplug.client.'.$first);
90
            }
91
        } elseif (isset($config['_inject_collector_plugin'])) {
92
            // No client was configured. Make sure to inject history plugin to the auto discovery client.
93 3
            $container->register('httplug.client', PluginClient::class)
94
                ->addArgument(new Reference('httplug.client.default'))
95
                ->addArgument([new Reference('httplug.collector.history_plugin')]);
96 3
        }
97
    }
98
99
    /**
100
     * @param ContainerBuilder $container
101 3
     * @param array            $config
102
     */
103
    private function configurePlugins(ContainerBuilder $container, array $config)
104
    {
105
        if (!empty($config['authentication'])) {
106
            $this->configureAuthentication($container, $config['authentication']);
107
        }
108
        unset($config['authentication']);
109
110
        foreach ($config as $name => $pluginConfig) {
111
            $pluginId = 'httplug.plugin.'.$name;
112
113
            if ($pluginConfig['enabled']) {
114
                $def = $container->getDefinition($pluginId);
115
                $this->configurePluginByName($name, $def, $pluginConfig);
116
            } else {
117
                $container->removeDefinition($pluginId);
118
            }
119
        }
120
    }
121
122
    /**
123
     * @param string     $name
124
     * @param Definition $definition
125
     * @param array      $config
126
     */
127
    private function configurePluginByName($name, Definition $definition, array $config)
128
    {
129
        switch ($name) {
130
            case 'cache':
131
                $definition
132
                    ->replaceArgument(0, new Reference($config['cache_pool']))
133
                    ->replaceArgument(1, new Reference($config['stream_factory']))
134
                    ->replaceArgument(2, $config['config']);
135
                break;
136
            case 'cookie':
137
                $definition->replaceArgument(0, new Reference($config['cookie_jar']));
138
                break;
139
            case 'decoder':
140
                $definition->addArgument($config['use_content_encoding']);
141
                break;
142
            case 'history':
143
                $definition->replaceArgument(0, new Reference($config['journal']));
144
                break;
145
            case 'logger':
146
                $definition->replaceArgument(0, new Reference($config['logger']));
147
                if (!empty($config['formatter'])) {
148
                    $definition->replaceArgument(1, new Reference($config['formatter']));
149
                }
150
                break;
151
            case 'redirect':
152
                $definition
153
                    ->addArgument($config['preserve_header'])
154
                    ->addArgument($config['use_default_for_multiple']);
155
                break;
156
            case 'retry':
157
                $definition->addArgument($config['retry']);
158
                break;
159
            case 'stopwatch':
160
                $definition->replaceArgument(0, new Reference($config['stopwatch']));
161
                break;
162
        }
163
    }
164
165
    /**
166
     * @param ContainerBuilder $container
167
     * @param array            $config
168
     */
169
    private function configureAuthentication(ContainerBuilder $container, array $config)
170
    {
171
        foreach ($config as $name => $values) {
172
            $authServiceKey = sprintf('httplug.plugin.authentication.%s.auth', $name);
173
            switch ($values['type']) {
174
                case 'bearer':
175
                    $container->register($authServiceKey, Bearer::class)
176
                        ->addArgument($values['token']);
177
                    break;
178
                case 'basic':
179
                    $container->register($authServiceKey, BasicAuth::class)
180
                        ->addArgument($values['username'])
181
                        ->addArgument($values['password']);
182
                    break;
183
                case 'wsse':
184
                    $container->register($authServiceKey, Wsse::class)
185
                        ->addArgument($values['username'])
186
                        ->addArgument($values['password']);
187
                    break;
188
                case 'service':
189
                    $authServiceKey = $values['service'];
190
                    break;
191
                default:
192
                    throw new \LogicException(sprintf('Unknown authentication type: "%s"', $values['type']));
193
            }
194
195
            $container->register('httplug.plugin.authentication.'.$name, AuthenticationPlugin::class)
196
                ->addArgument(new Reference($authServiceKey));
197
        }
198
    }
199
200
    /**
201
     * @param ContainerBuilder $container
202
     * @param string           $name
203
     * @param array            $arguments
204
     */
205
    private function configureClient(ContainerBuilder $container, $name, array $arguments)
206
    {
207
        $serviceId = 'httplug.client.'.$name;
208
        $def = $container->register($serviceId, DummyClient::class);
209
210
        if (empty($arguments['plugins'])) {
211
            $def->setFactory([new Reference($arguments['factory']), 'createClient'])
212
                ->addArgument($arguments['config']);
213
        } else {
214
            $def->setFactory('Http\HttplugBundle\ClientFactory\PluginClientFactory::createPluginClient')
215
                ->addArgument(
216
                    array_map(
217
                        function ($id) {
218
                            return new Reference($id);
219
                        },
220
                        $arguments['plugins']
221
                    )
222
                )
223
                ->addArgument(new Reference($arguments['factory']))
224
                ->addArgument($arguments['config']);
225
        }
226
227
228
        /*
229
         * Decorate the client with clients from client-common
230
         */
231
232 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...
233
            $container->register($serviceId.'.flexible', FlexibleHttpClient::class)
234
                ->addArgument(new Reference($serviceId.'.flexible.inner'))
235
                ->setPublic(false)
236
                ->setDecoratedService($serviceId);
237
        }
238
239 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...
240
            $container->register($serviceId.'.http_methods', HttpMethodsClient::class)
241
                ->setArguments([new Reference($serviceId.'.http_methods.inner'), new Reference('httplug.message_factory')])
242
                ->setPublic(false)
243
                ->setDecoratedService($serviceId);
244
        }
245
    }
246
}
247