Processor   B
last analyzed

Complexity

Total Complexity 45

Size/Duplication

Total Lines 342
Duplicated Lines 0 %

Test Coverage

Coverage 75.21%

Importance

Changes 5
Bugs 1 Features 0
Metric Value
eloc 111
c 5
b 1
f 0
dl 0
loc 342
ccs 88
cts 117
cp 0.7521
rs 8.8
wmc 45

17 Methods

Rating   Name   Duplication   Size   Complexity  
A getDirectivesGraphqlString() 0 3 1
A processStrings() 0 4 1
A __construct() 0 4 1
A setRunModel() 0 5 1
A getDirectivesGraphql() 0 24 5
A processQuery() 0 10 3
A processMutation() 0 13 4
A processFiles() 0 4 1
B process() 0 36 9
A setRunMigration() 0 5 1
A setRunEvent() 0 5 1
A setRunSeed() 0 5 1
A processString() 0 4 1
A setRunFactory() 0 5 1
A createSeederClass() 0 9 1
A setRunPolicy() 0 5 1
C processType() 0 46 12

How to fix   Complexity   

Complex Class

Complex classes like Processor often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Processor, and based on these observations, apply Extract Interface, too.

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 = \Nuwave\Lighthouse\Schema\DirectiveLocator::directiveName((string)$class);
100 8
                $directives[$name] = trim($class::definition());
101
            }
102
        }
103
104 8
        return $directives;
105
    }
106
107
    /**
108
     * Scan the given namespaces for directive classes.
109
     *
110
     * @param  string[]  $directiveNamespaces
111
     * @return string
112
     */
113 8
    public static function getDirectivesGraphqlString($directiveNamespaces = [ 'Modelarium\\Laravel\\Lighthouse\\Directives' ]): string
114
    {
115 8
        return implode("\n\n", self::getDirectivesGraphql($directiveNamespaces));
116
    }
117
118
    /**
119
     *
120
     * @param string[] $files
121
     * @return GeneratedCollection
122
     */
123 7
    public function processFiles(array $files): GeneratedCollection
124
    {
125 7
        $this->parser->fromFiles($files);
126 7
        return $this->process();
127
    }
128
129
    /**
130
     *
131
     * @param string $data
132
     * @return GeneratedCollection
133
     */
134
    public function processString(string $data): GeneratedCollection
135
    {
136
        $this->parser->fromString($data);
137
        return $this->process();
138
    }
139
140
    /**
141
     *
142
     * @param string[] $data
143
     * @return GeneratedCollection
144
     */
145 1
    public function processStrings(array $data): GeneratedCollection
146
    {
147 1
        $this->parser->fromStrings($data);
148 1
        return $this->process();
149
    }
150
151
    /**
152
     *
153
     * @return GeneratedCollection
154
     */
155 8
    public function process(): GeneratedCollection
156
    {
157 8
        $schema = $this->parser->getSchema();
158 8
        $typeMap = $schema->getTypeMap();
159
160 8
        $this->collection = new GeneratedCollection();
161 8
        if ($this->runSeed) {
162 8
            $this->createSeederClass();
163
        }
164
165 8
        foreach ($typeMap as $name => $object) {
166 8
            if ($object instanceof ObjectType) {
167 8
                if ($name === 'Query' || $name === 'Mutation' || $name === 'Subscription' || $name === 'Can') {
168 8
                    continue;
169
                }
170 8
                $g = $this->processType((string)$name, $object);
171 8
                $this->collection = $this->collection->merge($g);
172
            }
173
        }
174
175 8
        $this->collection = $this->collection->merge($this->processMutation($schema->getMutationType()));
176 8
        $this->collection = $this->collection->merge($this->processQuery($schema->getQueryType()));
177
178 8
        if ($this->runSeed) {
179 8
            $printer = new \Nette\PhpGenerator\PsrPrinter;
180 8
            $seeder = "<?php\n\n" . $printer->printClass($this->seederClass);
181 8
            $this->collection->add(
182 8
                new GeneratedItem(
183 8
                    GeneratedItem::TYPE_SEED,
184
                    $seeder,
185 8
                    SeedGenerator::getBasePath('database/seeds/DatabaseSeeder.php')
186
                )
187
            );
188
        }
189
190 8
        return $this->collection;
191
    }
192
193 8
    protected function processType(string $name, ObjectType $object): GeneratedCollection
