Passed
Push — master ( 253428...340885 )
by Bruno
03:15
created

ModelGenerator::processDirectives()   C

Complexity

Conditions 12
Paths 12

Size

Total Lines 49
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 31.692

Importance

Changes 4
Bugs 2 Features 1
Metric Value
eloc 32
c 4
b 2
f 1
dl 0
loc 49
ccs 16
cts 33
cp 0.4848
rs 6.9666
cc 12
nc 12
nop 1
crap 31.692

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php declare(strict_types=1);
2
3
namespace Modelarium\Laravel\Targets;
4
5
use Formularium\Datatype;
6
use Formularium\Extradata;
7
use Formularium\ExtradataParameter;
8
use Formularium\Field;
9
use Formularium\Model;
10
use Illuminate\Support\Str;
11
use GraphQL\Type\Definition\ListOfType;
12
use GraphQL\Type\Definition\NonNull;
13
use GraphQL\Type\Definition\ObjectType;
14
use GraphQL\Type\Definition\UnionType;
15
use Modelarium\BaseGenerator;
16
use Modelarium\Datatypes\Datatype_relationship;
17
use Modelarium\Datatypes\RelationshipFactory;
18
use Modelarium\Exception\Exception;
19
use Modelarium\FormulariumUtils;
20
use Modelarium\GeneratedCollection;
21
use Modelarium\GeneratedItem;
22
use Modelarium\Parser;
23
use Modelarium\Types\FormulariumScalarType;
24
use Nette\PhpGenerator\Method;
25
use GraphQL\Language\AST\DirectiveNode;
26
27
class ModelGenerator extends BaseGenerator
28
{
29
    /**
30
     * @var string
31
     */
32
    protected $stubDir = __DIR__ . "/stubs/";
33
34
    /**
35
     * @var string
36
     */
37
    protected static $modelDir = 'app/Models/';
38
39
    /**
40
     * @var ObjectType
41
     */
42
    protected $type = null;
43
44
    /**
45
     * @var \Nette\PhpGenerator\ClassType
46
     */
47
    public $class = null;
48
49
    /**
50
     * fillable attributes
51
     *
52
     * @var array
53
     */
54
    public $fillable = [];
55
56
    /**
57
     * fillable attributes
58
     *
59
     * @var array
60
     */
61
    public $hidden = [];
62
63
    /**
64
     * cast attributes
65
     *
66
     * @var array
67
     */
68
    public $casts = [];
69
70
    /**
71
     *
72
     * @var string
73
     */
74
    public $parentClassName = '\Illuminate\Database\Eloquent\Model';
75
76
    /**
77
     * fields
78
     *
79
     * @var Model
80
     */
81
    public $fModel = null;
82
83
    /**
84
     *
85
     * @var array
86
     */
87
    public $traits = [];
88
89
    /**
90
     * Random generation
91
     *
92
     * @var Method
93
     */
94
    protected $methodRandom = null;
95
96
    /**
97
     * Do we have a 'can' attribute?
98
     *
99
     * @var boolean
100
     */
101
    protected $hasCan = true;
102
103
    /**
104
     * If true, we have timestamps on the migration.
105
     *
106
     * @var boolean
107
     */
108
    protected $migrationTimestamps = false;
109
110 10
    public function generate(): GeneratedCollection
111
    {
112 10
        $this->fModel = Model::create($this->studlyName);
113 10
        $x = new GeneratedCollection([
114 10
            new GeneratedItem(
115 10
                GeneratedItem::TYPE_MODEL,
116 10
                $this->generateString(),
117 10
                $this->getGenerateFilename()
118
            ),
119 10
            new GeneratedItem(
120 10
                GeneratedItem::TYPE_MODEL,
121 10
                $this->templateStub('model'),
122 10
                $this->getGenerateFilename(false),
123 10
                true
124
            )
125
        ]);
126 10
        return $x;
127
    }
128
129 10
    protected function processField(
130
        string $typeName,
131
        \GraphQL\Type\Definition\FieldDefinition $field,
132
        \GraphQL\Language\AST\NodeList $directives,
133
        bool $isRequired
134
    ): void {
135 10
        $fieldName = $field->name;
136
137 10
        if ($typeName === 'ID') {
138 10
            return;
139
        }
140
141 10
        $scalarType = $this->parser->getScalarType($typeName);
142
143
        /**
144
         * @var Field $field
145
         */
146 10
        $field = null;
147 10
        if (!$scalarType) {
148
            // probably another model
149 8
            $field = FormulariumUtils::getFieldFromDirectives(
150 8
                $fieldName,
151 8
                $typeName,
152 8
                $directives
153
            );
154 5
        } elseif ($scalarType instanceof FormulariumScalarType) {
155 5
            $field = FormulariumUtils::getFieldFromDirectives(
156 5
                $fieldName,
157 5
                $scalarType->getDatatype()->getName(),
158 5
                $directives
159
            );
160
        } else {
161
            return;
162
        }
163
164 10
        if ($isRequired) {
165 10
            $field->setValidatorOption(
166 10
                Datatype::REQUIRED,
167 10
                'value',
168 10
                true
169
            );
170
        }
171
172 10
        $this->fModel->appendField($field);
173 10
    }
174
175 10
    protected function processFieldDirectives(
176
        \GraphQL\Type\Definition\FieldDefinition $field,
177
        \GraphQL\Language\AST\NodeList $directives
178
    ): void {
179 10
        $fieldName = $field->name;
180
181 10
        list($type, $isRequired) = Parser::getUnwrappedType($field->type);
182
183 10
        foreach ($directives as $directive) {
184
            $name = $directive->name->value;
185
            $className = $this->getDirectiveClass($name);
186
            if ($className) {
187
                $methodName = "$className::processModelFieldDirective";
188
                $methodName(
189
                    $this,
190
                    $field,
191
                    $directive
192
                );
193
            }
194
        }
195
196
        // TODO: convert to separate classes
197 10
        foreach ($directives as $directive) {
198
            $name = $directive->name->value;
199
            switch ($name) {
200
            
201
            case 'casts':
202
                foreach ($directive->arguments as $arg) {
203
                    /**
204
                     * @var \GraphQL\Language\AST\ArgumentNode $arg
205
                     */
206
207
                    $value = $arg->value->value;
0 ignored issues
show
Bug introduced by
Accessing value on the interface GraphQL\Language\AST\ValueNode suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
208
209
                    switch ($arg->name->value) {
210
                    case 'type':
211
                        $this->casts[$fieldName] = $value;
212
                    }
213
                }
214
                break;
215
            }
216
        }
217
218 10
        $typeName = $type->name;
219 10
        $this->processField($typeName, $field, $directives, $isRequired);
220 10
    }
221
222 8
    protected function processRelationship(
223
        \GraphQL\Type\Definition\FieldDefinition $field,
224
        \GraphQL\Language\AST\NodeList $directives
225
    ): void {
226 8
        $lowerName = mb_strtolower($this->getInflector()->singularize($field->name));
227 8
        $lowerNamePlural = $this->getInflector()->pluralize($lowerName);
228
229 8
        $targetClass = '\\App\\Models\\' . Str::studly($this->getInflector()->singularize($field->name));
230
231 8
        list($type, $isRequired) = Parser::getUnwrappedType($field->type);
232 8
        $typeName = $type->name;
233
234
        // special types that should be skipped.
235 8
        if ($typeName === 'Can') {
236
            $this->hasCan = true;
237
            return;
238
        }
239
240 8
        $generateRandom = false;
241 8
        $sourceTypeName = $this->lowerName;
242 8
        $targetTypeName = $lowerName;
243 8
        $relationship = null;
244 8
        $isInverse = false;
245
246
        // TODO: convert to separate classes
247 8
        foreach ($directives as $directive) {
248 8
            $name = $directive->name->value;
249 8
            switch ($name) {
250 8
            case 'belongsTo':
251 4
                $generateRandom = true;
252 4
                $relationship = RelationshipFactory::RELATIONSHIP_ONE_TO_MANY;
253 4
                $isInverse = true;
254 4
                $this->class->addMethod($lowerName)
255 4
                    ->setPublic()
256 4
                    ->setReturnType('\\Illuminate\\Database\\Eloquent\\Relations\\BelongsTo')
257 4
                    ->setBody("return \$this->belongsTo($targetClass::class);");
258 4
                break;
259
260 8
            case 'belongsToMany':
261 1
                $generateRandom = true;
262 1
                $relationship = RelationshipFactory::RELATIONSHIP_MANY_TO_MANY;
263 1
                $isInverse = true;
264 1
                $this->class->addMethod($lowerNamePlural)
265 1
                    ->setPublic()
266 1
                    ->setReturnType('\\Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany')
267 1
                    ->setBody("return \$this->belongsToMany($targetClass::class);");
268 1
                break;
269
270 7
            case 'hasOne':
271 3
                $relationship = RelationshipFactory::RELATIONSHIP_ONE_TO_ONE;
272 3
                $isInverse = false;
273 3
                $this->class->addMethod($lowerName)
274 3
                    ->setPublic()
275 3
                    ->setReturnType('\\Illuminate\\Database\\Eloquent\\Relations\\HasOne')
276 3
                    ->setBody("return \$this->hasOne($targetClass::class);");
277 3
                break;
278
279 7
            case 'hasMany':
280 1
                $relationship = RelationshipFactory::RELATIONSHIP_ONE_TO_MANY;
281 1
                $isInverse = false;
282 1
                $target = $this->getInflector()->singularize($targetClass);
283 1
                $this->class->addMethod($lowerNamePlural)
284 1
                    ->setPublic()
285 1
                    ->setReturnType('\\Illuminate\\Database\\Eloquent\\Relations\\HasMany')
286 1
                    ->setBody("return \$this->hasMany($target::class);");
287 1
                break;
288
289 7
            case 'morphOne':
290 7
            case 'morphMany':
291 7
            case 'morphToMany':
292 3
                if ($name === 'morphOne') {
293 1
                    $relationship = RelationshipFactory::MORPH_ONE_TO_ONE;
294
                } else {
295 2
                    $relationship = RelationshipFactory::MORPH_ONE_TO_MANY;
296
                }
297 3
                $isInverse = false;
298
299 3
                $targetType = $this->parser->getType($typeName);
300 3
                if (!$targetType) {
301
                    throw new Exception("Cannot get type {$typeName} as a relationship to {$this->baseName}");
302 3
                } elseif (!($targetType instanceof ObjectType)) {
303
                    throw new Exception("{$typeName} is not a type for a relationship to {$this->baseName}");
304
                }
305 3
                $targetField = null;
306 3
                foreach ($targetType->getFields() as $subField) {
307 3
                    $subDir = Parser::getDirectives($subField->astNode->directives);
308 3
                    if (array_key_exists('morphTo', $subDir) || array_key_exists('morphedByMany', $subDir)) {
309 3
                        $targetField = $subField->name;
310 3
                        break;
311
                    }
312
                }
313 3
                if (!$targetField) {
314
                    throw new Exception("{$targetType} does not have a '@morphTo' or '@morphToMany' field");
315
                }
316
317 3
                $this->class->addMethod($field->name)
318
                    // TODO: return type
319 3
                    ->setPublic()
320 3
                    ->setBody("return \$this->{$name}($typeName::class, '$targetField');");
321 3
                break;
322
    
323 7
            case 'morphTo':
324 2
                $relationship = RelationshipFactory::MORPH_ONE_TO_MANY; // TODO
325 2
                $isInverse = true;
326 2
                $this->class->addMethod($field->name)
327 2
                    ->setReturnType('\\Illuminate\\Database\\Eloquent\\Relations\\MorphTo')
328 2
                    ->setPublic()
329 2
                    ->setBody("return \$this->morphTo();");
330 2
                break;
331
332 5
            case 'morphedByMany':
333 1
                $relationship = RelationshipFactory::MORPH_MANY_TO_MANY; // TODO
334 1
                $isInverse = true;
335 1
                $typeMap = $this->parser->getSchema()->getTypeMap();
336
       
337 1
                foreach ($typeMap as $name => $object) {
338 1
                    if (!($object instanceof ObjectType) || $name === 'Query' || $name === 'Mutation' || $name === 'Subscription') {
339 1
                        continue;
340
                    }
341
342
                    /**
343
                     * @var ObjectType $object
344
                     */
345
346 1
                    if (str_starts_with((string)$name, '__')) {
347
                        // internal type
348 1
                        continue;
349
                    }
350
351 1
                    foreach ($object->getFields() as $subField) {
352 1
                        $subDirectives = Parser::getDirectives($subField->astNode->directives);
353
354 1
                        if (!array_key_exists('morphToMany', $subDirectives)) {
355 1
                            continue;
356
                        }
357
358 1
                        $methodName = $this->getInflector()->pluralize(mb_strtolower((string)$name));
359 1
                        $this->class->addMethod($methodName)
360 1
                                ->setReturnType('\\Illuminate\\Database\\Eloquent\\Relations\\MorphToMany')
361 1
                                ->setPublic()
362 1
                                ->setBody("return \$this->morphedByMany($name::class, '$lowerName');");
363
                    }
364
                }
365 1
                break;
366
367 4
            case 'laravelMediaLibraryData':
368
                $collection = 'images';
369
                $customFields = [];
370
                $studlyFieldName = Str::studly($field->name);
371
372
                // deps
373
                if (!in_array('\\Spatie\\MediaLibrary\\HasMedia', $this->class->getImplements())) {
374
                    $this->class->addImplement('\\Spatie\\MediaLibrary\\HasMedia');
375
                    $this->class->addTrait('\\Spatie\\MediaLibrary\\InteractsWithMedia');
376
                }
377
378
                // args
379
                foreach ($directive->arguments as $arg) {
380
                    /**
381
                     * @var \GraphQL\Language\AST\ArgumentNode $arg
382
                     */
383
384
                    switch ($arg->name->value) {
385
                    case 'collection':
386
                        $collection = $arg->value->value;
0 ignored issues
show
Bug introduced by
Accessing value on the interface GraphQL\Language\AST\ValueNode suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
387
                    break;
388
                    case 'fields':
389
                        foreach ($arg->value->values as $item) {
0 ignored issues
show
Bug introduced by
Accessing values on the interface GraphQL\Language\AST\ValueNode suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
390
                            $customFields[] = $item->value;
391
                        }
392
                    break;
393
                    }
394
                }
395
                $studlyCollection = Str::studly($collection);
396
397
                // registration
398
                if (!$this->class->hasMethod("registerMediaCollections")) {
399
                    $registerMediaCollections = $this->class->addMethod("registerMediaCollections")
400
                        ->setPublic()
401
                        ->setReturnType('void')
402
                        ->addComment("Configures Laravel media-library");
403
                } else {
404
                    $registerMediaCollections = $this->class->getMethod("registerMediaCollections");
405
                }
406
                $registerMediaCollections->addBody("\$this->addMediaCollection(?);\n", [$collection]);
407
408
                // all image models for this collection
409
                $this->class->addMethod("getMedia{$studlyCollection}Collection")
410
                    ->setPublic()
411
                    ->setReturnType('\\Spatie\\MediaLibrary\\MediaCollections\\Models\\Collections\\MediaCollection')
412
                    ->addComment("Returns a collection media from Laravel-MediaLibrary")
413
                    ->setBody("return \$this->getMedia(?);", [$collection]);
414
415
                // custom fields
416
                $this->class->addMethod("getMedia{$studlyCollection}CustomFields")
417
                    ->setPublic()
418
                    ->setReturnType('array')
419
                    ->addComment("Returns custom fields for the media")
420
                    ->setBody("return ?;", [$customFields]);
421
422
                $this->class->addMethod("get{$studlyFieldName}urlAttribute")
423
                    ->setPublic()
424
                    ->setReturnType('string')
425
                    ->addComment("Returns the media attribute (url) for the $collection")
426
                    ->setBody( /** @lang PHP */
427
                        <<< PHP
428
        \$image = \$this->getMedia{$studlyCollection}Collection()->first();
429
        if (\$image) {
430
            return \$image->getUrl();
431
        }
432
        return '';
433
        PHP
434
                    );
435
436
                // all image models for this collection
437
                $this->class->addMethod("get{$studlyFieldName}Attribute")
438
                    ->setPublic()
439
                    ->setReturnType('array')
440
                    ->addComment("Returns media attribute for the $collection media with custom fields")
441
                    ->setBody( /** @lang PHP */
442
                        <<< PHP
443
        \$image = \$this->getMedia{$studlyCollection}Collection()->first();
444
if (\$image) {
445
    \$customFields = [];
446
    foreach (\$this->getMedia{$studlyCollection}CustomFields() as \$c) {
447
        \$customFields[\$c] = \$image->getCustomProperty(\$c);
448
    }
449
    return [
450
        'url' => \$image->getUrl(),
451
        'fields' => json_encode(\$customFields)
452
    ];
453
}
454
return [];
455
PHP
456
                    );
457
                return;
458
            
459
            default:
460 4
                break;
461
            }
462
        }
463 8
        if (!$relationship) {
464
            throw new Exception("Could not find a relationship in {$typeName} for {$field->name} in {$sourceTypeName}");
465
        }
466
467 8
        $relationshipDatatype = "relationship:" . ($isInverse ? "inverse:" : "") .
468 8
            "$relationship:$sourceTypeName:$targetTypeName";
469
470 8
        $this->processField($relationshipDatatype, $field, $directives, $isRequired);
471
472 8
        if ($generateRandom) {
473 5
            if ($relationship == RelationshipFactory::RELATIONSHIP_MANY_TO_MANY || $relationship == RelationshipFactory::MORPH_MANY_TO_MANY) {
474
                // TODO: do we generate it? seed should do it?
475
            } else {
476 4
                $this->methodRandom->addBody(
477 4
                    '$data["' . $lowerName . '_id"] = function () {' . "\n" .
478 4
                '    return factory(' . $targetClass . '::class)->create()->id;'  . "\n" .
479 4
                '};'
480
                );
481
            }
482
        }
483 8
    }
484
485 10
    protected function processDirectives(
486
        \GraphQL\Language\AST\NodeList $directives
487
    ): void {
488
        // TODO: convert to separate classes
489 10
        foreach ($directives as $directive) {
490 1
            $name = $directive->name->value;
491 1
            $this->fModel->appendExtradata(FormulariumUtils::directiveToExtradata($directive));
492
493 1
            switch ($name) {
494 1
            case 'migrationSoftDeletes':
495 1
                $this->traits[] = '\Illuminate\Database\Eloquent\SoftDeletes';
496 1
                break;
497 1
            case 'modelNotifiable':
498
                $this->traits[] = '\Illuminate\Notifications\Notifiable';
499
                break;
500 1
            case 'modelMustVerifyEmail':
501
                $this->traits[] = '\Illuminate\Notifications\MustVerifyEmail';
502
                break;
503 1
            case 'migrationRememberToken':
504 1
                $this->hidden[] = 'remember_token';
505 1
                break;
506 1
            case 'migrationTimestamps':
507 1
                $this->migrationTimestamps = true;
508 1
                break;
509
            case 'modelExtends':
510
                foreach ($directive->arguments as $arg) {
511
                    /**
512
                     * @var \GraphQL\Language\AST\ArgumentNode $arg
513
                     */
514
515
                    $value = $arg->value->value;
0 ignored issues
show
Bug introduced by
Accessing value on the interface GraphQL\Language\AST\ValueNode suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
516
517
                    switch ($arg->name->value) {
518
                    case 'class':
519
                        $this->parentClassName = $value;
520
                    }
521
                }
522
                break;
523
            case 'renderable':
524
                foreach ($directive->arguments as $arg) {
525
                    /**
526
                     * @var \GraphQL\Language\AST\ArgumentNode $arg
527
                     */
528
529
                    $argName = $arg->name->value;
530
                    $argValue = $arg->value->value; /** @phpstan-ignore-line */
531
                    $this->fModel->appendRenderable($argName, $argValue);
0 ignored issues
show
Bug introduced by
The method appendRenderable() does not exist on Formularium\Model. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

531
                    $this->fModel->/** @scrutinizer ignore-call */ 
532
                                   appendRenderable($argName, $argValue);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
532
                }
533
                break;
534
            }
535
        }
536 10
    }
537
538 10
    public function generateString(): string
539
    {
540 10
        $namespace = new \Nette\PhpGenerator\PhpNamespace('App\\Models');
541 10
        $namespace->addUse('\\Illuminate\\Database\\Eloquent\\Relations\\BelongsTo');
542 10
        $namespace->addUse('\\Illuminate\\Database\\Eloquent\\Relations\\HasOne');
543 10
        $namespace->addUse('\\Illuminate\\Database\\Eloquent\\Relations\\HasMany');
544 10
        $namespace->addUse('\\Illuminate\\Database\\Eloquent\\Relations\\MorphTo');
545 10
        $namespace->addUse('\\Illuminate\\Database\\Eloquent\\Relations\\MorphOne');
546 10
        $namespace->addUse('\\Illuminate\\Database\\Eloquent\\Relations\\MorphToMany');
547 10
        $namespace->addUse('\\Illuminate\\Support\\Facades\\Auth');
548 10
        $namespace->addUse('\\Formularium\\Exception\\NoRandomException');
549 10
        $namespace->addUse('\\Modelarium\\Laravel\\Datatypes\\Datatype_relationship');
550
551 10
        $this->class = $namespace->addClass('Base' . $this->studlyName);
552 10
        $this->class
553 10
            ->addComment("This file was automatically generated by Modelarium.")
554 10
            ->setAbstract();
555
556 10
        $this->methodRandom = new Method('getRandomData');
557 10
        $this->methodRandom->addBody(
558 10
            '$data = static::getFormularium()->getRandom(get_called_class() . \'::getRandomFieldData\');' . "\n"
559
        );
560
561 10
        $this->processGraphql();
562
563
        // this might have changed
564 10
        $this->class->setExtends($this->parentClassName);
565
566 10
        foreach ($this->traits as $trait) {
567 1
            $this->class->addTrait($trait);
568
        }
569
570 10
        $this->class->addProperty('fillable')
571 10
            ->setProtected()
572 10
            ->setValue($this->fillable)
573 10
            ->setComment("The attributes that are mass assignable.\n@var array")
574 10
            ->setInitialized();
575
576 10
        $this->class->addProperty('hidden')
577 10
            ->setProtected()
578 10
            ->setValue($this->hidden)
579 10
            ->setComment("The attributes that should be hidden for arrays.\n@var array")
580 10
            ->setInitialized();
581
582 10
        if (!$this->migrationTimestamps) {
583 9
            $this->class->addProperty('timestamps')
584 9
                ->setPublic()
585 9
                ->setValue(false)
586 9
                ->setComment("Do not set timestamps.\n@var boolean")
587 9
                ->setInitialized();
588
        }
589
590 10
        if ($this->casts) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->casts of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
591
            $this->class->addProperty('casts')
592
                ->setProtected()
593
                ->setValue($this->casts)
594
                ->setComment("The attributes that should be cast.\n@var array")
595
                ->setInitialized();
596
        }
597
598 10
        $this->class->addMethod('getFields')
599 10
            ->setPublic()
600 10
            ->setStatic()
601 10
            ->setReturnType('array')
602 10
            ->addComment('@return array')
603 10
            ->addBody(
604 10
                "return ?;\n",
605
                [
606 10
                    $this->fModel->serialize()
607
                ]
608
            );
609
610 10
        $this->class->addMethod('getFormularium')
611 10
            ->setPublic()
612 10
            ->setStatic()
613 10
            ->setReturnType('\Formularium\Model')
614 10
            ->addComment('@return \Formularium\Model')
615 10
            ->addBody(
616
                '$model = \Formularium\Model::fromStruct(static::getFields());' . "\n" .
617 10
                'return $model;',
618
                [
619
                    //$this->studlyName,
620 10
                ]
621
            );
622
        
623 10
        $this->methodRandom
624 10
            ->addComment('@return array')
625 10
            ->setPublic()
626 10
            ->setStatic()
627 10
            ->setReturnType('array')
628 10
            ->addBody('return $data;');
629 10
        $this->class->addMember($this->methodRandom);
630
631 10
        $this->class->addMethod('getRandomFieldData')
632 10
            ->setPublic()
633 10
            ->setStatic()
634 10
            ->addComment("Filters fields and generate random data. Throw NoRandomException for fields you don't want to generate random data, or return a valid value.")
635 10
            ->addBody('
636
$d = $f->getDatatype();
637
if ($d instanceof Datatype_relationship) {
638
    throw new NoRandomException($f->getName());
639
}
640
return $f->getDatatype()->getRandom();')
641 10
            ->addParameter('f')->setType('Formularium\Field');
642
643
        // TODO perhaps we can use PolicyGenerator->policyClasses to auto generate
644 10
        if ($this->hasCan) {
645 10
            $this->class->addMethod('getCanAttribute')
646 10
                ->setPublic()
647 10
                ->setReturnType('array')
648 10
                ->addComment("Returns the policy permissions for actions such as editing or deleting.\n@return \Formularium\Model")
649 10
                ->addBody(
650 10
                    '$policy = new \\App\\Policies\\' . $this->studlyName . 'Policy();' . "\n" .
651 10
                    '$user = Auth::user();' . "\n" .
652 10
                    'return [' . "\n" .
653 10
                    '    //[ "ability" => "create", "value" => $policy->create($user) ]' . "\n" .
654 10
                    '];'
655
                );
656
        }
657
        
658 10
        $printer = new \Nette\PhpGenerator\PsrPrinter;
659 10
        return $this->phpHeader() . $printer->printNamespace($namespace);
660
    }
661
662 10
    protected function processGraphql(): void
663
    {
664 10
        foreach ($this->type->getFields() as $field) {
665 10
            $directives = $field->astNode->directives;
666
            if (
667 10
                ($field->type instanceof ObjectType) ||
668 10
                ($field->type instanceof ListOfType) ||
669 10
                ($field->type instanceof UnionType) ||
670 10
                ($field->type instanceof NonNull && (
671 10
                    ($field->type->getWrappedType() instanceof ObjectType) ||
672 10
                    ($field->type->getWrappedType() instanceof ListOfType) ||
673 10
                    ($field->type->getWrappedType() instanceof UnionType)
674
                ))
675
            ) {
676
                // relationship
677 8
                $this->processRelationship($field, $directives);
678
            } else {
679 10
                $this->processFieldDirectives($field, $directives);
680
            }
681
        }
682
683
        /**
684
         * @var \GraphQL\Language\AST\NodeList|null
685
         */
686 10
        $directives = $this->type->astNode->directives;
687 10
        if ($directives) {
688 10
            $this->processDirectives($directives);
0 ignored issues
show
Bug introduced by
$directives of type GraphQL\Language\AST\DirectiveNode[] is incompatible with the type GraphQL\Language\AST\NodeList expected by parameter $directives of Modelarium\Laravel\Targe...or::processDirectives(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

688
            $this->processDirectives(/** @scrutinizer ignore-type */ $directives);
Loading history...
689
        }
690 10
    }
691
692 10
    public function getGenerateFilename(bool $base = true): string
693
    {
694 10
        return $this->getBasePath(self::$modelDir . '/' . ($base ? 'Base' : '') . $this->studlyName . '.php');
695
    }
696
697
    public static function setModelDir(string $dir): void
698
    {
699
        self::$modelDir = $dir;
700
    }
701
}
702