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

HttplugExtension   B

Complexity

Total Complexity 40

Size/Duplication

Total Lines 200
Duplicated Lines 10 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 54.35%

Importance

Changes 11
Bugs 2 Features 4
Metric Value
wmc 40
c 11
b 2
f 4
lcom 1
cbo 6
dl 20
loc 200
ccs 25
cts 46
cp 0.5435
rs 8.2608

5 Methods

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