Completed
Pull Request — master (#356)
by David de
06:02 queued 02:09
created

FOSHttpCacheExtension::load()   F

Complexity

Conditions 21
Paths 8640

Size

Total Lines 93
Code Lines 58

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 48
CRAP Score 21.3698

Importance

Changes 0
Metric Value
dl 0
loc 93
ccs 48
cts 53
cp 0.9057
rs 2
c 0
b 0
f 0
cc 21
eloc 58
nc 8640
nop 2
crap 21.3698

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the FOSHttpCacheBundle package.
5
 *
6
 * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace FOS\HttpCacheBundle\DependencyInjection;
13
14
use FOS\HttpCache\ProxyClient\HttpDispatcher;
15
use FOS\HttpCacheBundle\DependencyInjection\Compiler\HashGeneratorPass;
16
use FOS\HttpCacheBundle\Http\ResponseMatcher\ExpressionResponseMatcher;
17
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
18
use Symfony\Component\Config\FileLocator;
19
use Symfony\Component\DependencyInjection\ContainerBuilder;
20
use Symfony\Component\DependencyInjection\Definition;
21
use Symfony\Component\DependencyInjection\DefinitionDecorator;
22
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
23
use Symfony\Component\DependencyInjection\Reference;
24
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
25
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
26
27
/**
28
 * {@inheritdoc}
29
 */
30
class FOSHttpCacheExtension extends Extension
31
{
32
    /**
33
     * {@inheritdoc}
34
     */
35 23
    public function getConfiguration(array $config, ContainerBuilder $container)
36
    {
37 23
        return new Configuration($container->getParameter('kernel.debug'));
38
    }
39
40
    /**
41
     * {@inheritdoc}
42
     */
43 23
    public function load(array $configs, ContainerBuilder $container)
44
    {
45 23
        $configuration = $this->getConfiguration($configs, $container);
46 23
        $config = $this->processConfiguration($configuration, $configs);
0 ignored issues
show
Bug introduced by
It seems like $configuration defined by $this->getConfiguration($configs, $container) on line 45 can be null; however, Symfony\Component\Depend...:processConfiguration() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
47
48 23
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
49 23
        $loader->load('matcher.xml');
50
51 23
        if ($config['debug']['enabled'] || (!empty($config['cache_control']))) {
52 3
            $debugHeader = $config['debug']['enabled'] ? $config['debug']['header'] : false;
53 3
            $container->setParameter($this->getAlias().'.debug_header', $debugHeader);
54 3
            $loader->load('cache_control_listener.xml');
55
        }
56
57 23
        $this->loadCacheable($container, $config['cacheable']);
58
59 23
        if (!empty($config['cache_control'])) {
60 3
            $this->loadCacheControl($container, $config['cache_control']);
61
        }
62
63 23
        if (isset($config['proxy_client'])) {
64 17
            $this->loadProxyClient($container, $loader, $config['proxy_client']);
65
        }
66
67 22
        if (isset($config['test'])) {
68 1
            $this->loadTest($container, $loader, $config['test']);
69
        }
70
71 22
        if ($config['cache_manager']['enabled']) {
72 17
            if (array_key_exists('custom_proxy_client', $config['cache_manager'])) {
73
                // overwrite the previously set alias, if a proxy client was also configured
74 1
                $container->setAlias(
75 1
                    $this->getAlias().'.default_proxy_client',
76 1
                    $config['cache_manager']['custom_proxy_client']
77
                );
78
            }
79 17
            if ('auto' === $config['cache_manager']['generate_url_type']) {
80 17
                if (array_key_exists('custom_proxy_client', $config['cache_manager'])) {
81 1
                    $generateUrlType = UrlGeneratorInterface::ABSOLUTE_URL;
82
                } else {
83 16
                    $defaultClient = $this->getDefaultProxyClient($config['proxy_client']);
84 16
                    if ($defaultClient !== 'noop'
85 16
                        && array_key_exists('base_url', $config['proxy_client'][$defaultClient])) {
86
                        $generateUrlType = UrlGeneratorInterface::ABSOLUTE_PATH;
87
                    } else {
88 17
                        $generateUrlType = UrlGeneratorInterface::ABSOLUTE_URL;
89
                    }
90
                }
91
            } else {
92
                $generateUrlType = $config['cache_manager']['generate_url_type'];
93
            }
94 17
            $container->setParameter($this->getAlias().'.cache_manager.generate_url_type', $generateUrlType);
95 17
            $loader->load('cache_manager.xml');
96
        }
97
98 22
        if ($config['tags']['enabled']) {
99 17
            $this->loadCacheTagging(
100
                $container,
101
                $loader,
102 17
                $config['tags'],
103 17
                array_key_exists('proxy_client', $config)
104 16
                    ? $this->getDefaultProxyClient($config['proxy_client'])
105 17
                    : 'custom'
106
            );
107
        } else {
108 5
            $container->setParameter($this->getAlias().'.compiler_pass.tag_annotations', false);
109
        }
110
111 21
        if ($config['invalidation']['enabled']) {
112 16
            $loader->load('invalidation_listener.xml');
113
114 16
            if (!empty($config['invalidation']['expression_language'])) {
115
                $container->setAlias(
116
                    $this->getAlias().'.invalidation.expression_language',
117
                    $config['invalidation']['expression_language']
118
                );
119
            }
120
121 16
            if (!empty($config['invalidation']['rules'])) {
122 2
                $this->loadInvalidatorRules($container, $config['invalidation']['rules']);
123
            }
124
        }
125
126 21
        if ($config['user_context']['enabled']) {
127 4
            $this->loadUserContext($container, $loader, $config['user_context']);
128
        }
129
130 21
        if (!empty($config['flash_message']) && $config['flash_message']['enabled']) {
131 1
            $container->setParameter($this->getAlias().'.event_listener.flash_message.options', $config['flash_message']);
132
133 1
            $loader->load('flash_message.xml');
134
        }
135 21
    }
136
137 23
    private function loadCacheable(ContainerBuilder $container, array $config)
138
    {
139 23
        $definition = $container->getDefinition($this->getAlias().'.response_matcher.cacheable');
140
141
        // Change CacheableResponseMatcher to ExpressionResponseMatcher
142 23
        if ($config['response']['expression']) {
143
            $definition->setClass(ExpressionResponseMatcher::class)
144
                ->setArguments([$config['response']['expression']]);
145
        } else {
146 23
            $container->setParameter(
147 23
                $this->getAlias().'.cacheable.response.additional_status',
148 23
                $config['response']['additional_status']
149
            );
150
        }
151 23
    }
152
153
    /**
154
     * @param ContainerBuilder $container
155
     * @param array            $config
156
     *
157
     * @throws InvalidConfigurationException
158
     */
159 3
    private function loadCacheControl(ContainerBuilder $container, array $config)
160
    {
161 3
        $controlDefinition = $container->getDefinition($this->getAlias().'.event_listener.cache_control');
162
163 3
        foreach ($config['rules'] as $rule) {
164 3
            $ruleMatcher = $this->parseRuleMatcher($container, $rule['match']);
165
166 3
            if ('default' === $rule['headers']['overwrite']) {
167 3
                $rule['headers']['overwrite'] = $config['defaults']['overwrite'];
168
            }
169
170 3
            $controlDefinition->addMethodCall('addRule', [$ruleMatcher, $rule['headers']]);
171
        }
172 3
    }
173
174 5
    private function parseRuleMatcher(ContainerBuilder $container, array $match)
175
    {
176 5
        $match['ips'] = (empty($match['ips'])) ? null : $match['ips'];
177
178 5
        return $this->createRequestMatcher(
179
            $container,
180 5
            $match['path'],
181 5
            $match['host'],
182 5
            $match['methods'],
183 5
            $match['ips'],
184 5
            $match['attributes']
185
        );
186
    }
187
188 4
    private function loadUserContext(ContainerBuilder $container, XmlFileLoader $loader, array $config)
189
    {
190 4
        $loader->load('user_context.xml');
191
192 4
        $container->getDefinition($this->getAlias().'.user_context.request_matcher')
193 4
            ->replaceArgument(0, $config['match']['accept'])
194 4
            ->replaceArgument(1, $config['match']['method']);
195
196 4
        $container->setParameter($this->getAlias().'.event_listener.user_context.options', [
197 4
            'user_identifier_headers' => $config['user_identifier_headers'],
198 4
            'user_hash_header' => $config['user_hash_header'],
199 4
            'ttl' => $config['hash_cache_ttl'],
200 4
            'add_vary_on_hash' => $config['always_vary_on_context_hash'],
201
        ]);
202 4
        $container->getDefinition($this->getAlias().'.event_listener.user_context')
203 4
            ->replaceArgument(0, new Reference($config['match']['matcher_service']));
204
205 4
        $container->getDefinition($this->getAlias().'.user_context.anonymous_request_matcher')
206 4
            ->replaceArgument(0, $config['user_identifier_headers']);
207
208 4
        if ($config['logout_handler']['enabled']) {
209 4
            $container->getDefinition($this->getAlias().'.user_context.logout_handler')
210 4
                ->replaceArgument(1, $config['user_identifier_headers'])
211 4
                ->replaceArgument(2, $config['match']['accept']);
212
        } else {
213
            $container->removeDefinition($this->getAlias().'.user_context.logout_handler');
214
        }
215
216 4
        if ($config['role_provider']) {
217 2
            $container->getDefinition($this->getAlias().'.user_context.role_provider')
218 2
                ->addTag(HashGeneratorPass::TAG_NAME)
219 2
                ->setAbstract(false);
220
        }
221 4
    }
222
223 5
    private function createRequestMatcher(ContainerBuilder $container, $path = null, $host = null, $methods = null, $ips = null, array $attributes = [])
224
    {
225 5
        $arguments = [$path, $host, $methods, $ips, $attributes];
226 5
        $serialized = serialize($arguments);
227 5
        $id = $this->getAlias().'.request_matcher.'.md5($serialized).sha1($serialized);
228
229 5
        if (!$container->hasDefinition($id)) {
230
            $container
231 5
                ->setDefinition($id, new DefinitionDecorator($this->getAlias().'.request_matcher'))
232 5
                ->setArguments($arguments)
233
            ;
234
        }
235
236 5
        return new Reference($id);
237
    }
238
239 17
    private function loadProxyClient(ContainerBuilder $container, XmlFileLoader $loader, array $config)
240
    {
241 17
        if (isset($config['varnish'])) {
242 13
            $this->loadVarnish($container, $loader, $config['varnish']);
243
        }
244 16
        if (isset($config['nginx'])) {
245 2
            $this->loadNginx($container, $loader, $config['nginx']);
246
        }
247 16
        if (isset($config['symfony'])) {
248 1
            $this->loadSymfony($container, $loader, $config['symfony']);
249
        }
250 16
        if (isset($config['noop'])) {
251 1
            $loader->load('noop.xml');
252
        }
253
254 16
        $container->setAlias(
255 16
            $this->getAlias().'.default_proxy_client',
256 16
            $this->getAlias().'.proxy_client.'.$this->getDefaultProxyClient($config)
257
        );
258 16
    }
259
260
    /**
261
     * Define the http dispatcher service for the proxy client $name.
262
     *
263
     * @param ContainerBuilder $container
264
     * @param array            $config
265
     * @param string           $serviceName
266
     */
267 16
    private function createHttpDispatcherDefinition(ContainerBuilder $container, array $config, $serviceName)
268
    {
269 16
        foreach ($config['servers'] as $url) {
270 16
            $this->validateUrl($url, 'Not a valid Varnish server address: "%s"');
271
        }
272 16
        if (!empty($config['base_url'])) {
273 16
            $baseUrl = $this->prefixSchema($config['base_url']);
274 16
            $this->validateUrl($baseUrl, 'Not a valid base path: "%s"');
275
        } else {
276
            $baseUrl = null;
277
        }
278 15
        $httpClient = null;
279 15
        if ($config['http_client']) {
280 1
            $httpClient = new Reference($config['http_client']);
281
        }
282
283 15
        $definition = new Definition(HttpDispatcher::class, [
284 15
            $config['servers'],
285 15
            $baseUrl,
286 15
            $httpClient,
287
        ]);
288
289 15
        $container->setDefinition($serviceName, $definition);
290 15
    }
291
292 13
    private function loadVarnish(ContainerBuilder $container, XmlFileLoader $loader, array $config)
293
    {
294 13
        $this->createHttpDispatcherDefinition($container, $config['http'], $this->getAlias().'.proxy_client.varnish.http_dispatcher');
295 12
        $loader->load('varnish.xml');
296 12
    }
297
298 2
    private function loadNginx(ContainerBuilder $container, XmlFileLoader $loader, array $config)
299
    {
300 2
        $this->createHttpDispatcherDefinition($container, $config['http'], $this->getAlias().'.proxy_client.nginx.http_dispatcher');
301 2
        $container->setParameter($this->getAlias().'.proxy_client.nginx.options', [
302 2
            'purge_location' => $config['purge_location'],
303
        ]);
304 2
        $loader->load('nginx.xml');
305 2
    }
306
307 1
    private function loadSymfony(ContainerBuilder $container, XmlFileLoader $loader, array $config)
308
    {
309 1
        $this->createHttpDispatcherDefinition($container, $config['http'], $this->getAlias().'.proxy_client.symfony.http_dispatcher');
310 1
        $loader->load('symfony.xml');
311 1
    }
312
313
    /**
314
     * @param ContainerBuilder $container
315
     * @param XmlFileLoader    $loader
316
     * @param array            $config    Configuration section for the tags node
317
     * @param string           $client    Name of the client used with the cache manager,
318
     *                                    "custom" when a custom client is used
319
     */
320 17
    private function loadCacheTagging(ContainerBuilder $container, XmlFileLoader $loader, array $config, $client)
321
    {
322 17
        if ('auto' === $config['enabled'] && 'varnish' !== $client) {
323 4
            $container->setParameter($this->getAlias().'.compiler_pass.tag_annotations', false);
324
325 4
            return;
326
        }
327 13
        if (!in_array($client, ['varnish', 'custom'])) {
328 1
            throw new InvalidConfigurationException(sprintf('You can not enable cache tagging with the %s client', $client));
329
        }
330
331 12
        $container->setParameter($this->getAlias().'.compiler_pass.tag_annotations', true);
332 12
        $container->setParameter($this->getAlias().'.tag_handler.header', $config['header']);
333 12
        $container->setParameter($this->getAlias().'.tag_handler.strict', $config['strict']);
334 12
        $loader->load('cache_tagging.xml');
335
336 12
        if (!empty($config['expression_language'])) {
337
            $container->setAlias(
338
                $this->getAlias().'.tag_handler.expression_language',
339
                $config['expression_language']
340
            );
341
        }
342
343 12
        if (!empty($config['rules'])) {
344 2
            $this->loadTagRules($container, $config['rules']);
345
        }
346 12
    }
347
348 1
    private function loadTest(ContainerBuilder $container, XmlFileLoader $loader, array $config)
349
    {
350 1
        $container->setParameter($this->getAlias().'.test.cache_header', $config['cache_header']);
351
352 1
        if ($config['proxy_server']) {
353 1
            $this->loadProxyServer($container, $loader, $config['proxy_server']);
354
        }
355 1
    }
356
357 1
    private function loadProxyServer(ContainerBuilder $container, XmlFileLoader $loader, array $config)
358
    {
359 1
        if (isset($config['varnish'])) {
360 1
            $this->loadVarnishProxyServer($container, $loader, $config['varnish']);
361
        }
362
363 1
        if (isset($config['nginx'])) {
364
            $this->loadNginxProxyServer($container, $loader, $config['varnish']);
365
        }
366
367 1
        $container->setAlias(
368 1
            $this->getAlias().'.test.default_proxy_server',
369 1
            $this->getAlias().'.test.proxy_server.'.$this->getDefaultProxyClient($config)
370
        );
371 1
    }
372
373 1
    private function loadVarnishProxyServer(ContainerBuilder $container, XmlFileLoader $loader, $config)
374
    {
375 1
        $loader->load('varnish_proxy.xml');
376 1
        foreach ($config as $key => $value) {
377 1
            $container->setParameter(
378 1
                $this->getAlias().'.test.proxy_server.varnish.'.$key,
379
                $value
380
            );
381
        }
382 1
    }
383
384
    private function loadNginxProxyServer(ContainerBuilder $container, XmlFileLoader $loader, $config)
385
    {
386
        $loader->load('nginx_proxy.xml');
387
        foreach ($config as $key => $value) {
388
            $container->setParameter(
389
                $this->getAlias().'.test.proxy_server.nginx.'.$key,
390
                $value
391
            );
392
        }
393
    }
394
395 2
    private function loadTagRules(ContainerBuilder $container, array $config)
396
    {
397 2
        $tagDefinition = $container->getDefinition($this->getAlias().'.event_listener.tag');
398
399 2
        foreach ($config as $rule) {
400 2
            $ruleMatcher = $this->parseRuleMatcher($container, $rule['match']);
401
402
            $tags = [
403 2
                'tags' => $rule['tags'],
404 2
                'expressions' => $rule['tag_expressions'],
405
            ];
406
407 2
            $tagDefinition->addMethodCall('addRule', [$ruleMatcher, $tags]);
408
        }
409 2
    }
410
411 2
    private function loadInvalidatorRules(ContainerBuilder $container, array $config)
412
    {
413 2
        $tagDefinition = $container->getDefinition($this->getAlias().'.event_listener.invalidation');
414
415 2
        foreach ($config as $rule) {
416 2
            $ruleMatcher = $this->parseRuleMatcher($container, $rule['match']);
417 2
            $tagDefinition->addMethodCall('addRule', [$ruleMatcher, $rule['routes']]);
418
        }
419 2
    }
420
421 16
    private function validateUrl($url, $msg)
422
    {
423 16
        $prefixed = $this->prefixSchema($url);
424
425 16
        if (!$parts = parse_url($prefixed)) {
426 1
            throw new InvalidConfigurationException(sprintf($msg, $url));
427
        }
428 16
    }
429
430 16
    private function prefixSchema($url)
431
    {
432 16
        if (false === strpos($url, '://')) {
433 16
            $url = sprintf('%s://%s', 'http', $url);
434
        }
435
436 16
        return $url;
437
    }
438
439 16
    private function getDefaultProxyClient(array $config)
440
    {
441 16
        if (isset($config['default'])) {
442
            return $config['default'];
443
        }
444
445 16
        if (isset($config['varnish'])) {
446 12
            return 'varnish';
447
        }
448
449 4
        if (isset($config['nginx'])) {
450 2
            return 'nginx';
451
        }
452
453 2
        if (isset($config['symfony'])) {
454 1
            return 'symfony';
455
        }
456
457 1
        if (isset($config['noop'])) {
458 1
            return 'noop';
459
        }
460
461
        throw new InvalidConfigurationException('No proxy client configured');
462
    }
463
}
464