Passed
Push — master ( db825e...64712d )
by Bruno
10:10
created

Processor::getDirectivesGraphqlString()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
ccs 2
cts 2
cp 1
cc 1
nc 1
nop 1
crap 1
1
<?php declare(strict_types=1);
2
3
namespace Modelarium\Laravel;
4
5
use GraphQL\Type\Definition\ObjectType;
6
use GraphQL\Type\Definition\Type;
7
use HaydenPierce\ClassFinder\ClassFinder;
8
use Modelarium\Exception\Exception;
9
use Modelarium\Exception\SkipGenerationException;
10
use Modelarium\GeneratedCollection;
11
use Modelarium\GeneratedItem;
12
use Modelarium\Laravel\Targets\EventGenerator;
13
use Modelarium\Laravel\Targets\FactoryGenerator;
14
use Modelarium\Laravel\Targets\MigrationGenerator;
15
use Modelarium\Laravel\Targets\ModelGenerator;
16
use Modelarium\Laravel\Targets\PolicyGenerator;
17
use Modelarium\Laravel\Targets\SeedGenerator;
18
use Modelarium\Parser;
19
use Modelarium\Processor as ModelariumProcessor;
20
use Nette\PhpGenerator\ClassType;
21
use Nuwave\Lighthouse\Schema\Factories\DirectiveFactory;
22
23
use function Safe\class_implements;
24
25
class Processor extends ModelariumProcessor
26
{
27
    /**
28
     * @var Parser
29
     */
30
    protected $parser = null;
31
32
    /**
33
     * @var bool
34
     */
35
    protected $runMigration = true;
36
37
    /**
38
     * @var bool
39
     */
40
    protected $runSeed = true;
41
42
    /**
43
     * @var bool
44
     */
45
    protected $runFactory = true;
46
47
    /**
48
     * @var bool
49
     */
50
    protected $runModel = true;
51
52
    /**
53
     * @var bool
54
     */
55
    protected $runPolicy = true;
56
57
    /**
58
     * @var bool
59
     */
60
    protected $runEvent = true;
61
62
    /**
63
     * DatabaseSeeder class for Laravel
64
     *
65
     * @var ClassType
66
     */
67
    protected $seederClass = null;
68
69 8
    public function __construct()
70
    {
71 8
        $this->parser = new Parser();
72 8
        $this->parser->setImport('directives.graphql', self::getDirectivesGraphqlString());
73 8
    }
74
75
    /**
76
     * Scan the given namespaces for directive classes.
77
     *
78
     * @param  string[]  $directiveNamespaces
79
     * @return array<string, string>
80
     */
81 8
    public static function getDirectivesGraphql($directiveNamespaces = [ 'Modelarium\Laravel\Lighthouse\Directives' ]): array
82
    {
83 8
        $directives = [];
84
85 8
        foreach ($directiveNamespaces as $directiveNamespace) {
86
            /** @var array<class-string> $classesInNamespace */
87 8
            $classesInNamespace = ClassFinder::getClassesInNamespace($directiveNamespace);
88
89 8
            foreach ($classesInNamespace as $class) {
90 8
                $reflection = new \ReflectionClass($class);
91 8
                if (! $reflection->isInstantiable()) {
92
                    continue;
93
                }
94
95 8
                if (! is_a($class, \Nuwave\Lighthouse\Schema\Directives\BaseDirective::class, true)) {
96
                    continue;
97
                }
98
                
99 8
                $name = DirectiveFactory::directiveName((string)$class);
100
                // @phpstan-ignore-next-line
101 8
                $directives[$name] = trim($class::definition());
102
            }
103
        }
104
105 8
        return $directives;
106
    }
107
108
    /**
109
     * Scan the given namespaces for directive classes.
110
     *
111
     * @param  string[]  $directiveNamespaces
112
     * @return string
113
     */
114 8
    public static function getDirectivesGraphqlString($directiveNamespaces = [ 'Modelarium\\Laravel\\Lighthouse\\Directives' ]): string
115
    {
116 8
        return implode("\n\n", self::getDirectivesGraphql($directiveNamespaces));
117
    }
118
119
    /**
120
     *
121
     * @param string[] $files
122
     * @return GeneratedCollection
123
     */
124
    public function processFiles(array $files): GeneratedCollection
125
    {
126
        $this->parser->fromFiles($files);
127
        return $this->process();
128
    }
129
130
    /**
131
     *
132
     * @param string $data
133
     * @return GeneratedCollection
134
     */
135 7
    public function processString(string $data): GeneratedCollection
136
    {
137 7
        $this->parser->fromString($data);
138 7
        return $this->process();
139
    }
140
141
    /**
142
     *
143
     * @param string[] $data
144
     * @return GeneratedCollection
145
     */
146 1
    public function processStrings(array $data): GeneratedCollection
147
    {
148 1
        $this->parser->fromStrings($data);
149 1
        return $this->process();
150
    }
151
152
    /**
153
     *
154
     * @return GeneratedCollection
155
     */
156 8
    public function process(): GeneratedCollection
157
    {
158 8
        $schema = $this->parser->getSchema();
159 8
        $typeMap = $schema->getTypeMap();
160
161 8
        $this->collection = new GeneratedCollection();
162 8
        if ($this->runSeed) {
163 8
            $this->createSeederClass();
164
        }
165
166 8
        foreach ($typeMap as $name => $object) {
167 8
            if ($object instanceof ObjectType) {
168 8
                if ($name === 'Query' || $name === 'Mutation' || $name === 'Subscription' || $name === 'Can') {
169 1
                    continue;
170
                }
171 8
                $g = $this->processType((string)$name, $object);
172 8
                $this->collection = $this->collection->merge($g);
173
            }
174
        }
175
176 8
        $this->collection = $this->collection->merge($this->processMutation($schema->getMutationType()));
177
        $this->collection = $this->collection->merge($this->processQuery($schema->getQueryType()));
178 8
179 8
        if ($this->runSeed) {
180 8
            $printer = new \Nette\PhpGenerator\PsrPrinter;
181 8
            $seeder = "<?php\n\n" . $printer->printClass($this->seederClass);
182 8
            $this->collection->add(
183 8
                new GeneratedItem(
184
                    GeneratedItem::TYPE_SEED,
185 8
                    $seeder,
186
                    SeedGenerator::getBasePath('database/seeds/DatabaseSeeder.php')
187
                )
188
            );
189
        }
190 8
191
        return $this->collection;
192
    }
193 8
194
    protected function processType(string $name, ObjectType $object): GeneratedCollection
195 8
    {
196 8
        $collection = new GeneratedCollection();
197
        if (str_starts_with($name, '__')) {
198 8
            // internal type
199
            return $collection;
200
        }
201
202 8
        // @typeSkip
203 8
        $directives = $object->astNode->directives;
204
        foreach ($directives as $directive) {
205
            $dName = $directive->name->value;
206
            if ($dName === 'typeSkip') {
207
                return $collection;
208
            }
209
        }
210 8
211
        if ($this->runMigration) {
212 8
            try {
213
                $collection = $collection->merge((new MigrationGenerator($this->parser, $name, $object))->generate());
214
            } catch (SkipGenerationException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
215
            }
216 8
        }
217
        if ($this->runSeed) {
218 8
            try {
219 8
                $generator = new SeedGenerator($this->parser, $name, $object);
220
                $collection = $collection->merge($generator->generate());
221 8
222 8
                $this->seederClass->getMethod('run')
223
                ->addBody('$this->call(' . $generator->getStudlyName() . 'Seeder::class);');
224
            } catch (SkipGenerationException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
225
            }
226 8
        }
227
        if ($this->runFactory) {
228 8
            try {
229
                $collection = $collection->merge((new FactoryGenerator($this->parser, $name, $object))->generate());
230
            } catch (SkipGenerationException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
231
            }
232 8
        }
233
        if ($this->runModel) {
234 8
            try {
235
                $collection = $collection->merge((new ModelGenerator($this->parser, $name, $object))->generate());
236
            } catch (SkipGenerationException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
237
            }
238 8
        }
239
        return $collection;
240
    }
241 8
242
    protected function processMutation(?Type $object):  GeneratedCollection
243 8
    {
244 8
        $collection = new GeneratedCollection();
245 7
        if (!$object) {
246
            return $collection;
247 1
        }
248 1
        if ($this->runPolicy) {
249
            $collection = $collection->merge((new PolicyGenerator($this->parser, 'Mutation', $object))->generate());
250 1
        }
251 1
        if ($this->runEvent) {
252
            $collection = $collection->merge((new EventGenerator($this->parser, 'Mutation', $object))->generate());
253 1
        }
254
        return $collection;
255
    }
256
257
258
    protected function processQuery(?Type $object):  GeneratedCollection
259
    {
260
        $collection = new GeneratedCollection();
261 8
        if (!$object) {
262
            return $collection;
263 8
        }
264 8
        if ($this->runEvent) {
265 8
            $collection = $collection->merge((new EventGenerator($this->parser, 'Query', $object))->generate());
266
        }
267 8
        return $collection;
268 8
    }
269 8
270 8
    /**
271
     * Generates the DatabaseSeeder class.
272
     *
273
     * @return void
274
     */
275
    protected function createSeederClass(): void
276
    {
277
        $this->seederClass = new \Nette\PhpGenerator\ClassType('DatabaseSeeder');
278
        $this->seederClass->setExtends('Illuminate\Database\Seeder')
279
            ->addComment("This file was automatically generated by Modelarium.");
280
281
        $this->seederClass->addMethod('run')
282
                ->setPublic()
283
                ->addComment("Seed the application\'s database.\n@return void");
284
    }
285
286
    /**
287
     * Set the value of runMigration
288
     *
289
     * @param  bool  $runMigration
290
     *
291
     * @return  self
292
     */
293
    public function setRunMigration(bool $runMigration): self
294
    {
295
        $this->runMigration = $runMigration;
296
297
        return $this;
298
    }
299
300
    /**
301
     * Set the value of runSeed
302
     *
303
     * @param  bool  $runSeed
304
     *
305
     * @return  self
306
     */
307
    public function setRunSeed(bool $runSeed): self
308
    {
309
        $this->runSeed = $runSeed;
310
311
        return $this;
312
    }
313
314
    /**
315
     * Set the value of runFactory
316
     *
317
     * @param  bool  $runFactory
318
     *
319
     * @return  self
320
     */
321
    public function setRunFactory(bool $runFactory): self
322
    {
323
        $this->runFactory = $runFactory;
324
325
        return $this;
326
    }
327
328
    /**
329
     * Set the value of runModel
330
     *
331
     * @param  bool  $runModel
332
     *
333
     * @return  self
334
     */
335
    public function setRunModel(bool $runModel): self
336
    {
337
        $this->runModel = $runModel;
338
339
        return $this;
340
    }
341
342
    /**
343
     * Set the value of runPolicy
344
     *
345
     * @param  bool  $runPolicy
346
     *
347
     * @return  self
348
     */
349
    public function setRunPolicy(bool $runPolicy): self
350
    {
351
        $this->runPolicy = $runPolicy;
352
353
        return $this;
354
    }
355
356
    /**
357
     * Set the value of runEvent
358
     *
359
     * @param  bool  $runEvent
360
     *
361
     * @return  self
362
     */
363
    public function setRunEvent(bool $runEvent): self
364
    {
365
        $this->runEvent = $runEvent;
366
367
        return $this;
368
    }
369
}
370