Completed
Pull Request — master (#55)
by Márk
31:49 queued 21:57
created

HttplugExtension   B

Complexity

Total Complexity 40

Size/Duplication

Total Lines 215
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 56.25%

Importance

Changes 11
Bugs 2 Features 4
Metric Value
wmc 40
c 11
b 2
f 4
lcom 1
cbo 6
dl 0
loc 215
ccs 27
cts 48
cp 0.5625
rs 8.2608

6 Methods

Rating   Name   Duplication   Size   Complexity  
D load() 0 46 9
D configureClients() 0 40 9
A configurePlugins() 0 17 4
D configurePluginByName() 0 37 10
B configureAuthentication() 0 30 6
A verifyPuliInstalled() 0 8 2

How to fix   Complexity   

Complex Class

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\Plugin\AuthenticationPlugin;
6
use Http\Client\Plugin\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 3
        $loader->load('discovery.xml');
37
38 3
        $enabled = is_bool($config['toolbar']['enabled']) ? $config['toolbar']['enabled'] : $container->hasParameter('kernel.debug') && $container->getParameter('kernel.debug');
39 3
        if ($enabled) {
40
            $loader->load('data-collector.xml');
41
            $config['_inject_collector_plugin'] = true;
42
43
            if (!empty($config['toolbar']['formatter'])) {
44
                $container->getDefinition('httplug.collector.message_journal')
45
                    ->replaceArgument(0, new Reference($config['toolbar']['formatter']));
46
            }
47
        }
48
49 3
        $useDiscovery = false;
50 3
51 1
        foreach ($config['classes'] as $service => $class) {
52 1
            if (!empty($class)) {
53 1
                $container->removeDefinition(sprintf('httplug.%s.default', $service));
54 3
                $container->register(sprintf('httplug.%s.default', $service), $class);
55
            } else {
56 3
                // we have to use discovery to find this class
57 3
                $useDiscovery = true;
58 3
            }
59 3
        }
60 3
61 3
        if ($useDiscovery) {
62
            $this->verifyPuliInstalled($container);
63
            $loader->load('puli.xml');
64
        }
65
66
        foreach ($config['main_alias'] as $type => $id) {
67
            $container->setAlias(sprintf('httplug.%s', $type), $id);
68
        }
69 3
70
        $this->configurePlugins($container, $config['plugins']);
71 3
        $this->configureClients($container, $config);
72 3
    }
73
74
    /**
75
     * Configure client services.
76
     *
77
     * @param ContainerBuilder $container
78
     * @param array            $config
79
     */
80
    private function configureClients(ContainerBuilder $container, array $config)
81
    {
82
        $first = isset($config['clients']['default']) ? 'default' : null;
83
        foreach ($config['clients'] as $name => $arguments) {
84
            if ($first === null) {
85
                $first = $name;
86
            }
87
88
            if (isset($config['_inject_collector_plugin'])) {
89
                array_unshift($arguments['plugins'], 'httplug.collector.history_plugin');
90
            }
91
92
            $def = $container->register('httplug.client.'.$name, DummyClient::class);
93
94 3
            if (empty($arguments['plugins'])) {
95
                $def->setFactory([new Reference($arguments['factory']), 'createClient'])
96
                    ->addArgument($arguments['config']);
97 3
            } else {
98
                $def->setFactory('Http\HttplugBundle\ClientFactory\PluginClientFactory::createPluginClient')
99
                    ->addArgument(array_map(function ($id) {
100
                        return new Reference($id);
101
                    }, $arguments['plugins']))
102 3
                    ->addArgument(new Reference($arguments['factory']))
103
                    ->addArgument($arguments['config']);
104
            }
105
        }
106
107
        // If we have clients configured
108
        if ($first !== null) {
109
            if ($first !== 'default') {
110
                // Alias the first client to httplug.client.default
111
                $container->setAlias('httplug.client.default', 'httplug.client.'.$first);
112
            }
113
        } elseif (isset($config['_inject_collector_plugin'])) {
114
            // No client was configured. Make sure to inject history plugin to the auto discovery client.
115
            $container->register('httplug.client', PluginClient::class)
116
                ->addArgument(new Reference('httplug.client.default'))
117
                ->addArgument([new Reference('httplug.collector.history_plugin')]);
118
        }
119
    }
