ConfigurationBuilderPass::getConfigTree()   B
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 27
Code Lines 24

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 27
rs 8.8571
cc 1
eloc 24
nc 1
nop 0
1
<?php
2
3
namespace Pim\Bundle\CustomEntityBundle\DependencyInjection\Compiler;
4
5
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
6
use Symfony\Component\Config\Definition\NodeInterface;
7
use Symfony\Component\Config\Definition\Processor;
8
use Symfony\Component\Config\Resource\FileResource;
9
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
10
use Symfony\Component\DependencyInjection\ContainerBuilder;
11
use Symfony\Component\DependencyInjection\Definition;
12
use Symfony\Component\DependencyInjection\Reference;
13
use Symfony\Component\Yaml\Parser;
14
15
/**
16
 * Builds configuration services
17
 *
18
 * @author    Antoine Guigan <[email protected]>
19
 * @copyright 2013 Akeneo SAS (http://www.akeneo.com)
20
 * @license   http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
21
 */
22
class ConfigurationBuilderPass implements CompilerPassInterface
23
{
24
    /**
25
     * {@inheritdoc}
26
     */
27
    public function process(ContainerBuilder $container)
28
    {
29
        $configurations = [];
30
        $bundles = $container->getParameter('kernel.bundles');
31
        $configTree = $this->getConfigTree();
32
        foreach ($bundles as $bundle) {
33
            $reflection = new \ReflectionClass($bundle);
34
            $path = sprintf('%s/Resources/config/custom_entities.yml', dirname($reflection->getFileName()));
35
            if (file_exists($path)) {
36
                $container->addResource(new FileResource($path));
37
                $configurations += $this->parseConfigFile($configTree, $path);
38
            }
39
        }
40
41
        foreach ($configurations as $name => $configuration) {
42
            if ($configuration['abstract']) {
43
                continue;
44
            }
45
46
            $serviceConfiguration =  $this->getMergedConfiguration($configuration, $configurations);
47
            $this->addService($container, $name, $serviceConfiguration);
48
        }
49
    }
50
51
    /**
52
     * Adds a configuration service to the DIC
53
     *
54
     * @param ContainerBuilder $container
55
     * @param string           $name
56
     * @param array            $configuration
57
     */
58
    protected function addService(ContainerBuilder $container, $name, array $configuration)
59
    {
60
        $definition = new Definition(
61
            $configuration['class'],
62
            [
63
                new Reference('event_dispatcher'),
64
                $name,
65
                $configuration['entity_class'],
66
                $configuration['options']
67
            ]
68
        );
69
        foreach ($configuration['actions'] as $type => $options) {
70
            if (null === $options || !$options['enabled']) {
71
                continue;
72
            }
73
            $service = $options['service'];
74
            unset($options['service'], $options['enabled']);
75
            $definition->addMethodCall('addAction', [$type, $service, $options]);
76
        }
77
        $serviceName = sprintf('pim_custom_entity_bundle.configuration.%s', $name);
78
        $container->addDefinitions([$serviceName => $definition]);
79
        $container->getDefinition('pim_custom_entity.configuration.registry')
80
            ->addMethodCall('add', [$name, $serviceName]);
81
    }
82
83
    /**
84
     * Gets a configuration merged with its parents
85
     *
86
     * @param array $configuration
87
     * @param array $configurations
88
     *
89
     * @return array
90
     */
91
    protected function getMergedConfiguration(array $configuration, array $configurations)
92
    {
93
        foreach (array_keys($configuration['actions']) as $actionType) {
94
            $configuration['actions'][$actionType] = $configuration['actions'][$actionType] + ['enabled' => true];
95
        }
96
97
        if (!$configuration['extends']) {
98
            return $configuration;
99
        }
100
101
        $parentConfiguration = $this->getMergedConfiguration(
102
            $configurations[$configuration['extends']],
103
            $configurations
104
        );
105
        if (!$configuration['class']) {
106
            $configuration['class'] = $parentConfiguration['class'];
107
        }
108
        $configuration['options'] = $configuration['options'] + $parentConfiguration['options'];
109
        foreach ($parentConfiguration['actions'] as $actionName => $actionConfiguration) {
110
            if (isset($configuration['actions'][$actionName])) {
111
                $configuration['actions'][$actionName] = $configuration['actions'][$actionName] + $actionConfiguration;
112
            } elseif (!array_key_exists($actionName, $configuration['actions'])) {
113
                $configuration['actions'][$actionName] = $actionConfiguration;
114
            }
115
        }
116
117
        return $configuration;
118
    }
119
120
    /**
121
     * Parses a config file and returns an array
122
     *
123
     * @param NodeInterface $configTree
124
     * @param string        $file
125
     *
126
     * @return array
127
     */
128
    protected function parseConfigFile(NodeInterface $configTree, $file)
129
    {
130
        $yamlParser = new Parser();
131
        $config = $yamlParser->parse(file_get_contents($file));
132
        $processor = new Processor();
133
134
        return $processor->process($configTree, $config);
0 ignored issues
show
Bug introduced by
It seems like $config defined by $yamlParser->parse(file_get_contents($file)) on line 131 can also be of type string; however, Symfony\Component\Config...on\Processor::process() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
135
    }
136
137
    /**
138
     * Returns the configuration definition
139
     *
140
     * @return NodeInterface
141
     */
142
    protected function getConfigTree()
143
    {
144
        $treeBuilder = new TreeBuilder();
145
        $root = $treeBuilder->root('custom_entities');
146
        $root
147
            ->useAttributeAsKey('name')
148
            ->prototype('array')
149
                ->addDefaultsIfNotSet()
150
                ->children()
151
                    ->scalarNode('name')->end()
152
                    ->scalarNode('class')->defaultNull()->end()
153
                    ->scalarNode('entity_class')->defaultNull()->end()
154
                    ->scalarNode('extends')->defaultValue('default')->end()
155
                    ->arrayNode('options')
156
                        ->prototype('variable')
157
                        ->end()
158
                    ->end()
159
                    ->booleanNode('abstract')->defaultFalse()->end()
160
                    ->arrayNode('actions')
161
                        ->prototype('variable')
162
                        ->end()
163
                    ->end()
164
                ->end()
165
            ->end();
166
167
        return $treeBuilder->buildTree();
168
    }
169
}
170