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 — annotations (#407)
by Vincent
22:42 queued 11:44
created

detectFilesByTypes()   B

Complexity

Conditions 7
Paths 20

Size

Total Lines 34

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 7

Importance

Changes 0
Metric Value
dl 0
loc 34
c 0
b 0
f 0
ccs 20
cts 20
cp 1
rs 8.4426
cc 7
nc 20
nop 4
crap 7
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Overblog\GraphQLBundle\DependencyInjection;
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\OverblogGraphQLBundle;
13
use Symfony\Component\Config\Definition\Exception\ForbiddenOverwriteException;
14
use Symfony\Component\Config\Resource\FileResource;
15
use Symfony\Component\DependencyInjection\ContainerBuilder;
16
use Symfony\Component\Finder\Finder;
17
use Symfony\Component\Finder\SplFileInfo;
18
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
19
20
class OverblogGraphQLTypesExtension extends Extension
21
{
22
    public const SUPPORTED_TYPES_EXTENSIONS = [
23
        'yaml' => '{yaml,yml}',
24
        'xml' => 'xml',
25
        'graphql' => '{graphql,graphqls}',
26
        'annotation' => 'php',
27
    ];
28
29
    public const PARSERS = [
30
        'yaml' => YamlParser::class,
31
        'xml' => XmlParser::class,
32
        'graphql' => GraphQLParser::class,
33
        'annotation' => AnnotationParser::class,
34
    ];
35
36
    private static $defaultDefaultConfig = [
37
        'definitions' => [
38
            'mappings' => [
39
                'auto_discover' => [
40
                    'root_dir' => true,
41
                    'bundles' => true,
42
                ],
43
                'types' => [],
44
            ],
45
        ],
46
    ];
47
48
    private $treatedFiles = [];
49
    private $preTreatedFiles = [];
50
51
    public const DEFAULT_TYPES_SUFFIX = '.types';
52
53 38
    public function load(array $configs, ContainerBuilder $container): void
54
    {
55 38
        $configs = \array_filter($configs);
56 38
        if (\count($configs) > 1) {
57 1
            throw new \InvalidArgumentException('Configs type should never contain more than one config to deal with inheritance.');
58
        }
59 37
        $configuration = $this->getConfiguration($configs, $container);
60 37
        $config = $this->processConfiguration($configuration, $configs);
61
62 32
        $container->setParameter($this->getAlias().'.config', $config);
63 32
    }
64
65 33
    public function containerPrependExtensionConfig(array $configs, ContainerBuilder $container): void
66
    {
67 33
        $container->setParameter('overblog_graphql_types.classes_map', []);
68 33
        $typesMappings = $this->mappingConfig($configs, $container);
69
        // reset treated files
70 33
        $this->treatedFiles = [];
71 33
        $typesMappings = \call_user_func_array('array_merge', $typesMappings);
72 33
        $typeConfigs = [];
73
        // treats mappings
74
        // Pre-parse all files
75 33
        foreach ($typesMappings as $params) {
76 33
            $this->preParseTypeConfigFiles($params['type'], $params['files'], $container, $configs);
77
        }
78
79
        // Parse all files and get related config
80 33
        foreach ($typesMappings as $params) {
81 33
            $typeConfigs = \array_merge($typeConfigs, $this->parseTypeConfigFiles($params['type'], $params['files'], $container, $configs));
82
        }
83
84 31
        $this->checkTypesDuplication($typeConfigs);
85
        // flatten config is a requirement to support inheritance
86 31
        $flattenTypeConfig = \call_user_func_array('array_merge', $typeConfigs);
87
88 31
        $container->prependExtensionConfig($this->getAlias(), $flattenTypeConfig);
89 31
    }
90
91
    /**
92
     * @param string           $type
93
     * @param SplFileInfo[]    $files
94
     * @param ContainerBuilder $container
95
     * @param array            $config
0 ignored issues
show
Documentation introduced by
There is no parameter named $config. Did you maybe mean $configs?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
96
     */
97 33
    private function preParseTypeConfigFiles($type, $files, ContainerBuilder $container, array $configs): void
98
    {
99 33
        if (\is_a(self::PARSERS[$type], PreParserInterface::class, true)) {
100
            foreach ($files as $file) {
101
                $fileRealPath = $file->getRealPath();
102
                if (isset($this->preTreatedFiles[$fileRealPath])) {
103
                    continue;
104
                }
105
106
                \call_user_func(self::PARSERS[$type].'::preParse', $file, $container, $configs);
107
                $this->preTreatedFiles[$file->getRealPath()] = true;
108
            }
109
        }
110 33
    }
111
112
    /**
113
     * @param $type
114
     * @param SplFileInfo[]    $files
115
     * @param ContainerBuilder $container
116
     * @param array            $config
0 ignored issues
show
Documentation introduced by
There is no parameter named $config. Did you maybe mean $configs?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
117
     *
118
     * @return array
119
     */
120 33
    private function parseTypeConfigFiles($type, $files, ContainerBuilder $container, array $configs)
121
    {
122 33
        $config = [];
123 33
        foreach ($files as $file) {
124 33
            $fileRealPath = $file->getRealPath();
125 33
            if (isset($this->treatedFiles[$fileRealPath])) {
126 1
                continue;
127
            }
128
129 33
            $config[] = \call_user_func(self::PARSERS[$type].'::parse', $file, $container, $configs);
130 31
            $this->treatedFiles[$file->getRealPath()] = true;
131
        }
132
133 31
        return $config;
134
    }
135
136 31
    private function checkTypesDuplication(array $typeConfigs): void
137
    {
138 31
        $types = \call_user_func_array('array_merge', \array_map('array_keys', $typeConfigs));
139
        $duplications = \array_keys(\array_filter(\array_count_values($types), function ($count) {
140 31
            return $count > 1;
141 31
        }));
142 31
        if (!empty($duplications)) {
143
            throw new ForbiddenOverwriteException(\sprintf(
144
                'Types (%s) cannot be overwritten. See inheritance doc section for more details.',
145
                \implode(', ', \array_map('json_encode', $duplications))
146
            ));
147
        }
148 31
    }
149
150 33
    private function mappingConfig(array $config, ContainerBuilder $container)
151
    {
152
        // use default value if needed
153 33
        $config = \array_replace_recursive(self::$defaultDefaultConfig, $config);
154
155 33
        $mappingConfig = $config['definitions']['mappings'];
156 33
        $typesMappings = $mappingConfig['types'];
157
158
        // app only config files (yml or xml or graphql)
159 33
        if ($mappingConfig['auto_discover']['root_dir'] && $container->hasParameter('kernel.root_dir')) {
160 1
            $typesMappings[] = ['dir' => $container->getParameter('kernel.root_dir').'/config/graphql', 'types' => null];
161
        }
162 33
        if ($mappingConfig['auto_discover']['bundles']) {
163 3
            $mappingFromBundles = $this->mappingFromBundles($container);
164 3
            $typesMappings = \array_merge($typesMappings, $mappingFromBundles);
165
        } else {
166
            // enabled only for this bundle
167 30
            $typesMappings[] = [
168 30
                'dir' => $this->bundleDir(OverblogGraphQLBundle::class).'/Resources/config/graphql',
169
                'types' => ['yaml'],
170
            ];
171
        }
172
173
        // from config
174 33
        $typesMappings = $this->detectFilesFromTypesMappings($typesMappings, $container);
175
176 33
        return $typesMappings;
177
    }
178
179 33
    private function detectFilesFromTypesMappings(array $typesMappings, ContainerBuilder $container)
180
    {
181 33
        return \array_filter(\array_map(
182
            function (array $typeMapping) use ($container) {
183 33
                $suffix = $typeMapping['suffix'] ?? '';
184 33
                $types = $typeMapping['types'] ?? null;
185 33
                $params = $this->detectFilesByTypes($container, $typeMapping['dir'], $suffix, $types);
186
187 33
                return $params;
188 33
            },
189 33
            $typesMappings
190
        ));
191
    }
192
193 3
    private function mappingFromBundles(ContainerBuilder $container)
194
    {
195 3
        $typesMappings = [];
196 3
        $bundles = $container->getParameter('kernel.bundles');
197
198
        // auto detect from bundle
199 3
        foreach ($bundles as $name => $class) {
200 1
            $bundleDir = $this->bundleDir($class);
201
202
            // only config files (yml or xml)
203 1
            $typesMappings[] = ['dir' => $bundleDir.'/Resources/config/graphql', 'types' => null];
204
        }
205
206 3
        return $typesMappings;
207
    }
208
209 33
    private function detectFilesByTypes(ContainerBuilder $container, $path, $suffix, array $types = null)
210
    {
211
        // add the closest existing directory as a resource
212 33
        $resource = $path;
213 33
        while (!\is_dir($resource)) {
214 1
            $resource = \dirname($resource);
215
        }
216 33
        $container->addResource(new FileResource($resource));
217
218 33
        $stopOnFirstTypeMatching = empty($types);
219
220 33
        $types = $stopOnFirstTypeMatching ? \array_keys(self::SUPPORTED_TYPES_EXTENSIONS) : $types;
221 33
        $files = [];
222
223 33
        foreach ($types as $type) {
224 33
            $finder = Finder::create();
225
            try {
226 33
                $finder->files()->in($path)->name(\sprintf('*%s.%s', $suffix, self::SUPPORTED_TYPES_EXTENSIONS[$type]));
227 1
            } catch (\InvalidArgumentException $e) {
228 1
                continue;
229
            }
230 33
            if ($finder->count() > 0) {
231 33
                $files[] = [
232 33
                    'type' => $type,
233 33
                    'files' => $finder,
234
                ];
235 33
                if ($stopOnFirstTypeMatching) {
236 33
                    break;
237
                }
238
            }
239
        }
240
241 33
        return $files;
242
    }
243
244 31
    private function bundleDir($bundleClass)
245
    {
246 31
        $bundle = new \ReflectionClass($bundleClass);
247 31
        $bundleDir = \dirname($bundle->getFileName());
248
249 31
        return $bundleDir;
250
    }
251
252 32
    public function getAliasPrefix()
253
    {
254 32
        return 'overblog_graphql';
255
    }
256
257 32
    public function getAlias()
258
    {
259 32
        return $this->getAliasPrefix().'_types';
260
    }
261
262 37
    public function getConfiguration(array $config, ContainerBuilder $container)
263
    {
264 37
        return new TypesConfiguration();
265
    }
266
}
267