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 — master (#277)
by Jérémiah
14:57
created

OverblogGraphQLTypesExtension::detectFilesByType()   B

Complexity

Conditions 6
Paths 16

Size

Total Lines 29
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 29
ccs 15
cts 15
cp 1
rs 8.439
c 0
b 0
f 0
cc 6
eloc 17
nc 16
nop 4
crap 6
1
<?php
2
3
namespace Overblog\GraphQLBundle\DependencyInjection;
4
5
use Overblog\GraphQLBundle\Config\Parser\GraphQLParser;
6
use Overblog\GraphQLBundle\Config\Parser\XmlParser;
7
use Overblog\GraphQLBundle\Config\Parser\YamlParser;
8
use Overblog\GraphQLBundle\OverblogGraphQLBundle;
9
use Symfony\Component\Config\Definition\Exception\ForbiddenOverwriteException;
10
use Symfony\Component\Config\Resource\FileResource;
11
use Symfony\Component\DependencyInjection\ContainerBuilder;
12
use Symfony\Component\Finder\Finder;
13
use Symfony\Component\Finder\SplFileInfo;
14
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
15
16
class OverblogGraphQLTypesExtension extends Extension
17
{
18
    const SUPPORTED_TYPES_EXTENSIONS = ['yaml' => '{yaml,yml}', 'xml' => 'xml', 'graphql' => '{graphql,graphqls}'];
19
20
    const PARSERS = [
21
        'yaml' => YamlParser::class,
22
        'xml' => XmlParser::class,
23
        'graphql' => GraphQLParser::class,
24
    ];
25
26
    private static $defaultDefaultConfig = [
27
        'definitions' => [
28
            'mappings' => [
29
                'auto_discover' => [
30
                    'root_dir' => true,
31
                    'bundles' => true,
32
                ],
33
                'types' => [],
34
            ],
35
        ],
36
    ];
37
38
    private $treatedFiles = [];
39
40
    const DEFAULT_TYPES_SUFFIX = '.types';
41
42 33
    public function load(array $configs, ContainerBuilder $container)
43
    {
44 33
        $this->checkTypesDuplication($configs);
45
        // flatten config is a requirement to support inheritance
46 32
        $flattenConfig = [call_user_func_array('array_merge', $configs)];
47 32
        $configuration = $this->getConfiguration($flattenConfig, $container);
48 32
        $config = $this->processConfiguration($configuration, $flattenConfig);
0 ignored issues
show
Bug introduced by
It seems like $configuration defined by $this->getConfiguration(...ttenConfig, $container) on line 47 can be null; however, Symfony\Component\Depend...:processConfiguration() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
49
50 27
        $container->setParameter($this->getAlias().'.config', $config);
51 27
    }
52
53 28
    public function containerPrependExtensionConfig(array $config, ContainerBuilder $container)
54
    {
55 28
        $typesMappings = $this->mappingConfig($config, $container);
56
        // reset treated files
57 28
        $this->treatedFiles = [];
58 28
        $typesMappings = call_user_func_array('array_merge', $typesMappings);
59
        // treats mappings
60 28
        foreach ($typesMappings as $params) {
61 28
            $this->prependExtensionConfigFromFiles($params['type'], $params['files'], $container);
62
        }
63 26
    }
64
65
    /**
66
     * @param $type
67
     * @param SplFileInfo[]    $files
68
     * @param ContainerBuilder $container
69
     */
70 28
    private function prependExtensionConfigFromFiles($type, $files, ContainerBuilder $container)
71
    {
72 28
        foreach ($files as $file) {
73 28
            $fileRealPath = $file->getRealPath();
74 28
            if (isset($this->treatedFiles[$fileRealPath])) {
75 1
                continue;
76
            }
77
78 28
            $typeConfig = call_user_func(self::PARSERS[$type].'::parse', $file, $container);
79 26
            $container->prependExtensionConfig($this->getAlias(), $typeConfig);
80 26
            $this->treatedFiles[$file->getRealPath()] = true;
81
        }
82 26
    }
83
84 33
    private function checkTypesDuplication(array $typeConfigs)
85
    {
86 33
        $types = call_user_func_array('array_merge', array_map('array_keys', $typeConfigs));
87 33
        $duplications = array_keys(array_filter(array_count_values($types), function ($count) {
88 33
            return $count > 1;
89 33
        }));
90 33
        if (!empty($duplications)) {
91 1
            throw new ForbiddenOverwriteException(sprintf(
92 1
                'Types (%s) cannot be overwritten. See inheritance doc section for more details.',
93 1
                implode(', ', array_map('json_encode', $duplications))
94
            ));
95
        }
96 32
    }
97
98 28
    private function mappingConfig(array $config, ContainerBuilder $container)
99
    {
100
        // use default value if needed
101 28
        $config = array_replace_recursive(self::$defaultDefaultConfig, $config);
102
103 28
        $mappingConfig = $config['definitions']['mappings'];
104 28
        $typesMappings = $mappingConfig['types'];
105
106
        // app only config files (yml or xml or graphql)
107 28
        if ($mappingConfig['auto_discover']['root_dir'] && $container->hasParameter('kernel.root_dir')) {
108 1
            $typesMappings[] = ['dir' => $container->getParameter('kernel.root_dir').'/config/graphql', 'types' => null];
109
        }
110 28
        if ($mappingConfig['auto_discover']['bundles']) {
111 3
            $mappingFromBundles = $this->mappingFromBundles($container);
112 3
            $typesMappings = array_merge($typesMappings, $mappingFromBundles);
113
        } else {
114
            // enabled only for this bundle
115 25
            $typesMappings[] = [
116 25
                'dir' => $this->bundleDir(OverblogGraphQLBundle::class).'/Resources/config/graphql',
117
                'types' => ['yaml'],
118
            ];
119
        }
120
121
        // from config
122 28
        $typesMappings = $this->detectFilesFromTypesMappings($typesMappings, $container);
123
124 28
        return $typesMappings;
125
    }
126
127 28
    private function detectFilesFromTypesMappings(array $typesMappings, ContainerBuilder $container)
128
    {
129 28
        return array_filter(array_map(
130 28
            function (array $typeMapping) use ($container) {
131 28
                $suffix = isset($typeMapping['suffix']) ? $typeMapping['suffix'] : '';
132 28
                $types = isset($typeMapping['types']) ? $typeMapping['types'] : null;
133 28
                $params = $this->detectFilesByTypes($container, $typeMapping['dir'], $suffix, $types);
134
135 28
                return $params;
136 28
            },
137 28
            $typesMappings
138
        ));
139
    }
140
141 3
    private function mappingFromBundles(ContainerBuilder $container)
142
    {
143 3
        $typesMappings = [];
144 3
        $bundles = $container->getParameter('kernel.bundles');
145
146
        // auto detect from bundle
147 3
        foreach ($bundles as $name => $class) {
148 1
            $bundleDir = $this->bundleDir($class);
149
150
            // only config files (yml or xml)
151 1
            $typesMappings[] = ['dir' => $bundleDir.'/Resources/config/graphql', 'types' => null];
152
        }
153
154 3
        return $typesMappings;
155
    }
156
157 28
    private function detectFilesByTypes(ContainerBuilder $container, $path, $suffix, array $types = null)
158
    {
159
        // add the closest existing directory as a resource
160 28
        $resource = $path;
161 28
        while (!is_dir($resource)) {
162 1
            $resource = dirname($resource);
163
        }
164 28
        $container->addResource(new FileResource($resource));
165
166 28
        $stopOnFirstTypeMatching = empty($types);
167
168 28
        $types = $stopOnFirstTypeMatching ? array_keys(self::SUPPORTED_TYPES_EXTENSIONS) : $types;
169 28
        $files = [];
170
171 28
        foreach ($types as $type) {
172 28
            $finder = Finder::create();
173
            try {
174 28
                $finder->files()->in($path)->name(sprintf('*%s.%s', $suffix, self::SUPPORTED_TYPES_EXTENSIONS[$type]));
175 1
            } catch (\InvalidArgumentException $e) {
176 1
                continue;
177
            }
178 28
            if ($finder->count() > 0) {
179 28
                $files[] = [
180 28
                    'type' => $type,
181 28
                    'files' => $finder,
182
                ];
183 28
                if ($stopOnFirstTypeMatching) {
184 28
                    break;
185
                }
186
            }
187
        }
188
189 28
        return $files;
190
    }
191
192 26
    private function bundleDir($bundleClass)
193
    {
194 26
        $bundle = new \ReflectionClass($bundleClass);
195 26
        $bundleDir = dirname($bundle->getFileName());
196
197 26
        return $bundleDir;
198
    }
199
200 27
    public function getAliasPrefix()
201
    {
202 27
        return 'overblog_graphql';
203
    }
204
205 27
    public function getAlias()
206
    {
207 27
        return $this->getAliasPrefix().'_types';
208
    }
209
210 32
    public function getConfiguration(array $config, ContainerBuilder $container)
211
    {
212 32
        return new TypesConfiguration();
213
    }
214
}
215