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
09:13
created

ResourceGenerator::setUpArguments()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 14
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 14
ccs 11
cts 11
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 11
nc 2
nop 0
crap 3
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->generateFromDefinition($definition);
120
        }
121 1
    }
122
123 1
    public function generateFromDefinition($definition)
124
    {
125 1
        $yaml = $this->readYaml($definition);
126
127 1
        $namespacePadding = explode('\\', $yaml['class']);
128 1
        $namespace = explode('\\', $yaml['namespace']);
129
130 1
        $yaml['class'] = array_pop($namespacePadding);
131 1
        $yaml['namespace'] = implode('\\', array_merge($namespace, $namespacePadding));
132
133 1
        $namespacePathPadding = implode(DIRECTORY_SEPARATOR, $namespacePadding);
134 1
        $baseClass = implode(
135 1
            '\\',
136
            array_merge(
137
                $namespace,
138
                $namespacePadding,
139
                [
140 1
                    $yaml['class']
141
                ]
142
            )
143
        );
144
145 1
        $this->save(
146 1
            $this->path .
147 1
                DIRECTORY_SEPARATOR .
148 1
                $namespacePathPadding .
149 1
                DIRECTORY_SEPARATOR,
150 1
            $yaml['class'] .
151 1
                '.php',
152 1
            $this->createBaseClass($yaml)
153
        );
154 1
        $this->save(
155 1
            $this->path .
156 1
                DIRECTORY_SEPARATOR .
157 1
                $namespacePathPadding .
158 1
                DIRECTORY_SEPARATOR,
159 1
            $yaml['class'] .
160 1
                'Interface.php',
161 1
            $this->createInterface($yaml)
162
        );
163 1
        $this->save(
164 1
            $this->path .
165 1
                DIRECTORY_SEPARATOR .
166 1
                'Async' .
167 1
                DIRECTORY_SEPARATOR .
168 1
                $namespacePathPadding .
169 1
                DIRECTORY_SEPARATOR,
170 1
            $yaml['class'] .
171 1
                '.php',
172 1
            $this->createExtendingClass(
173
                implode(
174 1
                    '\\',
175
                    array_merge(
176
                        $namespace,
177
                        [
178 1
                            'Async',
179
                        ],
180
                        $namespacePadding
181
                    )
182
                ),
183 1
                $yaml['class'],
184
                $baseClass
185
            )
186
        );
187 1
        $this->save(
188 1
            $this->path .
189 1
                DIRECTORY_SEPARATOR .
190 1
                'Sync' .
191 1
                DIRECTORY_SEPARATOR .
192 1
                $namespacePathPadding .
193 1
                DIRECTORY_SEPARATOR,
194 1
            $yaml['class'] .
195 1
                '.php',
196 1
            $this->createExtendingClass(
197
                implode(
198 1
                    '\\',
199
                    array_merge(
200
                        $namespace,
201
                        [
202 1
                            'Sync',
203
                        ],
204
                        $namespacePadding
205
                    )
206
                ),
207 1
                $yaml['class'],
208
                $baseClass
209
            )
210
        );
211 1
    }
212
213 1
    protected function readYaml(string $filename): array
214
    {
215 1
        return Yaml::parse(file_get_contents($filename));
216
    }
217
218 1
    protected function createBaseClass(array $yaml)
219
    {
220 1
        $factory = new BuilderFactory;
221
222 1
        $class = $factory->class($yaml['class'])
223 1
            ->implement($yaml['class'] . 'Interface')
224 1
            ->makeAbstract();
225 1
        $class->addStmt(
226 1
            new Node\Stmt\TraitUse([
227 1
                new Node\Name('TransportAwareTrait')
228
            ])
229
        );
230
231 1
        foreach ($yaml['properties'] as $name => $details) {
232 1
            $type = $details;
233 1
            if (is_array($details)) {
234 1
                $type = $details['type'];
235
            }
236 1
            $class->addStmt($this->createProperty($factory, $type, $name, $details));
237 1
            $class->addStmt($this->createMethod($factory, $type, $name, $details));
238
        }
239
240 1
        $node = $factory->namespace($yaml['namespace'])
241 1
            ->addStmt($factory->use('WyriHaximus\ApiClient\Resource\TransportAwareTrait'))
242 1
            ->addStmt($class)
243
244 1
            ->getNode()
245
        ;
246
247 1
        $prettyPrinter = new PrettyPrinter\Standard();
248 1
        return $prettyPrinter->prettyPrintFile([
249 1
            $node
250 1
        ]) . PHP_EOL;
251
    }
252
253 1
    protected function createInterface(array $yaml)