194
    {
195 8
        $collection = new GeneratedCollection();
196 8
        if (str_starts_with($name, '__')) {
197
            // internal type
198 8
            return $collection;
199
        }
200
201
        // @typeSkip
202 8
        $directives = $object->astNode->directives;
203 8
        foreach ($directives as $directive) {
204 5
            $dName = $directive->name->value;
205 5
            if ($dName === 'typeSkip') {
206 5
                return $collection;
207
            }
208
        }
209
210 8
        if ($this->runMigration) {
211
            try {
212 8
                $collection = $collection->merge((new MigrationGenerator($this->parser, $name, $object))->generate());
213
            } catch (SkipGenerationException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
214
            }
215
        }
216 8
        if ($this->runSeed) {
217
            try {
218 8
                $generator = new SeedGenerator($this->parser, $name, $object);
219 8
                $collection = $collection->merge($generator->generate());
220
221 8
                $this->seederClass->getMethod('run')
222 8
                ->addBody('$this->call(' . $generator->getStudlyName() . 'Seeder::class);');
223
            } catch (SkipGenerationException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
224
            }
225
        }
226 8
        if ($this->runFactory) {
227
            try {
228 8
                $collection = $collection->merge((new FactoryGenerator($this->parser, $name, $object))->generate());
229
            } catch (SkipGenerationException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
230
            }
231
        }
232 8
        if ($this->runModel) {
233
            try {
234 8
                $collection = $collection->merge((new ModelGenerator($this->parser, $name, $object))->generate());
235
            } catch (SkipGenerationException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
236
            }
237
        }
238 8
        return $collection;
239
    }
240
241 8
    protected function processMutation(?Type $object):  GeneratedCollection
242
    {
243 8
        $collection = new GeneratedCollection();
244 8
        if (!$object) {
245
            return $collection;
246
        }
247 8
        if ($this->runPolicy) {
248 8
            $collection = $collection->merge((new PolicyGenerator($this->parser, 'Mutation', $object))->generate());
249
        }
250 8
        if ($this->runEvent) {
251 8
            $collection = $collection->merge((new EventGenerator($this->parser, 'Mutation', $object))->generate());
252
        }
253 8
        return $collection;
254
    }
255
256
257 8
    protected function processQuery(?Type $object):  GeneratedCollection
258
    {
259 8
        $collection = new GeneratedCollection();
260 8
        if (!$object) {
261
            return $collection;
262
        }
263 8
        if ($this->runEvent) {
264 8
            $collection = $collection->merge((new EventGenerator($this->parser, 'Query', $object))->generate());
265
        }
266 8
        return $collection;
267
    }
268
269
    /**
270
     * Generates the DatabaseSeeder class.
271
     *
272
     * @return void
273
     */
274 8
    protected function createSeederClass(): void
275
    {
276 8
        $this->seederClass = new \Nette\PhpGenerator\ClassType('DatabaseSeeder');
277 8
        $this->seederClass->setExtends('Illuminate\Database\Seeder')
278 8
            ->addComment("This file was automatically generated by Modelarium.");
279
280 8
        $this->seederClass->addMethod('run')
281 8
                ->setPublic()
282 8
                ->addComment("Seed the application\'s database.\n@return void");
283 8
    }
284
285
    /**
286
     * Set the value of runMigration
287
     *
288
     * @param  bool  $runMigration
289
     *
290
     * @return  self
291
     */
292
    public function setRunMigration(bool $runMigration): self
293
    {
294
        $this->runMigration = $runMigration;
295
296
        return $this;
297
    }
298
299
    /**
300
     * Set the value of runSeed
301
     *
302
     * @param  bool  $runSeed
303
     *
304
     * @return  self
305
     */
306
    public function setRunSeed(bool $runSeed): self
307
    {
308
        $this->runSeed = $runSeed;
309
310
        return $this;
311
    }
312
313
    /**
314
     * Set the value of runFactory
315
     *
316
     * @param  bool  $runFactory
317
     *
318
     * @return  self
319
     */
320
    public function setRunFactory(bool $runFactory): self
321
    {
322
        $this->runFactory = $runFactory;
323
324
        return $this;
325
    }
326
327
    /**
328
     * Set the value of runModel
329
     *
330
     * @param  bool  $runModel
331
     *
332
     * @return  self
333
     */
334
    public function setRunModel(bool $runModel): self
335
    {
336
        $this->runModel = $runModel;
337
338
        return $this;
339
    }
340
341
    /**
342
     * Set the value of runPolicy
343
     *
344
     * @param  bool  $runPolicy
345
     *
346
     * @return  self
347
     */
348
    public function setRunPolicy(bool $runPolicy): self
349
    {
350
        $this->runPolicy = $runPolicy;
351
352
        return $this;
353
    }
354
355
    /**
356
     * Set the value of runEvent
357
     *
358
     * @param  bool  $runEvent
359
     *
360
     * @return  self
361
     */
362
    public function setRunEvent(bool $runEvent): self
363
    {
364
        $this->runEvent = $runEvent;
365
366
        return $this;
367
    }
368
}
369