GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#7)
by Cees-Jan
03:28 queued 01:13
created

ResourceGenerator::generateFromDefinition()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 96
Code Lines 69

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 57
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 96
ccs 57
cts 57
cp 1
rs 8.3859
c 0
b 0
f 0
cc 1
eloc 69
nc 1
nop 1
crap 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
declare(strict_types=1);
3
4
namespace WyriHaximus\ApiClient\Tools;
5
6
use Aura\Cli\Context;
7
use Aura\Cli\Stdio;
8
use Doctrine\Common\Inflector\Inflector;
9
use Exception;
10
use PhpParser\Builder\Method;
11
use PhpParser\Builder\Property;
12
use PhpParser\BuilderFactory;
13
use PhpParser\PrettyPrinter;
14
use PhpParser\Node;
15
use Symfony\Component\Yaml\Yaml;
16
use Symfony\CS\Config\Config;
17
use Symfony\CS\ConfigAwareInterface;
18
use Symfony\CS\ConfigInterface;
19
use Symfony\CS\FileCacheManager;
20
use Symfony\CS\Fixer;
21
use Symfony\CS\FixerInterface;
22
use WyriHaximus\ApiClient\Resource\ResourceInterface;
23
24
class ResourceGenerator
25
{
26
    /**
27
     * @var Context
28
     */
29
    protected $context;
30
31
    /**
32
     * @var Stdio
33
     */
34
    protected $stdio;
35
36
    /**
37
     * @var array
38
     */
39
    protected $definitions = [];
40
41
    /**
42
     * @var string
43
     */
44
    protected $path;
45
46
    /**
47
     * @var Fixer
48
     */
49
    protected $fixer;
50
51
    /**
52
     * @var array
53
     */
54
    protected $fixers;
55
56 2
    public function __construct(Context $context, Stdio $stdio)
57
    {
58 2
        $this->context = $context;
59 2
        $this->stdio = $stdio;
60
61 2
        $this->setUpArguments();
62 2
        $this->setUpFixers();
63 2
    }
64
65 2
    protected function setUpArguments()
66
    {
67 2
        $getOpt = $this->context->getopt(['s', 'a']);
68 2
        $i = 0;
69
        do {
70 2
            $i++;
71 2
            $opt = $getOpt->get($i);
72 2
            if ($opt === null) {
73 2
                break;
74
            }
75 2
            $this->definitions[] = $opt;
76 2
        } while (true);
77 2
        $this->path = array_pop($this->definitions);
78 2
    }
79
80 2
    protected function setUpFixers()
81
    {
82 2
        $this->fixer = new Fixer();
83 2
        $this->fixer->registerCustomFixers([
84 2
            new Fixer\Symfony\ExtraEmptyLinesFixer(),
85 2
            new Fixer\Symfony\SingleBlankLineBeforeNamespaceFixer(),
86 2
            new Fixer\PSR0\Psr0Fixer(),
87 2
            new Fixer\PSR1\EncodingFixer(),
88 2
            new Fixer\PSR1\ShortTagFixer(),
89 2
            new Fixer\PSR2\BracesFixer(),
90 2
            new Fixer\PSR2\ElseifFixer(),
91 2
            new Fixer\PSR2\EofEndingFixer(),
92 2
            new Fixer\PSR2\FunctionCallSpaceFixer(),
93 2
            new Fixer\PSR2\FunctionDeclarationFixer(),
94 2
            new Fixer\PSR2\IndentationFixer(),
95 2
            new Fixer\PSR2\LineAfterNamespaceFixer(),
96 2
            new Fixer\PSR2\LinefeedFixer(),
97 2
            new Fixer\PSR2\LowercaseConstantsFixer(),
98 2
            new Fixer\PSR2\LowercaseKeywordsFixer(),
99 2
            new Fixer\PSR2\MethodArgumentSpaceFixer(),
100 2
            new Fixer\PSR2\MultipleUseFixer(),
101 2
            new Fixer\PSR2\ParenthesisFixer(),
102 2
            new Fixer\PSR2\PhpClosingTagFixer(),
103 2
            new Fixer\PSR2\SingleLineAfterImportsFixer(),
104 2
            new Fixer\PSR2\TrailingSpacesFixer(),
105 2
            new Fixer\PSR2\VisibilityFixer(),
106 2
            new Fixer\Contrib\NewlineAfterOpenTagFixer(),
107 2
            new EmptyLineAboveDocblocksFixer(),
108
        ]);
109 2
        $config = Config::create()->
110 2
        fixers($this->fixer->getFixers())
111
        ;
112 2
        $this->fixer->addConfig($config);
113 2
        $this->fixers = $this->prepareFixers($config);
114 2
    }
115
116 1
    public function run()
117
    {
118 1
        foreach ($this->definitions as $definition) {
119 1
            $this->stdio->outln('-----');
120 1
            $this->stdio->outln('- Definition: ' . $definition);
121 1
            $this->stdio->outln('-----');
122 1
            $this->generateFromDefinition($definition);
123 1
            $this->stdio->outln('-----');
124
        }
125 1
    }
126
127 1
    public function generateFromDefinition($definition)
128
    {
129 1
        $yaml = $this->readYaml($definition);
130
131 1
        $namespacePadding = explode('\\', $yaml['class']);
132 1
        $namespace = explode('\\', $yaml['namespace']);
133
134 1
        $yaml['class'] = array_pop($namespacePadding);
135 1
        $yaml['namespace'] = implode('\\', array_merge($namespace, $namespacePadding));
136
137 1
        $namespacePathPadding = implode(DIRECTORY_SEPARATOR, $namespacePadding);
138 1
        $baseClass = implode(
139 1
            '\\',
140
            array_merge(
141
                $namespace,
142
                $namespacePadding,
143
                [
144 1
                    $yaml['class']
145
                ]
146
            )
147
        );
148
149 1
        $this->stdio->out('Interface: generating');
150 1
        $this->save(
151 1
            $this->path .
152 1
                DIRECTORY_SEPARATOR .
153 1
                $namespacePathPadding .
154 1
                DIRECTORY_SEPARATOR,
155 1
            $yaml['class'] .
156 1
                'Interface.php',
157 1
            $this->createInterface($yaml)
158
        );
159
160 1
        $this->stdio->out('Base class: generating');
161 1
        $this->save(
162 1
            $this->path .
163 1
                DIRECTORY_SEPARATOR .
164 1
                $namespacePathPadding .
165 1
                DIRECTORY_SEPARATOR,
166 1
            $yaml['class'] .
167 1
                '.php',
168 1
            $this->createBaseClass($yaml)
169
        );
170
171 1
        $this->stdio->out('Async class: generating');
172 1
        $this->save(
173 1
            $this->path .
174 1
                DIRECTORY_SEPARATOR .
175 1
                'Async' .
176 1
                DIRECTORY_SEPARATOR .
177 1
                $namespacePathPadding .
178 1
                DIRECTORY_SEPARATOR,
179 1
            $yaml['class'] .
180 1
                '.php',
181 1
            $this->createExtendingClass(
182
                implode(
183 1
                    '\\',
184
                    array_merge(
185
                        $namespace,
186
                        [
187 1
                            'Async',
188
                        ],
189
                        $namespacePadding
190
                    )
191
                ),
192 1
                $yaml['class'],
193
                $baseClass
194
            )
195
        );
196
197 1
        $this->stdio->out('Sync class: generating');
198 1
        $this->save(
199 1
            $this->path .
200 1
                DIRECTORY_SEPARATOR .
201 1
                'Sync' .
202 1
                DIRECTORY_SEPARATOR .
203 1
                $namespacePathPadding .
204 1
                DIRECTORY_SEPARATOR,
205 1
            $yaml['class'] .
206 1
                '.php',
207 1
            $this->createExtendingClass(
208
                implode(
209 1
                    '\\',
210
                    array_merge(
211
                        $namespace,
212
                        [
213 1
                            'Sync',
214
                        ],
215
                        $namespacePadding
216
                    )
217
                ),
218 1
                $yaml['class'],
219
                $baseClass
220
            )
221
        );
222 1
    }
223
224 1
    protected function readYaml(string $filename): array
225
    {
226 1
        return Yaml::parse(file_get_contents($filename));
227
    }
228
229 1
    protected function createBaseClass(array $yaml)
230
    {
231 1
        $factory = new BuilderFactory;
232
233 1
        $class = $factory->class($yaml['class'])
234 1
            ->implement($yaml['class'] . 'Interface')
235 1
            ->makeAbstract();
236 1
        $class->addStmt(
237 1
            new Node\Stmt\TraitUse([
238 1
                new Node\Name('TransportAwareTrait')
239
            ])
240
        );
241
242 1
        foreach ($yaml['properties'] as $name => $details) {
243 1
            $type = $details;
244 1
            if (is_array($details)) {
245 1
                $type = $details['type'];
246
            }
247 1
            $class->addStmt($this->createProperty($factory, $type, $name, $details));
248 1
            $class->addStmt($this->createMethod($factory, $type, $name, $details));
249
        }
250
251 1
        $node = $factory->namespace($yaml['namespace'])
252 1
            ->addStmt($factory->use('WyriHaximus\ApiClient\Resource\TransportAwareTrait'))
253 1
            ->addStmt($class)
254
255 1
            ->getNode()
256
        ;
257
258 1
        $prettyPrinter = new PrettyPrinter\Standard();
259 1
        return $prettyPrinter->prettyPrintFile([
260 1
            $node
261 1
        ]) . PHP_EOL;
262
    }
263
264 1
    protected function createInterface(array $yaml)
265
    {
266 1
        $factory = new BuilderFactory;
267
268 1
        $class = $factory->interface($yaml['class'] . 'Interface')
269 1
            ->extend('ResourceInterface');
270
271 1
        foreach ($yaml['properties'] as $name => $details) {
272 1
            $type = $details;
273 1
            if (is_array($details)) {
274 1
                $type = $details['type'];
275
            }
276 1
            $class->addStmt($this->createMethod($factory, $type, $name, $details));
277
        }
278
279 1
        $node = $factory->namespace($yaml['namespace'])
280 1
            ->addStmt($factory->use(ResourceInterface::class))
281 1
            ->addStmt($class)
282 1
            ->getNode()
283
        ;
284
285 1
        $prettyPrinter = new PrettyPrinter\Standard();
286 1
        return $prettyPrinter->prettyPrintFile([
287 1
            $node
288 1
        ]) . PHP_EOL;
289
    }
290
291 1
    protected function createProperty(BuilderFactory $factory, string $type, string $name, $details): Property
292
    {
293 1
        $property = $factory->property($name)
294 1
            ->makeProtected()
295 1
            ->setDocComment('/**
296 1
                              * @var ' . $type . '
297 1
                              */');
298 1
        if (isset($details['default'])) {
299 1
            $property->setDefault($details['default']);
300
        }
301
302 1
        return $property;
303
    }
304
305 1
    protected function createMethod(BuilderFactory $factory, string $type, string $name, $details): Method
0 ignored issues
show
Unused Code introduced by
The parameter $details is not used and could be removed.

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

Loading history...
306
    {
307 1
        return $factory->method(Inflector::camelize($name))
308 1
            ->makePublic()
309 1
            ->setReturnType($type)
310 1
            ->setDocComment('/**
311 1
                              * @return ' . $type . '
312 1
                              */')
313 1
            ->addStmt(
314 1
                new Node\Stmt\Return_(
315 1
                    new Node\Expr\PropertyFetch(
316 1
                        new Node\Expr\Variable('this'),
317
                        $name
318
                    )
319
                )
320
            );
321
    }
322
323 1
    protected function createExtendingClass(string $namespace, string $className, string $baseClass)
324
    {
325 1
        $factory = new BuilderFactory;
326
327 1
        $class = $factory->class($className)
328 1
            ->extend('Base' . $className);
329
330 1
        $class->addStmt($factory->method('refresh')
331 1
            ->makePublic()
332 1
            ->setReturnType($className)
333 1
            ->addStmt(
334 1
                new Node\Stmt\Return_(
335 1
                    new Node\Expr\MethodCall(
336 1
                        new Node\Expr\Variable('this'),
337 1
                        'wait',
338
                        [
0 ignored issues
show
Documentation introduced by
array(new \PhpParser\Nod...r\String_('refresh')))) is of type array<integer,object<Php...e\\Expr\\MethodCall>"}>, but the function expects a array<integer,object<PhpParser\Node\Arg>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
339 1
                            new Node\Expr\MethodCall(
340 1
                                new Node\Expr\Variable('this'),
341 1
                                'callAsync',
342
                                [
0 ignored issues
show
Documentation introduced by
array(new \PhpParser\Nod...lar\String_('refresh')) is of type array<integer,object<Php...de\\Scalar\\String_>"}>, but the function expects a array<integer,object<PhpParser\Node\Arg>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
343 1
                                    new Node\Scalar\String_('refresh'),
344
                                ]
345
                            ),
346
                        ]
347
                    )
348
                )
349
            ));
350
351 1
        $node = $factory->namespace($namespace)
352 1
            ->addStmt($factory->use($baseClass)->as('Base' . $className))
353 1
            ->addStmt($class)
354
355 1
            ->getNode()
356
        ;
357
358 1
        $prettyPrinter = new PrettyPrinter\Standard();
359 1
        return $prettyPrinter->prettyPrintFile([
360 1
            $node
361 1
        ]) . PHP_EOL;
362
    }
363
364 1
    protected function save(string $directory, string $fileName, string $fileContents)
365
    {
366 1
        $fileName = str_replace('\\', DIRECTORY_SEPARATOR, $fileName);
367 1
        if (file_exists($directory . $fileName)) {
368
            $this->stdio->outln(', exists!');
369
            return;
370
        }
371
372 1
        $path = $directory . $fileName;
373 1
        $pathChunks = explode(DIRECTORY_SEPARATOR, $path);
374 1
        array_pop($pathChunks);
375 1
        $path = implode(DIRECTORY_SEPARATOR, $pathChunks);
376 1
        if (!file_exists($path)) {
377 1
            mkdir($path, 0777, true);
378
        }
379
380 1
        if (!file_exists($path)) {
381
            throw new Exception('Unable to create: ' . $path);
382
        }
383
384 1
        $this->stdio->out(', writing');
385 1
        file_put_contents($directory . $fileName, $fileContents);
386
387
        do {
388 1
            usleep(500);
389 1
        } while (!file_exists($directory . $fileName));
390
391 1
        $this->stdio->out(', applying PSR-2');
392 1
        $this->applyPsr2($directory . $fileName);
393 1
        $this->stdio->outln(', done!');
394 1
    }
395
396 1
    protected function applyPsr2($fileName)
397
    {
398 1
        $file = new \SplFileInfo($fileName);
399 1
        $this->fixer->fixFile(
400
            $file,
401 1
            $this->fixers,
402 1
            false,
403 1
            false,
404 1
            new FileCacheManager(
405 1
                false,
406 1
                '',
407 1
                $this->fixers
408
            )
409
        );
410 1
    }
411
412
413
    /**
414
     * @param ConfigInterface $config
415
     *
416
     * @return FixerInterface[]
417
     */
418 2
    private function prepareFixers(ConfigInterface $config)
419
    {
420 2
        $fixers = $config->getFixers();
421
422 2
        foreach ($fixers as $fixer) {
423 2
            if ($fixer instanceof ConfigAwareInterface) {
424 2
                $fixer->setConfig($config);
425
            }
426
        }
427
428 2
        return $fixers;
429
    }
430
}
431