254
    {
255 1
        $factory = new BuilderFactory;
256
257 1
        $class = $factory->interface($yaml['class'] . 'Interface')
258 1
            ->extend('ResourceInterface');
259
260 1
        foreach ($yaml['properties'] as $name => $details) {
261 1
            $type = $details;
262 1
            if (is_array($details)) {
263 1
                $type = $details['type'];
264
            }
265 1
            $class->addStmt($this->createMethod($factory, $type, $name, $details));
266
        }
267
268 1
        $node = $factory->namespace($yaml['namespace'])
269 1
            ->addStmt($factory->use(ResourceInterface::class))
270 1
            ->addStmt($class)
271 1
            ->getNode()
272
        ;
273
274 1
        $prettyPrinter = new PrettyPrinter\Standard();
275 1
        return $prettyPrinter->prettyPrintFile([
276 1
            $node
277 1
        ]) . PHP_EOL;
278
    }
279
280 1
    protected function createProperty(BuilderFactory $factory, string $type, string $name, $details): Property
281
    {
282 1
        $property = $factory->property($name)
283 1
            ->makeProtected()
284 1
            ->setDocComment('/**
285 1
                              * @var ' . $type . '
286 1
                              */');
287 1
        if (isset($details['default'])) {
288 1
            $property->setDefault($details['default']);
289
        }
290
291 1
        return $property;
292
    }
293
294 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...
295
    {
296 1
        return $factory->method(Inflector::camelize($name))
297 1
            ->makePublic()
298 1
            ->setReturnType($type)
299 1
            ->setDocComment('/**
300 1
                              * @return ' . $type . '
301 1
                              */')
302 1
            ->addStmt(
303 1
                new Node\Stmt\Return_(
304 1
                    new Node\Expr\PropertyFetch(
305 1
                        new Node\Expr\Variable('this'),
306
                        $name
307
                    )
308
                )
309
            );
310
    }
311
312 1
    protected function createExtendingClass(string $namespace, string $className, string $baseClass)
313
    {
314 1
        $factory = new BuilderFactory;
315
316 1
        $class = $factory->class($className)
317 1
            ->extend('Base' . $className);
318
319 1
        $class->addStmt($factory->method('refresh')
320 1
            ->makePublic()
321 1
            ->setReturnType($className)
322 1
            ->addStmt(
323 1
                new Node\Stmt\Return_(
324 1
                    new Node\Expr\MethodCall(
325 1
                        new Node\Expr\Variable('this'),
326 1
                        'wait',
327
                        [
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...
328 1
                            new Node\Expr\MethodCall(
329 1
                                new Node\Expr\Variable('this'),
330 1
                                'callAsync',
331
                                [
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...
332 1
                                    new Node\Scalar\String_('refresh'),
333
                                ]
334
                            ),
335
                        ]
336
                    )
337
                )
338
            ));
339
340 1
        $node = $factory->namespace($namespace)
341 1
            ->addStmt($factory->use($baseClass)->as('Base' . $className))
342 1
            ->addStmt($class)
343
344 1
            ->getNode()
345
        ;
346
347 1
        $prettyPrinter = new PrettyPrinter\Standard();
348 1
        return $prettyPrinter->prettyPrintFile([
349 1
            $node
350 1
        ]) . PHP_EOL;
351
    }
352
353 1
    protected function save(string $directory, string $fileName, string $fileContents)
354
    {
355 1
        $fileName = str_replace('\\', DIRECTORY_SEPARATOR, $fileName);
356 1
        if (file_exists($directory . $fileName)) {
357
            return;
358
        }
359
360 1
        $path = $directory . $fileName;
361 1
        $pathChunks = explode(DIRECTORY_SEPARATOR, $path);
362 1
        array_pop($pathChunks);
363 1
        $path = implode(DIRECTORY_SEPARATOR, $pathChunks);
364 1
        if (!file_exists($path)) {
365 1
            mkdir($path, 0777, true);
366
        }
367
368 1
        if (!file_exists($path)) {
369
            throw new Exception('Unable to create: ' . $path);
370
        }
371
372 1
        file_put_contents($directory . $fileName, $fileContents);
373
374
        do {
375 1
            usleep(500);
376 1
        } while (!file_exists($directory . $fileName));
377
378 1
        $this->applyPsr2($directory . $fileName);
379
380 1
        $this->stdio->outln($directory . $fileName);
381 1
    }
382
383 1
    protected function applyPsr2($fileName)
384
    {
385 1
        $file = new \SplFileInfo($fileName);
386 1
        $this->fixer->fixFile(
387
            $file,
388 1
            $this->fixers,
389 1
            false,
390 1
            false,
391 1
            new FileCacheManager(
392 1
                false,
393 1
                '',
394 1
                $this->fixers
395
            )
396
        );
397 1
    }
398
399
400
    /**
401
     * @param ConfigInterface $config
402
     *
403
     * @return FixerInterface[]
404
     */
405 2
    private function prepareFixers(ConfigInterface $config)
406
    {
407 2
        $fixers = $config->getFixers();
408
409 2
        foreach ($fixers as $fixer) {
410 2
            if ($fixer instanceof ConfigAwareInterface) {
411 2
                $fixer->setConfig($config);
412
            }
413
        }
414
415 2
        return $fixers;
416
    }
417
}
418