DHNavigationExtension   A
last analyzed

Complexity

Total Complexity 19

Size/Duplication

Total Lines 79
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 19
eloc 39
c 1
b 0
f 0
dl 0
loc 79
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A load() 0 14 4
A findReferences() 0 11 6
A implementsProviderFactory() 0 7 2
B loadProviders() 0 30 7
1
<?php
2
3
namespace DH\NavigationBundle\DependencyInjection;
4
5
use DH\NavigationBundle\DependencyInjection\Compiler\FactoryValidatorPass;
6
use DH\NavigationBundle\Provider\ProviderFactoryInterface;
7
use Symfony\Component\Config\FileLocator;
8
use Symfony\Component\DependencyInjection\ContainerBuilder;
9
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
10
use Symfony\Component\DependencyInjection\Loader;
11
use Symfony\Component\DependencyInjection\Reference;
12
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
13
14
class DHNavigationExtension extends Extension
15
{
16
    /**
17
     * {@inheritdoc}
18
     */
19
    public function load(array $configs, ContainerBuilder $container): void
20
    {
21
        $configuration = new Configuration();
22
        $config = $this->processConfiguration($configuration, $configs);
23
24
        $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
25
        $loader->load('services.yaml');
26
27
        $this->loadProviders($container, $config);
28
29
        foreach ($config['providers'] as $providerName => $providerConfig) {
30
            if (isset($providerConfig['options'])) {
31
                foreach ($providerConfig['options'] as $key => $value) {
32
                    $container->setParameter('dh_navigation.%s.%s'.$providerName.'.'.$key, $value);
33
                }
34
            }
35
        }
36
    }
37
38
    private function loadProviders(ContainerBuilder $container, array $config): void
39
    {
40
        foreach ($config['providers'] as $providerName => $providerConfig) {
41
            $factoryClass = null;
42
43
            try {
44
                $factoryService = $container->getDefinition($providerConfig['factory']);
45
                $factoryClass = $factoryService->getClass() ?: $providerConfig['factory'];
46
                if (!$this->implementsProviderFactory($factoryClass)) {
47
                    throw new \LogicException(sprintf('Provider factory "%s" must implement ProviderFactoryInterface', $providerConfig['factory']));
48
                }
49
                // See if any option has a service reference
50
                $providerConfig['options'] = $this->findReferences($providerConfig['options']);
51
                $factoryClass::validate($providerConfig['options'], $providerName);
52
            } catch (ServiceNotFoundException $e) {
53
                // Assert: We are using a custom factory. If invalid config, it will be caught in FactoryValidatorPass
54
                $providerConfig['options'] = $this->findReferences($providerConfig['options']);
55
                FactoryValidatorPass::addFactoryServiceId($providerConfig['factory']);
56
            }
57
58
            if (null !== $factoryClass) {
59
                $serviceId = 'dh_navigation.provider.'.$providerName;
60
                $def = $container->register($serviceId, $factoryClass)
61
                    ->setFactory([new Reference($factoryClass), 'createProvider'])
62
                    ->addArgument($providerConfig['options'])
63
                ;
64
65
                $def->addTag('dh_navigation.provider');
66
                foreach ($providerConfig['aliases'] as $alias) {
67
                    $container->setAlias($alias, $serviceId);
68
                }
69
            }
70
        }
71
    }
72
73
    private function findReferences(array $options): array
74
    {
75
        foreach ($options as $key => $value) {
76
            if (\is_array($value)) {
77
                $options[$key] = $this->findReferences($value);
78
            } elseif ('_service' === substr((string) $key, -8) || 0 === strpos((string) $value, '@') || 'service' === $key) {
79
                $options[$key] = new Reference(ltrim($value, '@'));
80
            }
81
        }
82
83
        return $options;
84
    }
85
86
    private function implementsProviderFactory(string $factoryClass): bool
87
    {
88
        if (false === $interfaces = class_implements($factoryClass)) {
89
            return false;
90
        }
91
92
        return \in_array(ProviderFactoryInterface::class, $interfaces, true);
93
    }
94
}
95