Passed
Push — master ( 042e62...ddba13 )
by Bruno
08:16 queued 04:19
created

ModelariumCodeCommand::handle()   B

Complexity

Conditions 8
Paths 7

Size

Total Lines 34
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 21
c 1
b 0
f 0
nc 7
nop 0
dl 0
loc 34
rs 8.4444
1
<?php declare(strict_types=1);
2
3
namespace Modelarium\Laravel\Console\Commands;
4
5
use Formularium\Factory\CodeGeneratorFactory;
6
use HaydenPierce\ClassFinder\ClassFinder;
7
use Illuminate\Console\Command;
8
use Modelarium\Parser;
9
use Modelarium\GeneratedCollection;
10
use Modelarium\GeneratedItem;
11
use Modelarium\Laravel\Processor as LaravelProcessor;
12
use Modelarium\Options;
13
14
class ModelariumCodeCommand extends Command
15
{
16
    use WriterTrait;
0 ignored issues
show
introduced by
The trait Modelarium\Laravel\Console\Commands\WriterTrait requires some properties which are not provided by Modelarium\Laravel\Conso...s\ModelariumCodeCommand: $filename, $onlyIfNewFile, $contents
Loading history...
17
18
    /**
19
     * The name and signature of the console command.
20
     *
21
     * @var string
22
     */
23
    protected $signature = 'modelarium:code
24
        {name : The model name. Use "*" or "all" for all models}
25
        {--generator= : The generators to use [SQL, GraphQL, Typescript]}
26
        {--path= : The output directory. Defaults to `resources/{generator}/`}
27
        {--lighthouse : use lighthouse directives}
28
        {--overwrite : overwrite all files if they exist}
29
        {--prettier : run prettier on files}
30
        {--eslint : run eslint fix on files}
31
    ';
32
33
    /**
34
     * The console command description.
35
     *
36
     * @var string
37
     */
38
    protected $description = 'Generates code using Modelarium';
39
40
    /**
41
     * @var string CodeGenerator
42
     */
43
    protected $generatorName = "";
44
45
    /**
46
     * @var Parser
47
     */
48
    protected $parser = null;
49
50
    /**
51
     * @var Options
52
     */
53
    protected $modelariumOptions = null;
54
55
    /**
56
     * Create a new command instance.
57
     *
58
     * @return void
59
     */
60
    public function __construct()
61
    {
62
        parent::__construct();
63
64
        // read from Options()
65
        $this->modelariumOptions = new Options();
66
    }
67
68
    /**
69
     * Execute the console command.
70
     *
71
     * @return mixed
72
     */
73
    public function handle()
74
    {
75
        $name = $this->argument('name');
76
77
        // setup stuff
78
        $this->generatorName = $this->option('generator');
79
        if (empty($this->generatorName)) {
80
            $this->error('Which code format to generate. Example: `--generator=TypeScript`');
81
            return;
82
        }
83
        if (is_array($this->generatorName)) {
0 ignored issues
show
introduced by
The condition is_array($this->generatorName) is always false.
Loading history...
84
            $this->error('Please specify a single generator.');
85
            return;
86
        }
87
88
        $this->loadParser();
89
        if ($name === '*' || $name === 'all') {
90
            /** @var array<class-string> $classesInNamespace */
91
            $classesInNamespace = ClassFinder::getClassesInNamespace('App\\Models');
92
93
            foreach ($classesInNamespace as $class) {
94
                $reflection = new \ReflectionClass($class);
95
                if (!$reflection->isInstantiable()) {
96
                    continue;
97
                }
98
                $this->generateFromModel($class);
99
            }
100
            return;
101
        } elseif (is_array($name)) {
102
            // TODO
103
        } else {
104
            $this->generateFromModel('\\App\\Models\\' . $name);
105
        }
106
        $this->info('Finished frontend.');
107
    }
108
109
    protected function loadParser(): void
110
    {
111
        $files = [
112
            __DIR__ . '/../../../Types/Graphql/scalars.graphql'
113
        ];
114
        if ($this->option('lighthouse') || $this->modelariumOptions->getOption('modelarium', 'lighthouse')) {
115
            $files[] = __DIR__ . '/../../Graphql/definitionsLighthouse.graphql';
116
        }
117
118
        $path = base_path('graphql');
0 ignored issues
show
Bug introduced by
The function base_path was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

118
        $path = /** @scrutinizer ignore-call */ base_path('graphql');
Loading history...
119
        $dir = \Safe\scandir($path);
120
121
        // parse directives from lighthouse
122
        $modelNames = array_diff($dir, array('.', '..'));
123
124
        foreach ($modelNames as $n) {
125
            if (mb_strpos($n, '.graphql') === false) {
126
                continue;
127
            }
128
            $files[] = base_path('graphql/' . $n);
129
        }
130
        $this->parser = new Parser();
131
        $this->parser->setImport('directives.graphql', LaravelProcessor::getDirectivesGraphqlString());
132
        $this->parser->fromFiles($files);
133
    }
134
135
    protected function generateFromModel(string $name): void
136
    {
137
        $generator = CodeGeneratorFactory::factory($this->generatorName);
138
        $model = $name::getFormularium();
139
        $this->info("Starting $name...");
140
141
        $code = $generator->type($model);
142
143
        if (!$code) {
144
            $this->info('Nothing generated.');
145
            return;
146
        }
147
148
        $basepath = $this->option('path') ?: base_path('resources/' . $generator->getName());
0 ignored issues
show
Bug introduced by
The function base_path was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

148
        $basepath = $this->option('path') ?: /** @scrutinizer ignore-call */ base_path('resources/' . $generator->getName());
Loading history...
149
        if (!is_dir($basepath)) {
150
            \Safe\mkdir($basepath, 0777, true);
151
        }
152
153
        $collection = new GeneratedCollection();
154
        $collection->push(
155
            new GeneratedItem(
156
                GeneratedItem::TYPE_FRONTEND,
157
                $code,
158
                $generator->typeFilename($model)
0 ignored issues
show
Bug introduced by
The method typeFilename() does not exist on Formularium\CodeGenerator\CodeGenerator. ( Ignorable by Annotation )

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

158
                $generator->/** @scrutinizer ignore-call */ 
159
                            typeFilename($model)

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
159
            )
160
        );
161
162
        if (!$collection->count()) {
163
            $this->info('Nothing generated.');
164
            return;
165
        }
166
167
        $writtenFiles = $this->writeFiles(
168
            $collection,
169
            $basepath,
170
            function (GeneratedItem $i) {
0 ignored issues
show
Unused Code introduced by
The parameter $i 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

170
            function (/** @scrutinizer ignore-unused */ GeneratedItem $i) {

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...
171
                if ((bool)$this->option('overwrite') === true) {
172
                    return true;
173
                }
174
                return false;
175
            }
176
        );
177
        $this->info('Files generated.');
178
179
        if ($this->option('prettier') !== null ?: $this->modelariumOptions->getOption('frontend', 'prettier')) {
0 ignored issues
show
introduced by
The condition $this->option('prettier') !== null is always true.
Loading history...
180
            $this->info('Running prettier on generated files.');
181
            $useYarn = file_exists(base_path('yarn.lock'));
182
            if ($useYarn) {
183
                $command = "cd $basepath && npx prettier --write ";
184
            } else {
185
                $command = "cd $basepath && yarn prettier --write ";
186
            }
187
188
            // this runs all prettier commands in parallel.
189
            $run = array_reduce(
190
                $writtenFiles,
191
                function ($carry, $f) use ($command) {
192
                    return $carry . '(' . $command . $f . ') & ';
193
                }
194
            );
195
            shell_exec($run . ' wait');
196
        }
197
198
        if ($this->option('eslint') !== null ?: $this->modelariumOptions->getOption('frontend', 'eslint')) {
0 ignored issues
show
introduced by
The condition $this->option('eslint') !== null is always true.
Loading history...
199
            $this->info('Running eslint on generated files.');
200
            $useYarn = file_exists(base_path('yarn.lock'));
201
            if ($useYarn) {
202
                $command = "cd $basepath && npx eslint --fix ";
203
            } else {
204
                $command = "cd $basepath && yarn eslint --fix ";
205
            }
206
207
            // this runs all prettier commands in parallel.
208
            $run = array_reduce(
209
                $writtenFiles,
210
                function ($carry, $f) use ($command) {
211
                    return $carry . '(' . $command . $f . ') & ';
212
                }
213
            );
214
            shell_exec($run . ' wait');
215
        }
216
    }
217
}
218