Completed
Pull Request — master (#72)
by Márk
08:14
created

HttplugExtension   B

Complexity

Total Complexity 40

Size/Duplication

Total Lines 197
Duplicated Lines 9.14 %

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 18
loc 197
ccs 25
cts 46
cp 0.5435
rs 8.2608

5 Methods

Rating   Name   Duplication   Size   Complexity  
D configureClients() 0 40 9
C load() 0 34 8
A configurePlugins() 0 18 4
C configurePluginByName() 18 46 13
B configureAuthentication() 0 30 6

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\Plugin\AuthenticationPlugin;
6
use Http\Client\Common\PluginClient;
7
use Http\HttplugBundle\ClientFactory\DummyClient;
8
use Http\Message\Authentication\BasicAuth;
9
use Http\Message\Authentication\Bearer;
10
use Http\Message\Authentication\Wsse;
11
use Symfony\Component\Config\FileLocator;
12
use Symfony\Component\DependencyInjection\ContainerBuilder;
13
use Symfony\Component\DependencyInjection\Definition;
14
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
15
use Symfony\Component\DependencyInjection\Reference;
16
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
17
18
/**
19
 * @author David Buchmann <[email protected]>
20
 * @author Tobias Nyholm <[email protected]>
21
 */
22
class HttplugExtension extends Extension
23
{
24
    /**
25
     * {@inheritdoc}
26
     */
27 3
    public function load(array $configs, ContainerBuilder $container)
28
    {
29 3
        $configuration = $this->getConfiguration($configs, $container);
30 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...
31
32 3
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
33
34 3
        $loader->load('services.xml');
35 3
        $loader->load('plugins.xml');
36
37 3
        $enabled = is_bool($config['toolbar']['enabled']) ? $config['toolbar']['enabled'] : $container->hasParameter('kernel.debug') && $container->getParameter('kernel.debug');
38 3
        if ($enabled) {
39
            $loader->load('data-collector.xml');
40
            $config['_inject_collector_plugin'] = true;
41
42
            if (!empty($config['toolbar']['formatter'])) {
43
                $container->getDefinition('httplug.collector.message_journal')
44
                    ->replaceArgument(0, new Reference($config['toolbar']['formatter']));
45
            }
46
        }
47
48 3
        foreach ($config['classes'] as $service => $class) {
49 3
            if (!empty($class)) {
50 1
                $container->register(sprintf('httplug.%s.default', $service), $class);
51 1
            }
52 3
        }
53
54 3
        foreach ($config['main_alias'] as $type => $id) {
55 3
            $container->setAlias(sprintf('httplug.%s', $type), $id);
56 3
        }
57
58 3
        $this->configurePlugins($container, $config['plugins']);
59 3
        $this->configureClients($container, $config);
60 3
    }
61
62
    /**
63
     * Configure client services.
64
     *
65
     * @param ContainerBuilder $container
66
     * @param array            $config
67
     */
68 3
    private function configureClients(ContainerBuilder $container, array $config)
69
    {
70 3
        $first = isset($config['clients']['default']) ? 'default' : null;
71 3
        foreach ($config['clients'] as $name => $arguments) {
72
            if ($first === null) {
73
                $first = $name;
74
            }
75
76
            if (isset($config['_inject_collector_plugin'])) {
77
                array_unshift($arguments['plugins'], 'httplug.collector.history_plugin');
78
            }
79
80
            $def = $container->register('httplug.client.'.$name, DummyClient::class);
81
82
            if (empty($arguments['plugins'])) {
83
                $def->setFactory([new Reference($arguments['factory']), 'createClient'])
84
                    ->addArgument($arguments['config']);
85
            } else {
86
                $def->setFactory('Http\HttplugBundle\ClientFactory\PluginClientFactory::createPluginClient')
87
                    ->addArgument(array_map(function ($id) {
88
                        return new Reference($id);
89
                    }, $arguments['plugins']))
90
                    ->addArgument(new Reference($arguments['factory']))
91
                    ->addArgument($arguments['config']);
92
            }
93 3
        }
94
95
        // If we have clients configured
96 3
        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 3
        } elseif (isset($config['_inject_collector_plugin'])) {
102
            // No client was configured. Make sure to inject history plugin to the auto discovery client.
103
            $container->register('httplug.client', PluginClient::class)
104
                ->addArgument(new Reference('httplug.client.default'))
105
                ->addArgument([new Reference('httplug.collector.history_plugin')]);
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 View Code Duplication
            case 'cache':
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...
141
                if (class_exists('Http\Client\Common\Plugin\CachePlugin')) {
142
                    $definition->setClass('Http\Client\Common\Plugin\CachePlugin');
143
                }
144
                $definition
145
                    ->replaceArgument(0, new Reference($config['cache_pool']))
146
                    ->replaceArgument(1, new Reference($config['stream_factory']))
147
                    ->replaceArgument(2, $config['config']);
148
                break;
149
            case 'cookie':
150
                $definition->replaceArgument(0, new Reference($config['cookie_jar']));
151
                break;
152
            case 'decoder':
153
                $definition->addArgument($config['use_content_encoding']);
154
                break;
155
            case 'history':
156
                $definition->replaceArgument(0, new Reference($config['journal']));
157
                break;
158 View Code Duplication
            case 'logger':
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...
159
                if (class_exists('Http\Client\Common\Plugin\LoggerPlugin')) {
160
                    $definition->setClass('Http\Client\Common\Plugin\LoggerPlugin');
161
                }
162
                $definition->replaceArgument(0, new Reference($config['logger']));
163
                if (!empty($config['formatter'])) {
164
                    $definition->replaceArgument(1, new Reference($config['formatter']));
165
                }
166
                break;
167
            case 'redirect':
168
                $definition
169
                    ->addArgument($config['preserve_header'])
170
                    ->addArgument($config['use_default_for_multiple']);
171
                break;
172
            case 'retry':
173
                $definition->addArgument($config['retry']);
174
                break;
175
            case 'stopwatch':
176
                if (class_exists('Http\Client\Common\Plugin\StopwatchPlugin')) {
177
                    $definition->setClass('Http\Client\Common\Plugin\StopwatchPlugin');
178
                }
179
                $definition->replaceArgument(0, new Reference($config['stopwatch']));
180
                break;
181
        }
182
    }
183
184
    /**
185
     * @param ContainerBuilder $container
186
     * @param array            $config
187
     */
188
    private function configureAuthentication(ContainerBuilder $container, array $config)
189
    {
190
        foreach ($config as $name => $values) {
191
            $authServiceKey = sprintf('httplug.plugin.authentication.%s.auth', $name);
192
            switch ($values['type']) {
193
                case 'bearer':
194
                    $container->register($authServiceKey, Bearer::class)
195
                        ->addArgument($values['token']);
196
                    break;
197
                case 'basic':
198
                    $container->register($authServiceKey, BasicAuth::class)
199
                        ->addArgument($values['username'])
200
                        ->addArgument($values['password']);
201
                    break;
202
                case 'wsse':
203
                    $container->register($authServiceKey, Wsse::class)
204
                        ->addArgument($values['username'])
205
                        ->addArgument($values['password']);
206
                    break;
207
                case 'service':
208
                    $authServiceKey = $values['service'];
209
                    break;
210
                default:
211
                    throw new \LogicException(sprintf('Unknown authentication type: "%s"', $values['type']));
212
            }
213
214
            $container->register('httplug.plugin.authentication.'.$name, AuthenticationPlugin::class)
215
                ->addArgument(new Reference($authServiceKey));
216
        }
217
    }
218
}
219