Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Completed
Pull Request — master (#685)
by
unknown
14:33 queued 11:42
created

ConfigParserPass::processConfiguration()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Overblog\GraphQLBundle\DependencyInjection\Compiler;
6
7
use Overblog\GraphQLBundle\Config\Parser\AnnotationParser;
8
use Overblog\GraphQLBundle\Config\Parser\GraphQLParser;
9
use Overblog\GraphQLBundle\Config\Parser\PreParserInterface;
10
use Overblog\GraphQLBundle\Config\Parser\XmlParser;
11
use Overblog\GraphQLBundle\Config\Parser\YamlParser;
12
use Overblog\GraphQLBundle\DependencyInjection\TypesConfiguration;
13
use Overblog\GraphQLBundle\OverblogGraphQLBundle;
14
use Symfony\Component\Config\Definition\Exception\ForbiddenOverwriteException;
15
use Symfony\Component\Config\Definition\Processor;
16
use Symfony\Component\Config\Resource\FileResource;
17
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
18
use Symfony\Component\DependencyInjection\ContainerBuilder;
19
use Symfony\Component\Finder\Finder;
20
use Symfony\Component\Finder\SplFileInfo;
21
22
class ConfigParserPass implements CompilerPassInterface
23
{
24
    public const SUPPORTED_TYPES_EXTENSIONS = [
25
        'yaml' => '{yaml,yml}',
26
        'xml' => 'xml',
27
        'graphql' => '{graphql,graphqls}',
28
        'annotation' => 'php',
29
    ];
30
31
    public const PARSERS = [
32
        'yaml' => YamlParser::class,
33
        'xml' => XmlParser::class,
34
        'graphql' => GraphQLParser::class,
35
        'annotation' => AnnotationParser::class,
36
    ];
37
38
    private static $defaultDefaultConfig = [
39
        'definitions' => [
40
            'mappings' => [
41
                'auto_discover' => [
42
                    'root_dir' => true,
43
                    'bundles' => true,
44
                ],
45
                'types' => [],
46
            ],
47
        ],
48
    ];
49
50
    private $treatedFiles = [];
51
    private $preTreatedFiles = [];
52
53
    public const DEFAULT_TYPES_SUFFIX = '.types';
54
55 39
    public function process(ContainerBuilder $container): void
56
    {
57 39
        $config = $this->processConfiguration([$this->getConfigs($container)]);
58 36
        $container->setParameter($this->getAlias().'.config', $config);
59 36
    }
60
61 47
    public function processConfiguration(array $configs): array
62
    {
63 47
        return (new Processor())->processConfiguration(new TypesConfiguration(), $configs);
64
    }
65
66 39
    private function getConfigs(ContainerBuilder $container): array
67
    {
68 39
        $config = $container->getParameterBag()->resolveValue($container->getParameter('overblog_graphql.config'));
69 39
        $container->getParameterBag()->remove('overblog_graphql.config');
70 39
        $container->setParameter($this->getAlias().'.classes_map', []);
71 39
        $typesMappings = $this->mappingConfig($config, $container);
72
        // reset treated files
73 39
        $this->treatedFiles = [];
74 39
        $typesMappings = \array_merge(...$typesMappings);
75 39
        $typeConfigs = [];
76
77
        // treats mappings
78
        // Pre-parse all files
79 39
        AnnotationParser::reset();
80 39
        $typesNeedPreParsing = $this->typesNeedPreParsing();
81 39
        foreach ($typesMappings as $params) {
82 39
            if ($typesNeedPreParsing[$params['type']]) {
83 1
                $this->parseTypeConfigFiles($params['type'], $params['files'], $container, $config, true);
84
            }
85
        }
86
87
        // Parse all files and get related config
88 39
        foreach ($typesMappings as $params) {
89 39
            $typeConfigs = \array_merge($typeConfigs, $this->parseTypeConfigFiles($params['type'], $params['files'], $container, $config));
90
        }
91
92 37
        $this->checkTypesDuplication($typeConfigs);
93
        // flatten config is a requirement to support inheritance
94 37
        $flattenTypeConfig = \array_merge(...$typeConfigs);
95
96 37
        return $flattenTypeConfig;
97
    }
98
99 39
    private function typesNeedPreParsing(): array
100
    {
101 39
        $needPreParsing = [];
102 39
        foreach (self::PARSERS as $type => $className) {
103 39
            $needPreParsing[$type] = \is_a($className, PreParserInterface::class, true);
104
        }
105
106 39
        return $needPreParsing;
107
    }
108
109
    /**
110
     * @param $type
111
     * @param SplFileInfo[] $files
112
     *
113
     * @return array
114
     */
115 39
    private function parseTypeConfigFiles($type, $files, ContainerBuilder $container, array $configs, bool $preParse = false)
116
    {
117 39
        if ($preParse) {
118 1
            $method = 'preParse';
119 1
            $treatedFiles = &$this->preTreatedFiles;
120
        } else {
121 39
            $method = 'parse';
122 39
            $treatedFiles = &$this->treatedFiles;
123
        }
124
125 39
        $config = [];
126 39
        foreach ($files as $file) {
127 39
            $fileRealPath = $file->getRealPath();
128 39
            if (isset($treatedFiles[$fileRealPath])) {
129 1
                continue;
130
            }
131
132 39
            $config[] = \call_user_func([self::PARSERS[$type], $method], $file, $container, $configs);
133 37
            $treatedFiles[$file->getRealPath()] = true;
134
        }
135
136 37
        return $config;
137
    }
138
139 37
    private function checkTypesDuplication(array $typeConfigs): void
140
    {
141 37
        $types = \array_merge(...\array_map('array_keys', $typeConfigs));
142
        $duplications = \array_keys(\array_filter(\array_count_values($types), function ($count) {
143 37
            return $count > 1;
144 37
        }));
145 37
        if (!empty($duplications)) {
146
            throw new ForbiddenOverwriteException(\sprintf(
147
                'Types (%s) cannot be overwritten. See inheritance doc section for more details.',
148
                \implode(', ', \array_map('json_encode', $duplications))
149
            ));
150
        }
151 37
    }
152
153 39
    private function mappingConfig(array $config, ContainerBuilder $container)
154
    {
155
        // use default value if needed
156 39
        $config = \array_replace_recursive(self::$defaultDefaultConfig, $config);
157
158 39
        $mappingConfig = $config['definitions']['mappings'];
159 39
        $typesMappings = $mappingConfig['types'];
160
161
        // app only config files (yml or xml or graphql)
162 39
        if ($mappingConfig['auto_discover']['root_dir'] && $container->hasParameter('kernel.root_dir')) {
163 1
            $typesMappings[] = ['dir' => $container->getParameter('kernel.root_dir').'/config/graphql', 'types' => null];
164
        }
165 39
        if ($mappingConfig['auto_discover']['bundles']) {
166 4
            $mappingFromBundles = $this->mappingFromBundles($container);
167 4
            $typesMappings = \array_merge($typesMappings, $mappingFromBundles);
168
        } else {
169
            // enabled only for this bundle
170 35
            $typesMappings[] = [
171 35
                'dir' => $this->bundleDir(OverblogGraphQLBundle::class).'/Resources/config/graphql',
172
                'types' => ['yaml'],
173
            ];
174
        }
175
176
        // from config
177 39
        $typesMappings = $this->detectFilesFromTypesMappings($typesMappings, $container);
178
179 39
        return $typesMappings;
180
    }
181
182 39
    private function detectFilesFromTypesMappings(array $typesMappings, ContainerBuilder $container)
183
    {
184 39
        return \array_filter(\array_map(
185
            function (array $typeMapping) use ($container) {
186 39
                $suffix = $typeMapping['suffix'] ?? '';
187 39
                $types = $typeMapping['types'] ?? null;
188 39
                $params = $this->detectFilesByTypes($container, $typeMapping['dir'], $suffix, $types);
189
190 39
                return $params;
191
            },
192 39
            $typesMappings
193
        ));
194
    }
195
196 4
    private function mappingFromBundles(ContainerBuilder $container)
197
    {
198 4
        $typesMappings = [];
199 4
        $bundles = $container->getParameter('kernel.bundles');
200
201
        // auto detect from bundle
202 4
        foreach ($bundles as $name => $class) {
203 1
            $bundleDir = $this->bundleDir($class);
204
205
            // only config files (yml or xml)
206 1
            $typesMappings[] = ['dir' => $bundleDir.'/Resources/config/graphql', 'types' => null];
207
        }
208
209 4
        return $typesMappings;
210
    }
211
212 39
    private function detectFilesByTypes(ContainerBuilder $container, $path, $suffix, array $types = null)
213
    {
214
        // add the closest existing directory as a resource
215 39
        $resource = $path;
216 39
        while (!\is_dir($resource)) {
217 1
            $resource = \dirname($resource);
218
        }
219 39
        $container->addResource(new FileResource($resource));
220
221 39
        $stopOnFirstTypeMatching = empty($types);
222
223 39
        $types = $stopOnFirstTypeMatching ? \array_keys(self::SUPPORTED_TYPES_EXTENSIONS) : $types;
224 39
        $files = [];
225
226 39
        foreach ($types as $type) {
227 39
            $finder = Finder::create();
228
            try {
229 39
                $finder->files()->in($path)->name(\sprintf('*%s.%s', $suffix, self::SUPPORTED_TYPES_EXTENSIONS[$type]));
230 1
            } catch (\InvalidArgumentException $e) {
231 1
                continue;
232
            }
233 39
            if ($finder->count() > 0) {
234 39
                $files[] = [
235 39
                    'type' => $type,
236 39
                    'files' => $finder,
237
                ];
238 39
                if ($stopOnFirstTypeMatching) {
239 1
                    break;
240
                }
241
            }
242
        }
243
244 39
        return $files;
245
    }
246
247 36
    private function bundleDir($bundleClass)
248
    {
249 36
        $bundle = new \ReflectionClass($bundleClass);
250 36
        $bundleDir = \dirname($bundle->getFileName());
251
252 36
        return $bundleDir;
253
    }
254
255 39
    private function getAliasPrefix()
256
    {
257 39
        return 'overblog_graphql';
258
    }
259
260 39
    private function getAlias()
261
    {
262 39
        return $this->getAliasPrefix().'_types';
263
    }
264
}
265