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

Passed
Pull Request — 0.12 (#505)
by Jérémiah
20:07
created

ConfigParserPass::getConfigs()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 30
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 4

Importance

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