Passed
Push — master ( d9bfc5...6bf22a )
by Bruno
03:04
created

ModelariumFrontendCommand::handle()   B

Complexity

Conditions 8
Paths 11

Size

Total Lines 35
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 8
eloc 20
c 3
b 0
f 0
nc 11
nop 0
dl 0
loc 35
rs 8.4444
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
15
use function Modelarium\Laravel\Targets\endsWith;
16
17
class ModelariumFrontendCommand extends Command
18
{
19
    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...
20
21
    /**
22
     * The name and signature of the console command.
23
     *
24
     * @var string
25
     */
26
    protected $signature = 'modelarium:frontend
27
        {name : The model name. Use "*" or "all" for all models}
28
        {--framework=* : The frameworks to use}
29
        {--lighthouse : use lighthouse directives}
30
        {--overwrite-graphql : overwrite graphql files if they exist}
31
        {--overwrite-match= : overwrite files that contain this string}
32
        {--overwrite : overwrite all files if they exist}
33
        {--prettier : run prettier 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
     * Create a new command instance.
55
     *
56
     * @return void
57
     */
58
    public function __construct()
59
    {
60
        parent::__construct();
61
    }
62
63
    /**
64
     * Execute the console command.
65
     *
66
     * @return mixed
67
     */
68
    public function handle()
69
    {
70
        $name = $this->argument('name');
71
72
        // setup stuff
73
        // @phpstan-ignore-next-line
74
        $this->frameworks = $this->option('framework');
75
        if (empty($this->frameworks)) {
76
            $this->error('If you are generating frontend you need to specify frameworks. Example: `--framework=HTML --framework=Bootstrap --framework=Vue`');
77
            return;
78
        }
79
        if (!is_array($this->frameworks)) {
0 ignored issues
show
introduced by
The condition is_array($this->frameworks) is always true.
Loading history...
80
            // @phpstan-ignore-next-line
81
            $this->frameworks = [$this->frameworks];
82
        }
83
      
84
        $this->loadParser();
85
        if ($name === '*' || $name === 'all') {
86
            /** @var array<class-string> $classesInNamespace */
87
            $classesInNamespace = ClassFinder::getClassesInNamespace('App\\Models');
88
89
            foreach ($classesInNamespace as $class) {
90
                $reflection = new \ReflectionClass($class);
91
                if (!$reflection->isInstantiable()) {
92
                    continue;
93
                }
94
                $this->generateFromModel($class);
95
            }
96
            return;
97
        } elseif (is_array($name)) {
98
            // TODO
99
        } else {
100
            $this->generateFromModel('\\App\\Models\\' . $name);
101
        }
102
        $this->info('Finished frontend.');
103
    }
104
105
    protected function loadParser(): void
106
    {
107
        $files = [
108
            __DIR__ . '/../../../Types/Graphql/scalars.graphql'
109
        ];
110
        if ($this->option('lighthouse')) {
111
            $files[] = __DIR__ . '/../../Graphql/definitionsLighthouse.graphql';
112
        }
113
114
        $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

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

155
        $basepath = /** @scrutinizer ignore-call */ base_path('resources/js/components/');
Loading history...
156
        $writtenFiles = $this->writeFiles(
157
            $collection,
158
            $basepath,
159
            function (GeneratedItem $i) use ($match) {
160
                if ((bool)$this->option('overwrite') === true) {
161
                    return true;
162
                }
163
                if ((bool)$this->option('overwrite-graphql') === true) {
164
                    if (
165
                        StringUtil::endsWith($i->filename, '.graphql')
166
                    ) {
167
                        return true;
168
                    } elseif (StringUtil::endsWith($i->filename, 'model.js')) {
169
                        return true;
170
                    }
171
                }
172
                if ($match && mb_strpos($i->filename, $match) !== false) {
173
                    return true;
174
                }
175
                return false;
176
            }
177
        );
178
        $this->info('Files generated.');
179
180
        if ($this->option('prettier')) {
181
            $this->info('Running prettier on generated files.');
182
            $useYarn = file_exists(base_path('yarn.lock'));
183
            if ($useYarn) {
184
                $command = "cd $basepath && npx prettier --write ";
185
            } else {
186
                $command = "cd $basepath && yarn prettier --write ";
187
            }
188
189
            // this runs all prettier commands in parallel.
190
            $run = array_reduce(
191
                $writtenFiles,
192
                function ($carry, $f) use ($command) {
193
                    return $carry . '(' . $command . $f . ') & ';
194
                }
195
            );
196
            shell_exec($run . ' wait');
197
        }
198
    }
199
}
200