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
Push — master ( b20e51...080493 )
by Jérémiah
17:11 queued 10s
created

TypeGenerator   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 257
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 44
eloc 107
dl 0
loc 257
ccs 99
cts 99
cp 1
rs 8.8798
c 0
b 0
f 0

19 Methods

Rating   Name   Duplication   Size   Complexity  
A setBaseCacheDir() 0 3 1
A generateParentClassName() 0 6 2
A getBaseCacheDir() 0 3 1
A resolveTypeCode() 0 3 1
A generateClassName() 0 3 1
A generateComplexity() 0 22 2
A generateTypeName() 0 3 1
A generateClassDocBlock() 0 3 1
A generatePublic() 0 18 2
A compile() 0 22 5
A generateUseStrictAccess() 0 15 6
A __construct() 0 21 4
A generateAccess() 0 11 3
A getCacheDir() 0 7 4
A generateScalarType() 0 3 1
A setCacheDir() 0 5 1
A generateClosureUseStatements() 0 3 1
A loadClasses() 0 17 6
A getClassesMap() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like TypeGenerator often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use TypeGenerator, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Overblog\GraphQLBundle\Generator;
6
7
use Composer\Autoload\ClassLoader;
8
use Overblog\GraphQLBundle\Config\Processor;
9
use Overblog\GraphQLBundle\Definition\Argument;
10
use Overblog\GraphQLBundle\Definition\Type\CustomScalarType;
11
use Overblog\GraphQLBundle\ExpressionLanguage\ExpressionLanguage;
12
use Overblog\GraphQLGenerator\Generator\TypeGenerator as BaseTypeGenerator;
13
use Symfony\Component\ExpressionLanguage\Expression;
14
use Symfony\Component\Filesystem\Filesystem;
15
16
class TypeGenerator extends BaseTypeGenerator
17
{
18
    public const USE_FOR_CLOSURES = '$globalVariable';
19
20
    public const DEFAULT_CONFIG_PROCESSOR = [Processor::class, 'process'];
21
22
    private $cacheDir;
23
24
    private $configProcessor;
25
26
    private $configs;
27
28
    private $useClassMap;
29
30
    private $baseCacheDir;
31
32
    private static $classMapLoaded = false;
33
34 66
    public function __construct(
35
        $classNamespace,
36
        array $skeletonDirs,
37
        $cacheDir,
38
        array $configs,
39
        $useClassMap = true,
40
        callable $configProcessor = null,
41
        $baseCacheDir = null,
42
        $cacheDirMask = null
43
    ) {
44 66
        $this->setCacheDir($cacheDir);
45 66
        $this->configProcessor = null === $configProcessor ? static::DEFAULT_CONFIG_PROCESSOR : $configProcessor;
46 66
        $this->configs = $configs;
47 66
        $this->useClassMap = $useClassMap;
48 66
        $this->baseCacheDir = $baseCacheDir;
49 66
        if (null === $cacheDirMask) {
50
            // we apply permission 0777 for default cache dir otherwise we apply 0775.
51 65
            $cacheDirMask = null === $cacheDir ? 0777 : 0775;
52
        }
53
54 66
        parent::__construct($classNamespace, $skeletonDirs, $cacheDirMask);
55 66
    }
56
57
    /**
58
     * @return string|null
59
     */
60 30
    public function getBaseCacheDir()
61
    {
62 30
        return $this->baseCacheDir;
63
    }
64
65
    /**
66
     * @param string|null $baseCacheDir
67
     */
68 30
    public function setBaseCacheDir($baseCacheDir): void
69
    {
70 30
        $this->baseCacheDir = $baseCacheDir;
71 30
    }
72
73
    /**
74
     * @return string|null
75
     */
76 33
    public function getCacheDir(/*bool $useDefault = true*/)
77
    {
78 33
        $useDefault = \func_num_args() > 0 ? \func_get_arg(0) : true;
79 33
        if ($useDefault) {
80 33
            return $this->cacheDir ?: $this->baseCacheDir.'/overblog/graphql-bundle/__definitions__';
81
        } else {
82 30
            return $this->cacheDir;
83
        }
84
    }
85
86
    /**
87
     * @param string|null $cacheDir
88
     *
89
     * @return $this
90
     */
91 66
    public function setCacheDir($cacheDir)
92
    {
93 66
        $this->cacheDir = $cacheDir;
94
95 66
        return $this;
96
    }
97
98 33
    protected function generateClassName(array $config)
99
    {
100 33
        return $config['class_name'];
101
    }
102
103
    protected function generateClassDocBlock(array $value)
104
    {
105
        return <<<'EOF'
106
107
/**
108
 * THIS FILE WAS GENERATED AND SHOULD NOT BE MODIFIED!
109
 */
110
EOF;
111
    }
112
113 32
    protected function generateClosureUseStatements(array $config)
114
    {
115 32
        return \sprintf('use (%s) ', static::USE_FOR_CLOSURES);
116
    }
117
118 26
    protected function resolveTypeCode($alias)
119
    {
120 26
        return  \sprintf('$globalVariable->get(\'typeResolver\')->resolve(%s)', \var_export($alias, true));
121
    }
122
123 32
    protected function generatePublic(array $value)
124
    {
125 32
        if (!$this->arrayKeyExistsAndIsNotNull($value, 'public')) {
126 32
            return 'null';
127
        }
128
129 1
        $publicCallback = $this->callableCallbackFromArrayValue($value, 'public', '$typeName, $fieldName');
130
131
        $code = <<<'CODE'
132 1
function ($fieldName) <closureUseStatements> {
133
<spaces><spaces>$publicCallback = %s;
134
<spaces><spaces>return call_user_func($publicCallback, $this->name, $fieldName);
135
<spaces>}
136
CODE;
137
138 1
        $code = \sprintf($code, $publicCallback);
139
140 1
        return $code;
141
    }
142
143 32
    protected function generateAccess(array $value)
144
    {
145 32
        if (!$this->arrayKeyExistsAndIsNotNull($value, 'access')) {
146 32
            return 'null';
147
        }
148
149 2
        if (\is_bool($value['access'])) {
150 1
            return $this->varExport($value['access']);
151
        }
152
153 2
        return $this->callableCallbackFromArrayValue($value, 'access', '$value, $args, $context, \\GraphQL\\Type\\Definition\\ResolveInfo $info, $object');
154
    }
155
156
    /**
157
     * @param array $value
158
     *
159
     * @return string
160
     */
161 32
    protected function generateComplexity(array $value)
162
    {
163 32
        $resolveComplexity = parent::generateComplexity($value);
164 32
        $resolveComplexity = \ltrim($this->prefixCodeWithSpaces($resolveComplexity));
165
166 32
        if ('null' === $resolveComplexity) {
167 32
            return $resolveComplexity;
168
        }
169
170 3
        $argumentClass = $this->shortenClassName(Argument::class);
171
172
        $code = <<<'CODE'
173 3
function ($childrenComplexity, $args = []) <closureUseStatements>{
174
<spaces><spaces>$resolveComplexity = %s;
175
176
<spaces><spaces>return call_user_func_array($resolveComplexity, [$childrenComplexity, new %s($args)]);
177
<spaces>}
178
CODE;
179
180 3
        $code = \sprintf($code, $resolveComplexity, $argumentClass);
181
182 3
        return $code;
183
    }
184
185
    /**
186
     * @param array $value
187
     *
188
     * @return string
189
     */
190 3
    protected function generateScalarType(array $value)
191
    {
192 3
        return $this->callableCallbackFromArrayValue($value, 'scalarType');
193
    }
194
195 32
    protected function generateParentClassName(array $config)
196
    {
197 32
        if ('custom-scalar' === $config['type']) {
198 3
            return $this->shortenClassName(CustomScalarType::class);
199
        } else {
200 32
            return parent::generateParentClassName($config);
201
        }
202
    }
203
204 32
    protected function generateTypeName(array $config)
205
    {
206 32
        return $this->varExport($config['config']['name']);
207
    }
208
209 32
    protected function generateUseStrictAccess(array $value)
210
    {
211 32
        $expressionLanguage = $this->getExpressionLanguage();
212 32
        $useStrictAccess = 'true';
213 32
        if (null !== $expressionLanguage && $this->arrayKeyExistsAndIsNotNull($value, 'access') && $value['access'] instanceof Expression) {
214 2
            $names = ExpressionLanguage::KNOWN_NAMES;
215 2
            if ($expressionLanguage instanceof ExpressionLanguage) {
216 2
                $names = \array_merge($names, $expressionLanguage->getGlobalNames());
217
            }
218 2
            $parsedExpression = $expressionLanguage->parse($value['access'], $names);
219 2
            $serializedNode = \str_replace("\n", '//', (string) $parsedExpression->getNodes());
220 2
            $useStrictAccess = false === \strpos($serializedNode, 'NameNode(name: \'object\')') ? 'true' : 'false';
221
        }
222
223 32
        return $useStrictAccess;
224
    }
225
226 33
    public function compile($mode): array
227
    {
228 33
        $cacheDir = $this->getCacheDir();
229 33
        $writeMode = $mode & self::MODE_WRITE;
230 33
        if ($writeMode && \file_exists($cacheDir)) {
231 1
            $fs = new Filesystem();
232 1
            $fs->remove($cacheDir);
233
        }
234 33
        $configs = \call_user_func($this->configProcessor, $this->configs);
235 33
        $classes = $this->generateClasses($configs, $cacheDir, $mode);
236
237 33
        if ($writeMode && $this->useClassMap) {
238 31
            $content = "<?php\nreturn ".\var_export($classes, true).';';
239
            // replaced hard-coding absolute path by __DIR__ (see https://github.com/overblog/GraphQLBundle/issues/167)
240 31
            $content = \str_replace(' => \''.$cacheDir, ' => __DIR__ . \'', $content);
241
242 31
            \file_put_contents($this->getClassesMap(), $content);
243
244 31
            $this->loadClasses(true);
245
        }
246
247 33
        return $classes;
248
    }
249
250 61
    public function loadClasses($forceReload = false): void
251
    {
252 61
        if ($this->useClassMap && (!self::$classMapLoaded || $forceReload)) {
253 31
            $classMapFile = $this->getClassesMap();
254 31
            $classes = \file_exists($classMapFile) ? require $classMapFile : [];
255
            /** @var ClassLoader $mapClassLoader */
256 31
            static $mapClassLoader = null;
257 31
            if (null === $mapClassLoader) {
258 1
                $mapClassLoader = new ClassLoader();
259 1
                $mapClassLoader->setClassMapAuthoritative(true);
260
            } else {
261 30
                $mapClassLoader->unregister();
262
            }
263 31
            $mapClassLoader->addClassMap($classes);
264 31
            $mapClassLoader->register();
265
266 31
            self::$classMapLoaded = true;
267
        }
268 61
    }
269
270 31
    private function getClassesMap(): string
271
    {
272 31
        return $this->getCacheDir().'/__classes.map';
273
    }
274
}
275