Completed
Push — master ( 709dbb...f12a68 )
by Tobias
09:11
created

BazingaGeocoderExtension::getConfiguration()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 2
1
<?php
2
3
/*
4
 * This file is part of the BazingaGeocoderBundle package.
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 *
8
 * @license    MIT License
9
 */
10
11
namespace Bazinga\GeocoderBundle\DependencyInjection;
12
13
use Bazinga\GeocoderBundle\ProviderFactory\ProviderFactoryInterface;
14
use Geocoder\Provider\Cache\ProviderCache;
15
use Geocoder\Provider\Provider;
16
use Symfony\Component\Config\Definition\Processor;
17
use Symfony\Component\Config\FileLocator;
18
use Symfony\Component\DependencyInjection\ContainerBuilder;
19
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
20
use Symfony\Component\DependencyInjection\Reference;
21
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
22
23
/**
24
 * William Durand <[email protected]>.
25
 */
26
class BazingaGeocoderExtension extends Extension
27
{
28
    public function load(array $configs, ContainerBuilder $container)
29
    {
30
        $processor = new Processor();
31
        $configuration = $this->getConfiguration($configs, $container);
32
        $config = $processor->processConfiguration($configuration, $configs);
0 ignored issues
show
Bug introduced by
It seems like $configuration defined by $this->getConfiguration($configs, $container) on line 31 can be null; however, Symfony\Component\Config...: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...
33
34
        $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
35
        $loader->load('services.yml');
36
37
        if (true === $config['profiling']['enabled']) {
38
            $loader->load('profiling.yml');
39
        }
40
        $this->loadProviders($container, $config);
41
42
        if ($config['fake_ip']['enabled']) {
43
            $definition = $container->getDefinition('bazinga_geocoder.event_listener.fake_request');
44
            $definition->replaceArgument(0, $config['fake_ip']['ip']);
45
        } else {
46
            $container->removeDefinition('bazinga_geocoder.event_listener.fake_request');
47
        }
48
    }
49
50
    private function loadProviders(ContainerBuilder $container, array $config)
51
    {
52
        foreach ($config['providers'] as $providerName => $providerConfig) {
53
            $factoryService = $container->getDefinition($providerConfig['factory']);
54
            $factoryClass = $factoryService->getClass() ?: $providerConfig['factory'];
55
            if (!(is_a($factoryClass, ProviderFactoryInterface::class))) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
56
                //throw new \LogicException(sprintf('Provider factory "%s" must implement ProviderFactoryInterface', $providerConfig['factory']));
0 ignored issues
show
Unused Code Comprehensibility introduced by
73% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
57
            }
58
            $factoryClass::validate($providerConfig['options'], $providerName);
59
60
            // See if any option has a service reference
61
            $providerConfig['options'] = $this->findReferences($providerConfig['options']);
62
63
            $serviceId = 'bazinga_geocoder.provider.'.$providerName;
64
            $def = $container->register($serviceId, Provider::class);
65
            $def->setFactory([new Reference($providerConfig['factory']), 'createProvider'])
66
                ->addArgument($providerConfig['options']);
67
68
            $def->addTag('bazinga_geocoder.provider');
69
            foreach ($providerConfig['aliases'] as $alias) {
70
                $container->setAlias($alias, $serviceId);
71
            }
72
73
            $this->configureCache($container, $serviceId, $providerConfig);
74
        }
75
    }
76
77
    /**
78
     * Add cache to a provider if needed.
79
     *
80
     * @param ContainerBuilder $
81
     * @param string $serviceId
82
     * @param array  $providerConfig
83
     */
84
    private function configureCache(ContainerBuilder $container, string $serviceId, array $providerConfig)
85
    {
86
        if (null === $providerConfig['cache'] && null === $providerConfig['cache_lifetime']) {
87
            return;
88
        }
89
90
        if (!class_exists(ProviderCache::class)) {
91
            throw new \LogicException('You must install "geocoder-php/cache-provider" to use cache.');
92
        }
93
94
        if (null === $cacheServiceId = $providerConfig['cache']) {
95
            if (!$container->has('app.cache')) {
96
                throw new \LogicException('You need to specify a service for cache.');
97
            }
98
            $cacheServiceId = 'app.cache';
99
        }
100
101
        $container->register($serviceId.'.cache', ProviderCache::class)
102
            ->setDecoratedService($serviceId)
103
            ->setArguments([
104
                new Reference($serviceId.'.cache.inner'),
105
                new Reference($cacheServiceId),
106
                $providerConfig['cache_lifetime'],
107
            ]);
108
    }
109
110
    /**
111
     * {@inheritdoc}
112
     */
113
    public function getConfiguration(array $config, ContainerBuilder $container)
114
    {
115
        return new Configuration($container->getParameter('kernel.debug'));
116
    }
117
118
    /**
119
     * @param array $options
120
     *
121
     * @return array
122
     */
123
    private function findReferences(array $options)
124
    {
125
        foreach ($options as $key => $value) {
126
            if (is_array($value)) {
127
                $options[$key] = $this->findReferences($value);
128
            } elseif (substr($key, -8) === '_service' || strpos($value, '@') === 0 || $key === 'service') {
129
                $options[$key] = new Reference(ltrim($value, '@'));
130
            }
131
        }
132
133
        return $options;
134
    }
135
}
136