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 (#254)
by Jérémiah
09:17
created

OverblogGraphQLTypesExtension   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 199
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 28
lcom 1
cbo 7
dl 0
loc 199
ccs 92
cts 92
cp 1
rs 10
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A load() 0 10 1
A containerPrependExtensionConfig() 0 11 2
A prependExtensionConfigFromFiles() 0 13 3
A checkTypesDuplication() 0 13 2
B mappingConfig() 0 28 4
A detectFilesFromTypesMappings() 0 13 3
A mappingFromBundles() 0 15 2
C detectFilesByTypes() 0 34 7
A bundleDir() 0 7 1
A getAliasPrefix() 0 4 1
A getAlias() 0 4 1
A getConfiguration() 0 4 1
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 32
    public function load(array $configs, ContainerBuilder $container)
43
    {
44 32
        $this->checkTypesDuplication($configs);
45
        // flatten config is a requirement to support inheritance
46 31
        $flattenConfig = [call_user_func_array('array_merge', $configs)];
47 31
        $configuration = $this->getConfiguration($flattenConfig, $container);
48 31
        $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 26
        $container->setParameter($this->getAlias().'.config', $config);
51 26
    }
52
53 27
    public function containerPrependExtensionConfig(array $config, ContainerBuilder $container)
54
    {
55 27
        $typesMappings = $this->mappingConfig($config, $container);
56
        // reset treated files
57 27
        $this->treatedFiles = [];
58 27
        $typesMappings = call_user_func_array('array_merge', $typesMappings);
59
        // treats mappings
60 27
        foreach ($typesMappings as $params) {
61 27
            $this->prependExtensionConfigFromFiles($params['type'], $params['files'], $container);
62
        }
63 25
    }
64
65
    /**
66
     * @param $type
67
     * @param SplFileInfo[]    $files
68
     * @param ContainerBuilder $container
69
     */
70 27
    private function prependExtensionConfigFromFiles($type, $files, ContainerBuilder $container)
71
    {
72 27
        foreach ($files as $file) {
73 27
            $fileRealPath = $file->getRealPath();
74 27
            if (isset($this->treatedFiles[$fileRealPath])) {
75 1
                continue;
76
            }
77
78 27
            $typeConfig = call_user_func(self::PARSERS[$type].'::parse', $file, $container);
79 25
            $container->prependExtensionConfig($this->getAlias(), $typeConfig);
80 25
            $this->treatedFiles[$file->getRealPath()] = true;
81
        }
82 25
    }
83
84 32
    private function checkTypesDuplication(array $typeConfigs)
85
    {
86 32
        $types = call_user_func_array('array_merge', array_map('array_keys', $typeConfigs));
87 32
        $duplications = array_keys(array_filter(array_count_values($types), function ($count) {
88 32
            return $count > 1;
89 32
        }));
90 32
        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 31
    }
97
98 27
    private function mappingConfig(array $config, ContainerBuilder $container)
99
    {
100
        // use default value if needed
101 27
        $config = array_replace_recursive(self::$defaultDefaultConfig, $config);
102
103 27
        $mappingConfig = $config['definitions']['mappings'];
104 27
        $typesMappings = $mappingConfig['types'];
105
106
        // app only config files (yml or xml or graphql)
107 27
        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 27
        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 24
            $typesMappings[] = [
116 24
                'dir' => $this->bundleDir(OverblogGraphQLBundle::class).'/Resources/config/graphql',
117
                'types' => ['yaml'],
118
            ];
119
        }
120
121
        // from config
122 27
        $typesMappings = $this->detectFilesFromTypesMappings($typesMappings, $container);
123
124 27
        return $typesMappings;
125
    }
126
127 27
    private function detectFilesFromTypesMappings(array $typesMappings, ContainerBuilder $container)
128
    {
129 27
        return array_filter(array_map(
130 27
            function (array $typeMapping) use ($container) {
131 27
                $suffix = isset($typeMapping['suffix']) ? $typeMapping['suffix'] : '';
132 27
                $types = isset($typeMapping['types']) ? $typeMapping['types'] : null;
133 27
                $params = $this->detectFilesByTypes($container, $typeMapping['dir'], $suffix, $types);
134
135 27
                return $params;
136 27
            },
137 27
            $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 27
    private function detectFilesByTypes(ContainerBuilder $container, $path, $suffix, array $types = null)
158
    {
159
        // add the closest existing directory as a resource
160 27
        $resource = $path;
161 27
        while (!is_dir($resource)) {
162 1
            $resource = dirname($resource);
163
        }
164 27
        $container->addResource(new FileResource($resource));
165
166 27
        $stopOnFirstTypeMatching = empty($types);
167
168 27
        $types = $stopOnFirstTypeMatching ? array_keys(self::SUPPORTED_TYPES_EXTENSIONS) : $types;
169 27
        $files = [];
170
171 27
        foreach ($types as $type) {
172 27
            $finder = Finder::create();
173
            try {
174 27
                $finder->files()->in($path)->name(sprintf('*%s.%s', $suffix, self::SUPPORTED_TYPES_EXTENSIONS[$type]));
175 1
            } catch (\InvalidArgumentException $e) {
176 1
                continue;
177
            }
178 27
            if ($finder->count() > 0) {
179 27
                $files[] = [
180 27
                    'type' => $type,
181 27
                    'files' => $finder,
182
                ];
183 27
                if ($stopOnFirstTypeMatching) {
184 27
                    break;
185
                }
186
            }
187
        }
188
189 27
        return $files;
190
    }
191
192 25
    private function bundleDir($bundleClass)
193
    {
194 25
        $bundle = new \ReflectionClass($bundleClass);
195 25
        $bundleDir = dirname($bundle->getFileName());
196
197 25
        return $bundleDir;
198
    }
199
200 26
    public function getAliasPrefix()
201
    {
202 26
        return 'overblog_graphql';
203
    }
204
205 26
    public function getAlias()
206
    {
207 26
        return $this->getAliasPrefix().'_types';
208
    }
209
210 31
    public function getConfiguration(array $config, ContainerBuilder $container)
211
    {
212 31
        return new TypesConfiguration();
213
    }
214
}
215