ModelariumFrontendCommand   A
last analyzed

Complexity

Total Complexity 31

Size/Duplication

Total Lines 207
Duplicated Lines 0 %

Importance

Changes 13
Bugs 1 Features 1
Metric Value
eloc 97
c 13
b 1
f 1
dl 0
loc 207
rs 9.92
wmc 31

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
B handle() 0 33 9
A loadParser() 0 24 5
C generateFromModel() 0 86 16
1
<?php declare(strict_types=1);
2
3
namespace Modelarium\Laravel\Console\Commands;
4
5
use Formularium\FrameworkComposer;
6
use Formularium\StringUtil;
7
use HaydenPierce\ClassFinder\ClassFinder;
8
use Illuminate\Console\Command;
9
use Modelarium\Exception\Exception;
10
use Modelarium\Parser;
11
use Modelarium\Frontend\FrontendGenerator;
12
use Modelarium\GeneratedItem;
13
use Modelarium\Laravel\Processor as LaravelProcessor;
14
use Modelarium\Options;
15
16
class ModelariumFrontendCommand extends Command
17
{
18
    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...delariumFrontendCommand: $filename, $onlyIfNewFile, $contents
Loading history...
19
20
    /**
21
     * The name and signature of the console command.
22
     *
23
     * @var string
24
     */
25
    protected $signature = 'modelarium:frontend
26
        {name : The model name. Use "*" or "all" for all models}
27
        {--framework=* : The frameworks to use}
28
        {--lighthouse : use lighthouse directives}
29
        {--overwrite-graphql : overwrite graphql files if they exist}
30
        {--overwrite-match= : overwrite files that contain this string}
31
        {--overwrite : overwrite all files if they exist}
32
        {--prettier : run prettier on files}
33
        {--eslint : run eslint fix on files}
34
    ';
35
36
    /**
37
     * The console command description.
38
     *
39
     * @var string
40
     */
41
    protected $description = 'Creates frontend using Modelarium';
42
43
    /**
44
     * @var string[] List of Frameworks to be passed to the FrameworkComposer
45
     */
46
    protected $frameworks;
47
48
    /**
49
     * @var Parser
50
     */
51
    protected $parser = null;
52
53
    /**
54
     * @var Options
55
     */
56
    protected $modelariumOptions = null;
57
58
    /**
59
     * Create a new command instance.
60
     *
61
     * @return void
62
     */
63
    public function __construct()
64
    {
65
        parent::__construct();
66
67
        // read from Options()
68
        $this->modelariumOptions = new Options();
69
    }
70
71
    /**
72
     * Execute the console command.
73
     *
74
     * @return mixed
75
     */
76
    public function handle()
77
    {
78
        $name = $this->argument('name');
79
80
        // setup stuff
81
        $this->frameworks = $this->option('framework') ?: $this->modelariumOptions->getOption('frontend', 'framework');
82
        if (empty($this->frameworks)) {
83
            $this->error('If you are generating frontend you need to specify frameworks. Example: `--framework=HTML --framework=Bootstrap --framework=Vue`');
84
            return;
85
        }
86
        if (!is_array($this->frameworks)) {
87
            $this->frameworks = [$this->frameworks];
88
        }
89
90
        $this->loadParser();
91
        if ($name === '*' || $name === 'all') {
92
            /** @var array<class-string> $classesInNamespace */
93
            $classesInNamespace = ClassFinder::getClassesInNamespace('App\\Models');
94
95
            foreach ($classesInNamespace as $class) {
96
                $reflection = new \ReflectionClass($class);
97
                if (!$reflection->isInstantiable()) {
98
                    continue;
99
                }
100
                $this->generateFromModel($class);
101
            }
102
            return;
103
        } elseif (is_array($name)) {
104
            // TODO
105
        } else {
106
            $this->generateFromModel('\\App\\Models\\' . $name);
107
        }
108
        $this->info('Finished frontend.');
109
    }
110
111
    protected function loadParser(): void
112
    {
113
        $files = [
114
            __DIR__ . '/../../../Types/Graphql/scalars.graphql'
115
        ];
116
        if ($this->option('lighthouse') || $this->modelariumOptions->getOption('modelarium', 'lighthouse')) {
117
            $files[] = __DIR__ . '/../../Graphql/definitionsLighthouse.graphql';
118
        }
119
120
        $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

120
        $path = /** @scrutinizer ignore-call */ base_path('graphql');
Loading history...
121
        $dir = \Safe\scandir($path);
122
123
        // parse directives from lighthouse
124
        $modelNames = array_diff($dir, array('.', '..'));
125
126
        foreach ($modelNames as $n) {
127
            if (mb_strpos($n, '.graphql') === false) {
128
                continue;
129
            }
130
            $files[] = base_path('graphql/' . $n);
131
        }
132
        $this->parser = new Parser();
133
        $this->parser->setImport('directives.graphql', LaravelProcessor::getDirectivesGraphqlString());
134
        $this->parser->fromFiles($files);
135
    }
136
137
    protected function generateFromModel(string $name): void
138
    {
139
        $composer = FrameworkComposer::create($this->frameworks);
140
        $model = $name::getFormularium();
141
        $this->info("Starting $name...");
142
143
        $generator = new FrontendGenerator($composer, $model, $this->parser);
144
        $collection = $generator->generate();
145
146
        if (!$collection->count()) {
147
            $this->info('Nothing generated.');
148
            return;
149
        }
150
151
        /**
152
         * @var string $match
153
         */
154
        $match = $this->option('overwrite-match');
155
        if (!empty($match)) {
156
            if (!is_string($match)) {
0 ignored issues
show
introduced by
The condition is_string($match) is always true.
Loading history...
157
                $this->error('--overwrite-match must be a string');
158
                throw new Exception('');
159
            }
160
        }
161
162
        $basepath = base_path('resources/js/components/');
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

162
        $basepath = /** @scrutinizer ignore-call */ base_path('resources/js/components/');
Loading history...
163
        $writtenFiles = $this->writeFiles(
164
            $collection,
165
            $basepath,
166
            function (GeneratedItem $i) use ($match) {
167
                if ((bool)$this->option('overwrite') === true) {
168
                    return true;
169
                }
170
                if ((bool)$this->option('overwrite-graphql') === true) {
171
                    if (
172
                        StringUtil::endsWith($i->filename, '.graphql')
173
                    ) {
174
                        return true;
175
                    } elseif (StringUtil::endsWith($i->filename, 'model.js')) {
176
                        return true;
177
                    }
178
                }
179
                if ($match && mb_strpos($i->filename, $match) !== false) {
180
                    return true;
181
                }
182
                return false;
183
            }
184
        );
185
        $this->info('Files generated.');
186
187
        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...
188
            $this->info('Running prettier on generated files.');
189
            $useYarn = file_exists(base_path('yarn.lock'));
190
            if ($useYarn) {
191
                $command = "cd $basepath && npx prettier --write ";
192
            } else {
193
                $command = "cd $basepath && yarn prettier --write ";
194
            }
195
196
            // this runs all prettier commands in parallel.
197
            $run = array_reduce(
198
                $writtenFiles,
199
                function ($carry, $f) use ($command) {
200
                    return $carry . '(' . $command . $f . ') & ';
201
                }
202
            );
203
            shell_exec($run . ' wait');
204
        }
205
206
        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...
207
            $this->info('Running eslint on generated files.');
208
            $useYarn = file_exists(base_path('yarn.lock'));
209
            if ($useYarn) {
210
                $command = "cd $basepath && npx eslint --fix ";
211
            } else {
212
                $command = "cd $basepath && yarn eslint --fix ";
213
            }
214
215
            // this runs all prettier commands in parallel.
216
            $run = array_reduce(
217
                $writtenFiles,
218
                function ($carry, $f) use ($command) {
219
                    return $carry . '(' . $command . $f . ') & ';
220
                }
221
            );
222
            shell_exec($run . ' wait');
223
        }
224
    }
225
}
226