120
121
    /**
122
     * @param ContainerBuilder $container
123
     * @param array            $config
124
     */
125
    private function configurePlugins(ContainerBuilder $container, array $config)
126
    {
127
        if (!empty($config['authentication'])) {
128
            $this->configureAuthentication($container, $config['authentication']);
129
        }
130
        unset($config['authentication']);
131
132
        foreach ($config as $name => $pluginConfig) {
133
            $pluginId = 'httplug.plugin.'.$name;
134
            if ($pluginConfig['enabled']) {
135
                $def = $container->getDefinition($pluginId);
136
                $this->configurePluginByName($name, $def, $pluginConfig);
137
            } else {
138
                $container->removeDefinition($pluginId);
139
            }
140
        }
141
    }
142
143
    /**
144
     * @param string     $name
145
     * @param Definition $definition
146
     * @param array      $config
147
     */
148
    private function configurePluginByName($name, Definition $definition, array $config)
149
    {
150
        switch ($name) {
151
            case 'cache':
152
                $definition
153
                    ->replaceArgument(0, new Reference($config['cache_pool']))
154
                    ->replaceArgument(1, new Reference($config['stream_factory']))
155
                    ->replaceArgument(2, $config['config']);
156
                break;
157
            case 'cookie':
158
                $definition->replaceArgument(0, new Reference($config['cookie_jar']));
159
                break;
160
            case 'decoder':
161
                $definition->addArgument($config['use_content_encoding']);
162
                break;
163
            case 'history':
164
                $definition->replaceArgument(0, new Reference($config['journal']));
165
                break;
166
            case 'logger':
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
                $definition->replaceArgument(0, new Reference($config['stopwatch']));
182
                break;
183
        }
184
    }
185
186
    /**
187
     * @param ContainerBuilder $container
188
     * @param array            $config
189
     */
190
    private function configureAuthentication(ContainerBuilder $container, array $config)
191
    {
192
        foreach ($config as $name => $values) {
193
            $authServiceKey = sprintf('httplug.plugin.authentication.%s.auth', $name);
194
            switch ($values['type']) {
195
                case 'bearer':
196
                    $container->register($authServiceKey, Bearer::class)
197
                        ->addArgument($values['token']);
198
                    break;
199
                case 'basic':
200
                    $container->register($authServiceKey, BasicAuth::class)
201
                        ->addArgument($values['username'])
202
                        ->addArgument($values['password']);
203
                    break;
204
                case 'wsse':
205
                    $container->register($authServiceKey, Wsse::class)
206
                        ->addArgument($values['username'])
207
                        ->addArgument($values['password']);
208
                    break;
209
                case 'service':
210
                    $authServiceKey = $values['service'];
211
                    break;
212
                default:
213
                    throw new \LogicException(sprintf('Unknown authentication type: "%s"', $values['type']));
214
            }
215
216
            $container->register('httplug.plugin.authentication.'.$name, AuthenticationPlugin::class)
217
                ->addArgument(new Reference($authServiceKey));
218
        }
219
    }
220
221
    /**
222
     * Verifies that Puli bundle is installed.
223
     *
224
     * @param ContainerBuilder $container
225
     *
226
     * @throws \Exception
227
     */
228
    private function verifyPuliInstalled(ContainerBuilder $container)
229
    {
230
        if (false === $container->has('puli.discovery')) {
231
            throw new \Exception(
232
                'You need to install puli/symfony-bundle or add configuration at httplug.classes in order to use this bundle. Refer to http://some.doc'
233
            );
234
        }
235
    }
236
}
237