Completed
Pull Request — master (#84)
by Tobias
08:23 queued 05:37
created

HttplugExtension::configurePlugins()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 3
Bugs 0 Features 1
Metric Value
c 3
b 0
f 1
dl 0
loc 18
ccs 0
cts 0
cp 0
rs 9.2
cc 4
eloc 11
nc 6
nop 2
crap 20
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\HttplugBundle\Collector\DebugPlugin;
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
    /**
28
     * {@inheritdoc}
29
     */
30 3
    public function load(array $configs, ContainerBuilder $container)
31
    {
32 3
        $configuration = $this->getConfiguration($configs, $container);
33 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...
34
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 3
        $enabled = is_bool($config['toolbar']['enabled']) ? $config['toolbar']['enabled'] : $container->hasParameter('kernel.debug') && $container->getParameter('kernel.debug');
41 3
        if ($enabled) {
42
            $loader->load('data-collector.xml');
43
            $config['_inject_collector_plugin'] = true;
44
45
            if (!empty($config['toolbar']['formatter'])) {
46
                // Add custom formatter
47
                $container->getDefinition('httplug.collector.debug_collector')
48
                    ->replaceArgument(0, new Reference($config['toolbar']['formatter']));
49
            }
50
51
            $container->getDefinition('httplug.formatter.full_http_message')
52
                ->addArgument($config['toolbar']['captured_body_length']);
53
        }
54
55 3
        foreach ($config['classes'] as $service => $class) {
56 3
            if (!empty($class)) {
57 1
                $container->register(sprintf('httplug.%s.default', $service), $class);
58 1
            }
59 3
        }
60
61
        // Set main aliases
62 3
        foreach ($config['main_alias'] as $type => $id) {
63 3
            $container->setAlias(sprintf('httplug.%s', $type), $id);
64 3
        }
65
66 3
        $this->configurePlugins($container, $config['plugins']);
67 3
        $this->configureClients($container, $config);
68 3
    }
69
70
    /**
71
     * Configure client services.
72
     *
73
     * @param ContainerBuilder $container
74
     * @param array            $config
75
     */
76 3
    private function configureClients(ContainerBuilder $container, array $config)
77
    {
78
        // If we have a client named 'default'
79 3
        $first = isset($config['clients']['default']) ? 'default' : null;
80
81 3
        foreach ($config['clients'] as $name => $arguments) {
82
            if ($first === null) {
83
                // Save the name of the first configurated client.
84
                $first = $name;
85
            }
86
87
            $this->configureClient($container, $name, $arguments, $config['_inject_collector_plugin']);
88 3
        }
89
90
        // If we have clients configured
91 3
        if ($first !== null) {
92
            if ($first !== 'default') {
93
                // Alias the first client to httplug.client.default
94
                $container->setAlias('httplug.client.default', 'httplug.client.'.$first);
95
            }
96 3
        } elseif (isset($config['_inject_collector_plugin'])) {
97
            $serviceIdDebugPlugin = $this->registerDebugPlugin($container, 'default');
98
            // No client was configured. Make sure to configure the auto discovery client with the PluginClient.
99
            $container->register('httplug.client', PluginClient::class)
100
                ->addArgument(new Reference('httplug.client.default'))
101
                ->addArgument([])
102
                ->addArgument(['debug_plugins' => [new Reference($serviceIdDebugPlugin)]]);
103
        }
104
    }
105
106
    /**
107
     * @param ContainerBuilder $container
108
     * @param array            $config
109
     */
110
    private function configurePlugins(ContainerBuilder $container, array $config)
111
    {
112
        if (!empty($config['authentication'])) {
113
            $this->configureAuthentication($container, $config['authentication']);
114
        }
115
        unset($config['authentication']);
116
117
        foreach ($config as $name => $pluginConfig) {
118
            $pluginId = 'httplug.plugin.'.$name;
119
120
            if ($pluginConfig['enabled']) {
121
                $def = $container->getDefinition($pluginId);
122
                $this->configurePluginByName($name, $def, $pluginConfig);
123
            } else {
124
                $container->removeDefinition($pluginId);
125
            }
126
        }
127
    }
128
129
    /**
130
     * @param string     $name
131
     * @param Definition $definition
132
     * @param array      $config
133
     */
134
    private function configurePluginByName($name, Definition $definition, array $config)
135
    {
136
        switch ($name) {
137
            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
            case 'cookie':
144
                $definition->replaceArgument(0, new Reference($config['cookie_jar']));
145
                break;
146
            case 'decoder':
147
                $definition->addArgument($config['use_content_encoding']);
148
                break;
149
            case 'history':
150
                $definition->replaceArgument(0, new Reference($config['journal']));
151
                break;
152
            case 'logger':
153
                $definition->replaceArgument(0, new Reference($config['logger']));
154
                if (!empty($config['formatter'])) {
155
                    $definition->replaceArgument(1, new Reference($config['formatter']));
156
                }
157
                break;
158
            case 'redirect':
159
                $definition
160
                    ->addArgument($config['preserve_header'])
161
                    ->addArgument($config['use_default_for_multiple']);
162
                break;
163
            case 'retry':
164
                $definition->addArgument($config['retry']);
165
                break;
166
            case 'stopwatch':
167
                $definition->replaceArgument(0, new Reference($config['stopwatch']));
168
                break;
169
        }
170
    }
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             $enableCollector
212
     */
213
    private function configureClient(ContainerBuilder $container, $name, array $arguments, $enableCollector)
214
    {
215
        $serviceId = 'httplug.client.'.$name;
216
        $def = $container->register($serviceId, DummyClient::class);
217
218
        // If there is no plugins nor should we use the data collector
219
        if (empty($arguments['plugins']) && !$enableCollector) {
220
            $def->setFactory([new Reference($arguments['factory']), 'createClient'])
221
                ->addArgument($arguments['config']);
222
        } else {
223
            $serviceIdDebugPlugin = $this->registerDebugPlugin($container, $name);
224
225
            $def->setFactory('Http\HttplugBundle\ClientFactory\PluginClientFactory::createPluginClient')
226
                ->addArgument(
227
                    array_map(
228
                        function ($id) {
229
                            return new Reference($id);
230
                        },
231
                        $arguments['plugins']
232
                    )
233
                )
234
                ->addArgument(new Reference($arguments['factory']))
235
                ->addArgument($arguments['config'])
236
                ->addArgument(['debug_plugins' => [new Reference($serviceIdDebugPlugin)]]);
237
238
            // tell the plugin journal what plugins we used
239
            $container->getDefinition('httplug.collector.plugin_journal')
240
                ->addMethodCall('setPlugins', [$name, $arguments['plugins']]);
241
        }
242
243
244
        /*
245
         * Decorate the client with clients from client-common
246
         */
247
248 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...
249
            $container->register($serviceId.'.flexible', FlexibleHttpClient::class)
250
                ->addArgument(new Reference($serviceId.'.flexible.inner'))
251
                ->setPublic(false)
252
                ->setDecoratedService($serviceId);
253
        }
254
255 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...
256
            $container->register($serviceId.'.http_methods', HttpMethodsClient::class)
257
                ->setArguments([new Reference($serviceId.'.http_methods.inner'), new Reference('httplug.message_factory')])
258
                ->setPublic(false)
259
                ->setDecoratedService($serviceId);
260
        }
261
    }
262
263
    /**
264
     * Create a new plugin service for this client.
265
     *
266
     * @param ContainerBuilder $container
267
     * @param string           $name
268
     *
269
     * @return string
270
     */
271
    private function registerDebugPlugin(ContainerBuilder $container, $name)
272
    {
273
        $serviceIdDebugPlugin = 'httplug.client.'.$name.'.debug_plugin';
274
        $container->register($serviceIdDebugPlugin, DebugPlugin::class)
275
            ->addArgument(new Reference('httplug.collector.debug_collector'))
276
            ->addArgument($name)
277
            ->setPublic(false);
278
279
        return $serviceIdDebugPlugin;
280
    }
281
}
282