Passed
Push — master ( 7487a1...48aa9a )
by Richard
06:33
created

GraphQLInputGenerator   F

Complexity

Total Complexity 92

Size/Duplication

Total Lines 288
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 92
eloc 183
c 3
b 0
f 0
dl 0
loc 288
rs 2

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
A generate() 0 13 2
A rollback() 0 5 2
D sanitiseFieldTypes() 0 99 61
C prepareRelationship() 0 58 13
A generateRelation() 0 6 1
A generateRelations() 0 23 5
A generateSchema() 0 26 5
A getRelationFunctionText() 0 9 2

How to fix   Complexity   

Complex Class

Complex classes like GraphQLInputGenerator 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 GraphQLInputGenerator, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace PWWEB\Artomator\Generators\GraphQL;
4
5
use Illuminate\Support\Str;
6
use InfyOm\Generator\Generators\BaseGenerator;
7
use PWWEB\Artomator\Common\CommandData;
8
9
class GraphQLInputGenerator extends BaseGenerator
10
{
11
    /**
12
     * @var CommandData
13
     */
14
    private $commandData;
15
16
    /**
17
     * @var string
18
     */
19
    private $fileName;
20
21
    /**
22
     * @var string
23
     */
24
    private $fileContents;
25
26
    /**
27
     * @var string
28
     */
29
    private $templateData;
30
31
    public function __construct(CommandData $commandData)
32
    {
33
        $this->commandData = $commandData;
34
        $this->fileName = $commandData->config->pathGraphQL;
35
        $this->fileContents = file_get_contents($this->fileName);
36
        $this->templateData = get_artomator_template('graphql.inputs');
37
        $this->templateData = fill_template($this->commandData->dynamicVars, $this->templateData);
38
        $this->templateData = fill_template($this->generateSchema(), $this->templateData);
39
    }
40
41
    public function generate()
42
    {
43
        if (true === Str::contains($this->fileContents, $this->templateData)) {
44
            $this->commandData->commandObj->info('GraphQL Inputs '.$this->commandData->config->mHumanPlural.' already exist; Skipping');
45
46
            return;
47
        }
48
49
        $this->fileContents .= $this->templateData;
50
51
        file_put_contents($this->fileName, $this->fileContents);
52
53
        $this->commandData->commandComment("\nGraphQL Inputs created");
54
    }
55
56
    public function rollback()
57
    {
58
        if (Str::contains($this->fileContents, $this->templateData)) {
59
            file_put_contents($this->fileName, str_replace($this->templateData, '', $this->fileContents));
60
            $this->commandData->commandComment('GraphQL Inputs deleted');
61
        }
62
    }
63
64
    private function sanitiseFieldTypes(string $fieldType)
65
    {
66
        $needle = '/\(.+\)?/g';
67
        $replace = '';
68
        $fieldType = preg_replace($needle, $replace, $fieldType);
69
        // There are 5 basic scalar types + 2 lighthouse ones (Date and DateTime);
70
        switch ($fieldType) {
71
            case 'bigIncrements':
72
            case 'bigInteger':
73
            case 'binary':
74
            case 'increments':
75
            case 'integer':
76
            case 'mediumIncrements':
77
            case 'mediumInteger':
78
            case 'smallIncrements':
79
            case 'smallInteger':
80
            case 'tinyIncrements':
81
            case 'tinyInteger':
82
            case 'unsignedBigInteger':
83
            case 'unsignedInteger':
84
            case 'unsignedMediumInteger':
85
            case 'unsignedSmallInteger':
86
            case 'unsignedTinyInteger':
87
            case 'year':
88
                return 'Int';
89
90
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
91
92
            case 'unsignedDecimal':
93
            case 'point':
94
            case 'polygon':
95
            case 'multiPoint':
96
            case 'multiPolygon':
97
            case 'float':
98
            case 'decimal':
99
            case 'double':
100
                return 'Float';
101
102
                break;
103
104
            case 'uuid':
105
            case 'string':
106
            case 'text':
107
            case 'rememberToken':
108
            case 'mediumText':
109
            case 'multiLineString':
110
            case 'ipAddress':
111
            case 'json':
112
            case 'jsonb':
113
            case 'lineString':
114
            case 'longText':
115
            case 'macAddress':
116
            case 'char':
117
                return 'String';
118
119
                break;
120
121
            case 'boolean':
122
                return 'Boolean';
123
124
                break;
125
126
            case 'foreignId':
127
                return 'ID';
128
129
                break;
130
131
            case 'time':
132
            case 'timeTz':
133
            case 'timestamp':
134
            case 'timestampTz':
135
            case 'timestamps':
136
            case 'timestampsTz':
137
            case 'softDeletes':
138
            case 'softDeletesTz':
139
            case 'nullableTimestamps':
140
            case 'dateTime':
141
            case 'dateTimeTz':
142
                return 'DateTime';
143
144
                break;
145
146
            case 'date':
147
                return 'Date';
148
149
                break;
150
151
            case 'set':
152
            case 'nullableMorphs':
153
            case 'nullableUuidMorphs':
154
            case 'morphs':
155
            case 'uuidMorphs':
156
            case 'geometry':
157
            case 'geometryCollection':
158
            case 'enum':
159
            default:
160
                return ucfirst($fieldType);
161
162
                break;
163
        }
164
    }
165
166
    private function generateSchema()
167
    {
168
        $schema = [];
169
        foreach ($this->commandData->fields as $field) {
170
            if ($field->isFillable) {
171
                if ('foreignId' === $field->fieldType) {
172
                    continue;
173
                } else {
174
                    $field_type = $this->sanitiseFieldTypes($field->fieldType);
175
                }
176
177
                $field_type .= (Str::contains($field->validations, 'required') ? '!' : '');
178
179
                $schema[] = $field->name.': '.$field_type;
180
            }
181
        }
182
        $schema = array_merge($schema, $this->generateRelations());
183
        $schema = implode(infy_nl_tab(1, 1), $schema);
184
        $create_schema = str_replace('$TYPE$', 'Create', $schema);
185
        $update_schema = str_replace('$TYPE$', 'Update', $schema);
186
        $upsert_schema = str_replace('$TYPE$', 'Upsert', $schema);
187
188
        return [
189
            '$CREATE_SCHEMA$' => $create_schema,
190
            '$UPDATE_SCHEMA$' => str_replace('!', '', $update_schema),
191
            '$UPSERT_SCHEMA$' => str_replace('!', '', $upsert_schema),
192
        ];
193
    }
194
195
    private function generateRelations()
196
    {
197
        $relations = [];
198
199
        $count = 1;
200
        $fieldsArr = [];
201
        foreach ($this->commandData->relations as $relation) {
202
            $field = (isset($relation->inputs[0])) ? $relation->inputs[0] : null;
203
204
            $relationShipText = $field;
205
            if (in_array($field, $fieldsArr)) {
206
                $relationShipText = $relationShipText.'_'.$count;
207
                $count++;
208
            }
209
210
            $relationText = $this->getRelationFunctionText($relation, $relationShipText);
211
            if (false === empty($relationText)) {
212
                $fieldsArr[] = $field;
213
                $relations[] = $relationText;
214
            }
215
        }
216
217
        return $relations;
218
    }
219
220
    protected function getRelationFunctionText($relationship, $relationText = null)
221
    {
222
        extract($this->prepareRelationship($relationship, $relationText));
223
224
        if (false === empty($functionName)) {
225
            return $this->generateRelation($functionName, $template);
226
        }
227
228
        return '';
229
    }
230
231
    private function generateRelation($functionName, $template)
232
    {
233
        $template = str_replace('$FUNCTION_NAME$', $functionName, $template);
234
        $template = str_replace('$RELATION_GRAPHQL_NAME$', ucfirst(Str::singular($functionName)), $template);
235
236
        return $template;
237
    }
238
239
    protected function prepareRelationship($relationship, $relationText = null)
240
    {
241
        $singularRelation = (false === empty($relationship->relationName)) ? $relationship->relationName : Str::camel(Str::singular($relationText));
242
        $pluralRelation = (false === empty($relationship->relationName)) ? $relationship->relationName : Str::camel(Str::plural($relationText));
243
244
        switch ($relationship->type) {
245
            case '1t1':
246
                $functionName = $singularRelation;
247
                $template = '$FUNCTION_NAME$: $TYPE$$RELATION_GRAPHQL_NAME$';
248
                $templateFile = '';
249
250
                break;
251
            case '1tm':
252
                $functionName = $pluralRelation;
253
                $template = '$FUNCTION_NAME$: $TYPE$$RELATION_GRAPHQL_NAME$HasMany';
254
                $templateFile = 'hasMany';
255
256
                break;
257
            case 'mt1':
258
                if (false === empty($relationship->relationName)) {
259
                    $singularRelation = $relationship->relationName;
260
                } elseif (isset($relationship->inputs[1])) {
261
                    $singularRelation = Str::camel(str_replace('_id', '', strtolower($relationship->inputs[1])));
262
                }
263
                $functionName = $singularRelation;
264
                $template = '$FUNCTION_NAME$: $TYPE$$RELATION_GRAPHQL_NAME$BelongsTo';
265
                $templateFile = 'belongsTo';
266
267
                break;
268
            case 'mtm':
269
                $functionName = $pluralRelation;
270
                $template = '$FUNCTION_NAME$: $TYPE$$RELATION_GRAPHQL_NAME$BelongsToMany';
271
                $templateFile = 'belongsToMany';
272
273
                break;
274
            case 'hmt':
275
                $functionName = $pluralRelation;
276
                $template = '';
277
                $templateFile = '';
278
279
                break;
280
            default:
281
                $functionName = '';
282
                $template = '';
283
                $templateFile = '';
284
285
                break;
286
        }
287
        if (false === empty($templateFile)) {
288
            $templateFile = get_artomator_template('graphql.relations.'.$templateFile);
289
            $templateFile = str_replace('$RELATION_GRAPHQL_NAME$', ucfirst(Str::singular($functionName)), $templateFile);
290
291
            if (false === Str::contains($this->fileContents, $templateFile) && false === Str::contains($this->templateData, $templateFile)) {
292
                $this->templateData .= $templateFile;
293
            }
294
        }
295
296
        return compact('functionName', 'template');
297
    }
298
}
299