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.11 (#455)
by Jérémiah
16:51
created

AbstractClassGenerator::generateSpaces()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
/*
4
 * This file is part of the OverblogGraphQLPhpGenerator package.
5
 *
6
 * (c) Overblog <http://github.com/overblog/>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Overblog\GraphQLGenerator\Generator;
13
14
use Overblog\GraphQLGenerator\ClassUtils;
15
use Symfony\Component\ExpressionLanguage\Expression;
16
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
17
18
abstract class AbstractClassGenerator
19
{
20
    const SKELETON_FILE_PREFIX = '.php.skeleton';
21
22
    /**
23
     * The namespace that contains all classes.
24
     *
25
     * @var string
26
     */
27
    private $classNamespace;
28
29
    private $internalUseStatements = [];
30
31
    private $useStatements = [];
32
33
    private $traits = [];
34
35
    private $implements = [];
36
37
    private $skeletonDirs = [];
38
39
    /**
40
     * Number of spaces to use for indention in generated code.
41
     */
42
    private $numSpaces;
43
44
    /**
45
     * The actual spaces to use for indention.
46
     *
47
     * @var string
48
     */
49
    private $spaces;
50
51
    private static $templates = [];
52
53
    /**
54
     * @param string $classNamespace The namespace to use for the classes.
55
     * @param string[]|string $skeletonDirs
56
     */
57 102
    public function __construct($classNamespace = null, $skeletonDirs = [])
58
    {
59 102
        $this->setClassNamespace($classNamespace);
60 102
        $this->setSkeletonDirs($skeletonDirs);
61 102
        $this->setNumSpaces(4);
62 102
    }
63
64 64
    public function getClassNamespace()
65
    {
66 64
        return $this->classNamespace;
67
    }
68
69 102
    public function setClassNamespace($classNamespace)
70
    {
71 102
        $this->classNamespace = ClassUtils::cleanClasseName($classNamespace);
72
73 102
        return $this;
74
    }
75
76
    /**
77
     * @param string[]|string $skeletonDirs
78
     * @return $this
79
     */
80 102
    public function setSkeletonDirs($skeletonDirs)
81
    {
82 102
        $this->skeletonDirs = [];
83
84 102
        if (\is_string($skeletonDirs)) {
85 1
            $this->addSkeletonDir($skeletonDirs);
86
        } else {
87 102
            if (!\is_array($skeletonDirs) && !$skeletonDirs instanceof \Traversable) {
0 ignored issues
show
introduced by
The condition is_array($skeletonDirs) is always true.
Loading history...
88 1
                throw new \InvalidArgumentException(
89 1
                    \sprintf('Skeleton dirs must be array or object implementing \Traversable interface, "%s" given.', \gettype($skeletonDirs))
90
                );
91
            }
92
93 102
            foreach ($skeletonDirs as $skeletonDir) {
94 64
                $this->addSkeletonDir($skeletonDir);
95
            }
96
        }
97
98 102
        return $this;
99
    }
100
101 63
    public function getSkeletonDirs($withDefault = true)
102
    {
103 63
        $skeletonDirs = $this->skeletonDirs ;
104
105 63
        if ($withDefault) {
106 63
            $skeletonDirs[] = __DIR__.'/../Resources/skeleton';
107
        }
108
109 63
        return $skeletonDirs;
110
    }
111
112 66
    public function addSkeletonDir($skeletonDir)
113
    {
114 66
        if (!\is_string($skeletonDir) && !\is_object($skeletonDir) && !\is_callable($skeletonDir, '__toString')) {
0 ignored issues
show
Bug introduced by
'__toString' of type string is incompatible with the type boolean expected by parameter $syntax_only of is_callable(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

114
        if (!\is_string($skeletonDir) && !\is_object($skeletonDir) && !\is_callable($skeletonDir, /** @scrutinizer ignore-type */ '__toString')) {
Loading history...
115 1
            throw new \InvalidArgumentException(
116 1
                \sprintf('Skeleton dir must be string or object implementing __toString, "%s" given.', \gettype($skeletonDir))
117
            );
118
        }
119
120 65
        $skeletonDir = (string) $skeletonDir;
121
122 65
        if (!\is_dir($skeletonDir)) {
123 1
            throw new \InvalidArgumentException(\sprintf('Skeleton dir "%s" not found.', $skeletonDir));
124
        }
125 64
        $this->skeletonDirs[] = \realpath($skeletonDir);
126
127 64
        return $this;
128
    }
129
130
131
    /**
132
     * Sets the number of spaces the exported class should have.
133
     *
134
     * @param integer $numSpaces
135
     *
136
     * @return self
137
     */
138 102
    public function setNumSpaces($numSpaces)
139
    {
140 102
        $this->spaces = \str_repeat(' ', $numSpaces);
141 102
        $this->numSpaces = $numSpaces;
142
143 102
        return $this;
144
    }
145
146 1
    public function addTrait($trait)
147
    {
148 1
        $cleanTrait = $this->shortenClassName($trait, false);
149 1
        if (!\in_array($cleanTrait, $this->traits)) {
150 1
            $this->traits[] = $cleanTrait;
151
        }
152
153 1
        return $this;
154
    }
155
156 1
    public function clearTraits()
157
    {
158 1
        $this->traits = [];
159
160 1
        return $this;
161
    }
162
163 64
    public function addImplement($implement)
164
    {
165 64
        $cleanImplement = $this->shortenClassName($implement, false);
166 64
        if (!\in_array($cleanImplement, $this->implements)) {
167 64
            $this->implements[] = $cleanImplement;
168
        }
169
170 64
        return $this;
171
    }
172
173 1
    public function clearImplements()
174
    {
175 1
        $this->implements = [];
176
177 1
        return $this;
178
    }
179
180 64
    public function addUseStatement($useStatement)
181
    {
182 64
        $cleanUse = ClassUtils::cleanClasseName($useStatement);
183 64
        if (!\in_array($cleanUse, $this->useStatements)) {
184 64
            $this->useStatements[] = $cleanUse;
185
        }
186
187 64
        return $this;
188
    }
189
190 1
    public function clearUseStatements()
191
    {
192 1
        $this->useStatements = [];
193
194 1
        return $this;
195
    }
196
197 63
    public function getSkeletonContent($skeleton, $withDefault = true)
198
    {
199 63
        $skeletonDirs = $this->getSkeletonDirs($withDefault);
200
201 63
        foreach ($skeletonDirs as $skeletonDir) {
202 63
            $path = $skeletonDir.'/'.$skeleton.static::SKELETON_FILE_PREFIX;
203
204 63
            if (!\file_exists($path)) {
205 33
                continue;
206
            }
207
208 62
            if (!isset(self::$templates[$path])) {
209 8
                $content = \trim(\file_get_contents($path));
210
211 8
                self::$templates[$path] = $content;
212
            }
213
214 62
            return self::$templates[$path];
215
        }
216
217 1
        throw new \InvalidArgumentException(
218 1
            \sprintf(
219 1
                'Skeleton "%s" could not be found in %s.',
220 1
                $skeleton,
221 1
                \implode(', ', $skeletonDirs)
222
            )
223
        );
224
    }
225
226 61
    protected function addInternalUseStatement($use)
227
    {
228 61
        $cleanUse = ClassUtils::cleanClasseName($use);
229 61
        if (!\in_array($cleanUse, $this->internalUseStatements)) {
230 61
            $this->internalUseStatements[] = $cleanUse;
231
        }
232 61
    }
233
234 63
    protected function clearInternalUseStatements()
235
    {
236 63
        $this->internalUseStatements = [];
237
238 63
        return $this;
239
    }
240
241 92
    protected function shortenClassName($definition, $isInternal = true)
242
    {
243 92
        $shortName = ClassUtils::shortenClassName($definition);
244
245 92
        $useStatement = \preg_replace('@\:\:.*$@i', '', $definition);
246 92
        if ($isInternal) {
247 61
            $this->addInternalUseStatement($useStatement);
248
        } else {
249 64
            $this->addUseStatement($useStatement);
250
        }
251
252 92
        return $shortName;
253
    }
254
255 48
    protected function shortenClassFromCode($code)
256
    {
257 48
        $codeParsed = ClassUtils::shortenClassFromCode(
258 48
            $code,
259
            function ($matches) {
260 48
                return $this->shortenClassName($matches[1]);
261 48
            }
262
        );
263
264 48
        return $codeParsed;
265
    }
266
267 62
    protected function processPlaceHoldersReplacements(array $placeHolders, $content, array $values)
268
    {
269 62
        $replacements = [];
270
271 62
        foreach ($placeHolders as $placeHolder) {
272 62
            $generator = [$this, 'generate'.\ucfirst($placeHolder)];
273 62
            $name = '<'.$placeHolder.'>';
274
275 62
            if (\is_callable($generator)) {
276 61
                $replacements[$name] = \call_user_func_array($generator, [$values]);
277
            } else {
278 1
                throw new \RuntimeException(
279 1
                    \sprintf(
280 1
                        'Generator [%s] for placeholder "%s" is not callable.',
281 1
                        \get_class($generator[0]).'::'.$generator[1],
282 1
                        $placeHolder
283
                    )
284
                );
285
            }
286
        }
287
288 60
        return \strtr($content, $replacements);
289
    }
290
291 62
    protected function processTemplatePlaceHoldersReplacements($template, array $values, array $skip = [])
292
    {
293 62
        $code = $this->getSkeletonContent($template);
294 62
        $placeHolders = $this->getPlaceHolders($code);
295 62
        $code = $this->processPlaceHoldersReplacements(\array_diff($placeHolders, $skip), $code, $values);
296
297 60
        return $code;
298
    }
299
300 62
    protected function getPlaceHolders($content)
301
    {
302 62
        \preg_match_all('@<([\w]+)>@i', $content, $placeHolders);
303
304 62
        return isset($placeHolders[1]) ? $placeHolders[1] : [];
305
    }
306
307
    /**
308
     * @param string $code
309
     * @param int $num
310
     *
311
     * @return string
312
     */
313 60
    protected function prefixCodeWithSpaces($code, $num = 1)
314
    {
315 60
        $lines = \explode("\n", $code);
316
317 60
        foreach ($lines as $key => $value) {
318 60
            if (!empty($value)) {
319 60
                $lines[$key] = \str_repeat($this->spaces, $num).$lines[$key];
320
            }
321
        }
322
323 60
        return \implode("\n", $lines);
324
    }
325
326 61
    protected function generateSpaces()
327
    {
328 61
        return $this->spaces;
329
    }
330
331 61
    protected function generateNamespace()
332
    {
333 61
        return null !== $this->classNamespace ? 'namespace '.$this->classNamespace.';' : null;
334
    }
335
336 60
    protected function generateUseStatement(array $config)
0 ignored issues
show
Unused Code introduced by
The parameter $config is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

336
    protected function generateUseStatement(/** @scrutinizer ignore-unused */ array $config)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
337
    {
338 60
        $statements = \array_merge($this->internalUseStatements, $this->useStatements);
339 60
        \sort($statements);
340
341 60
        $useStatements = $this->tokenizeUseStatements($statements);
342
343 60
        return $useStatements;
344
    }
345
346 61
    protected function generateClassType()
347
    {
348 61
        return 'final ';
349
    }
350
351 61
    protected function generateImplements()
352
    {
353 61
        return \count($this->implements) ? ' implements '.\implode(', ', $this->implements) : null;
354
    }
355
356 61
    protected function generateTraits()
357
    {
358 61
        $traits = $this->tokenizeUseStatements($this->traits, '<spaces>');
359
360 61
        return $traits ? $traits."\n" : $traits;
361
    }
362
363 61
    protected function tokenizeUseStatements(array $useStatements, $prefix = '')
364
    {
365 61
        if (empty($useStatements)) {
366 61
            return null;
367
        }
368
369 60
        $code = '';
370
371 60
        foreach ($useStatements as $useStatement) {
372 60
            $code .= "\n${prefix}use $useStatement;";
373
        }
374
375 60
        return $code;
376
    }
377
378
    /**
379
     * Generates classes files.
380
     *
381
     * @param array    $configs raw configs
382
     * @param string   $outputDirectory
383
     * @param int|bool $mode
384
     *
385
     * @return array classes map [[FQCLN => classPath], [FQCLN => classPath], ...]
386
     */
387
    abstract public function generateClasses(array $configs, $outputDirectory, $mode = false);
388
389
    /**
390
     * Generates a class file.
391
     *
392
     * @param array $config
393
     * @param $outputDirectory
394
     * @param bool $mode
395
     *
396
     * @return array classes map [FQCLN => classPath]
397
     */
398
    abstract public function generateClass(array $config, $outputDirectory, $mode = false);
399
}
400