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.

GenerateCommand::generateClassCode()   B
last analyzed

Complexity

Conditions 7
Paths 8

Size

Total Lines 47
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 32
nc 8
nop 3
dl 0
loc 47
rs 8.4746
c 1
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
namespace Thunder\Platenum\Command;
4
5
use Composer\Autoload\ClassLoader;
6
use Thunder\Platenum\Enum\ConstantsEnumTrait;
7
use Thunder\Platenum\Enum\DocblockEnumTrait;
8
use Thunder\Platenum\Exception\PlatenumException;
9
use Thunder\Platenum\Enum\StaticEnumTrait;
10
11
/**
12
 * @author Tomasz Kowalczyk <[email protected]>
13
 * @codeCoverageIgnore
14
 * @internal
15
 */
16
final class GenerateCommand
17
{
18
    /** @var ClassLoader */
19
    private $classLoader;
20
21
    public function __construct(ClassLoader $loader)
22
    {
23
        $this->classLoader = $loader;
24
    }
25
26
    /**
27
     * @param int $argc
28
     * @param string[] $argv
29
     */
30
    public function execute(int $argc, array $argv): void
31
    {
32
        $this->writeln('Platenum (c) 2019 Tomasz Kowalczyk.');
33
        $this->writeln('');
34
35
        if($argc < 4) {
36
            $this->writeln('usage:    bin/generate <source> <class> MEMBER=value,MEMBER=value,...');
37
            $this->writeln('examples: bin/generate constants UserStatus ACTIVE=1,INACTIVE=2');
38
            $this->writeln('          bin/generate docblock PaymentType INTERNAL,EXTERNAL');
39
            $this->writeln('          bin/generate static "Project\\Namespace\\Currency" PLN=10,EUR=12,USD=14');
40
            exit(1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
41
        }
42
        if(false === in_array($argv[1], ['constants', 'docblock', 'static'], true)) {
43
            $this->writeln(sprintf('Unrecognized type `%s`. Allowed: `%s`.', $argv[1], 'constants,docblock,static'));
44
            exit(1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
45
        }
46
47
        $path = $this->computeClassPath($argv[2]);
48
        $code = $this->generateClassCode($argv[1], $argv[2], $argv[3]);
49
50
        if(file_exists($path)) {
51
            $this->writeln("\e[0;31mFile already exists.\e[0m");
52
            return;
53
        }
54
        $this->writeFile($path, $code);
55
56
        $this->writeln('');
57
        $this->writeln('--- BEGIN CLASS CODE ---');
58
        $this->writeln("\e[0;33m$code\e[0m");
59
        $this->writeln('--- END CLASS CODE ---');
60
    }
61
62
    private function writeFile(string $path, string $content): void
63
    {
64
        if(!$path) {
65
            return;
66
        }
67
68
        $directory = \dirname($path);
69
        if(!file_exists($directory) && !\mkdir($directory, 0777, true) && !\is_dir($directory)) {
70
            throw new PlatenumException(sprintf('Failed to create target directory `%s`.', $directory));
71
        }
72
73
        $bytes = file_put_contents($path, $content);
74
        if($bytes !== \strlen($content)) {
75
            throw new PlatenumException(sprintf('Failed to write target file at path `%s`.', $path));
76
        }
77
    }
78
79
    private function computeClassPath(string $fqcn): string
80
    {
81
        $prefix = '';
82
        $path = '';
83
        /** @var string[] $paths */
84
        foreach($this->classLoader->getPrefixesPsr4() as $ns => $paths) {
85
            if(0 === strpos($fqcn, $ns)) {
86
                $prefix = $ns;
87
                $path = (string)realpath($paths[0]);
88
                break;
89
            }
90
        }
91
92
        if(false === ($prefix && $path)) {
93
            $this->writeln(sprintf("Namespace `\e[0;32m%s\e[0m` is not mapped in Composer autoloader.", $fqcn));
94
            $this->writeln('Generated code will be written below. No files will be written to disk.');
95
            return '';
96
        }
97
98
        $fullPath = $path.DIRECTORY_SEPARATOR.str_replace('\\', DIRECTORY_SEPARATOR, str_replace($prefix, '', $fqcn)).'.php';
99
        $this->writeln(sprintf("Namespace prefix `\e[0;32m%s\e[0m` is mapped to `\e[0;32m%s\e[0m`.", $prefix, $path));
100
        $this->writeln(sprintf("Class file will be written to path: `\e[0;32m%s\e[0m`", $fullPath));
101
102
        return $fullPath;
103
    }
104
105
    private function generateClassCode(string $type, string $fqcn, string $keys): string
106
    {
107
        $namespace = $fqcn;
108
        $lastSlash = (int)strrpos($namespace, '\\');
109
        $class = substr($namespace, $lastSlash ? $lastSlash + 1 : 0);
110
        $namespace = $lastSlash ? substr($namespace, 0, $lastSlash) : 'X';
111
112
        preg_match_all('~(?<key>[a-zA-Z]+)(=(?<value>[^,$]+),?)?~', $keys, $matches);
113
        if(PREG_NO_ERROR !== preg_last_error()) {
114
            throw new PlatenumException(sprintf('Failed to parse keys, `%s`.', preg_last_error()));
115
        }
116
117
        $index = 1;
118
        $docblockEntries = [];
119
        $constantsEntries = [];
120
        $staticEntries = [];
121
        /** @var array<string,array<int,string>> $matches */
122
        $count = \count($matches['key']);
123
        for($i = 0; $i < $count; $i++) {
124
            $key = $matches['key'][$i];
125
            $value = $matches['value'][$i] ?: $index++;
126
            /** @psalm-suppress TypeDoesNotContainType */
127
            if(false === ctype_digit((string)$value)) {
128
                $value = '\''.$value.'\'';
129
            }
130
131
            $constantsEntries[] = '    private const '.strtoupper($key).' = '.$value.';';
132
            $docblockEntries[] = ' * @method static static '.strtoupper($key).'()';
133
            $staticEntries[] = '        \''.strtoupper($key).'\' => '.$value.';';
134
        }
135
136
        $values = [
137
            'constants' => ['template' => static::CONSTANTS_TEMPLATE, 'trait' => ConstantsEnumTrait::class, 'members' => implode("\n", $constantsEntries)],
138
            'docblock'  => ['template' => static::DOCBLOCK_TEMPLATE,  'trait' => DocblockEnumTrait::class,  'members' => ''],
139
            'static'    => ['template' => static::STATIC_TEMPLATE,    'trait' => StaticEnumTrait::class,    'members' => implode("\n", $staticEntries)],
140
        ];
141
        $replaces = [
142
            '<NS>' => $namespace,
143
            '<CLASS>' => $class,
144
            '<DOCBLOCK>' => implode("\n", $docblockEntries),
145
            '<TRAIT>' => substr($values[$type]['trait'], (int)strrpos($values[$type]['trait'], "\\") + 1),
146
            '<TRAIT_NS>' => $values[$type]['trait'],
147
            '<MEMBERS>' => $values[$type]['members'],
148
        ];
149
150
        /** @psalm-suppress InvalidArgument */
151
        return str_replace(array_keys($replaces), array_values($replaces), $values[$type]['template']);
152
    }
153
154
    private function writeln(string $message): void
155
    {
156
        echo $message."\n";
157
    }
158
159
    private const CONSTANTS_TEMPLATE = <<<EOF
160
<?php
161
declare(strict_types=1);
162
namespace <NS>;
163
164
use <TRAIT_NS>;
165
166
/**
167
<DOCBLOCK>
168
 */
169
final class <CLASS>
170
{
171
    use <TRAIT>;
172
173
<MEMBERS>
174
}
175
176
EOF;
177
178
    private const DOCBLOCK_TEMPLATE = <<<EOF
179
<?php
180
declare(strict_types=1);
181
namespace <NS>;
182
183
use <TRAIT_NS>;
184
185
/**
186
<DOCBLOCK>
187
 */
188
final class <CLASS>
189
{
190
    use <TRAIT>;
191
}
192
193
EOF;
194
195
    private const STATIC_TEMPLATE = <<<EOF
196
<?php
197
declare(strict_types=1);
198
namespace <NS>;
199
200
use <TRAIT_NS>;
201
202
/**
203
<DOCBLOCK>
204
 */
205
final class <CLASS>
206
{
207
    use <TRAIT>;
208
209
    private static \$mapping = [
210
<MEMBERS>
211
    ];
212
}
213
214
EOF;
215
}
216