Passed
Push — master ( 77d3fa...749702 )
by Bruno
05:09 queued 01:56
created

Processor::getDirectivesGraphql()   A

Complexity

Conditions 6
Paths 6

Size

Total Lines 27
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 6.288

Importance

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