Passed
Push — master ( bcac8b...ca1b68 )
by Reza
03:47
created

StubParser   A

Complexity

Total Complexity 41

Size/Duplication

Total Lines 293
Duplicated Lines 0 %

Importance

Changes 25
Bugs 1 Features 2
Metric Value
eloc 117
c 25
b 1
f 2
dl 0
loc 293
rs 9.1199
wmc 41

23 Methods

Rating   Name   Duplication   Size   Complexity  
A getModelName() 0 5 1
A parseSetPropertiesValue() 0 11 2
A parseProperties() 0 15 3
A getInputClassNamespace() 0 5 2
A setStore() 0 3 1
A parseActionInComponent() 0 14 4
A setLocaleTexts() 0 6 1
A setInputs() 0 2 1
A parseDataInBlade() 0 14 3
A parseInputsInBlade() 0 9 2
A setValidationRules() 0 3 1
A replaceModel() 0 17 1
A parseTitlesInBlade() 0 21 3
A setAuthType() 0 2 1
A uploadCodeParser() 0 16 2
A __construct() 0 4 1
A parseBlade() 0 15 1
A parseValidationRules() 0 10 2
A normalizeField() 0 9 2
A makeTab() 0 5 2
A getModelNameInLowerCase() 0 3 1
A normalizeInput() 0 9 3
A setFields() 0 2 1

How to fix   Complexity   

Complex Class

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

1
<?php
2
3
namespace EasyPanel\Parsers;
4
5
use Illuminate\Support\Facades\File;
6
use Illuminate\Support\Str;
7
use EasyPanel\Parsers\HTMLInputs\InputList;
8
use EasyPanel\Parsers\Fields\Field;
9
use EasyPanel\Parsers\HTMLInputs\BaseInput;
10
use EasyPanel\Services\LangManager;
11
12
class StubParser
13
{
14
    use Translatable;
15
16
    private $inputName;
17
    private $parsedModel;
18
19
    private $fields;
20
    private $inputs;
21
    private $validationRules;
22
    private $hasAuth;
23
    private $store;
24
25
    public function __construct($inputName, $parsedModel)
26
    {
27
        $this->inputName = $inputName;
28
        $this->parsedModel = $parsedModel;
29
    }
30
31
    public function setValidationRules($rules)
32
    {
33
        $this->validationRules = $rules;
34
    }
35
36
    public function setStore($store)
37
    {
38
        $this->store = $store;
39
    }
40
41
    public function setAuthType(bool $hasAuth){
42
        $this->hasAuth = $hasAuth;
43
    }
44
45
    public function setFields(array $fields){
46
        $this->fields = $fields;
47
    }
48
49
    public function setInputs(array $inputs){
50
        $this->inputs = $inputs;
51
    }
52
53
    public function replaceModel($stub)
54
    {
55
        $modelNamespace = $this->parsedModel;
56
        $modelName = $this->getModelName($modelNamespace);
57
58
        $array = [
59
            '{{ modelName }}' => ucfirst($modelName),
60
            '{{ modelNamespace }}' => $modelNamespace,
61
            '{{ uploadFile }}' => $this->uploadCodeParser(),
62
            '{{ model }}' => strtolower($modelName),
63
            '{{ properties }}' => $this->parseProperties(),
64
            '{{ rules }}' => $this->parseValidationRules(),
65
            '{{ fields }}' => $this->parseActionInComponent(),
66
            '{{ setProperties }}' => $this->parseSetPropertiesValue(),
67
        ];
68
69
        return str_replace(array_keys($array), array_values($array), $stub);
70
    }
71
72
    /**
73
     * Make Locale files
74
     */
75
    public function setLocaleTexts()
76
    {
77
        $this->addText(ucfirst($this->inputName));
78
        $this->addText(ucfirst(Str::plural($this->inputName)));
79
80
        $this->translate();
81
    }
82
83
    /**
84
     * Get model name from namespace
85
     */
86
    public function getModelName($modelNamespace)
87
    {
88
        $array = explode('\\', $modelNamespace);
89
90
        return end($array);
91
    }
92
93
    /**
94
     * Parse properties in Livewire component
95
     */
96
    public function parseProperties()
97
    {
98
        $fields = array_keys($this->inputs);
99
        $str = '';
100
101
        if(in_array($this->inputName, $fields)){
102
            $this->error("Model name must not equal to column names, fix it and rerun command with -f flag");
0 ignored issues
show
Bug introduced by
The method error() does not exist on EasyPanel\Parsers\StubParser. ( Ignorable by Annotation )

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

102
            $this->/** @scrutinizer ignore-call */ 
103
                   error("Model name must not equal to column names, fix it and rerun command with -f flag");

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...
103
            die;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
104
        }
105
106
        foreach ($fields as $field) {
107
            $str .= 'public $'.$field.";".$this->makeTab(1);
108
        }
109
110
        return $str;
111
    }
112
113
    /**
114
     * Parse Uploading Code
115
     */
116
    public function uploadCodeParser()
117
    {
118
        $filesInput = array_keys($this->inputs, 'file');
119
        $str = '';
120
        foreach ($filesInput as $file) {
121
            // We get store path which has been defined in crud's config file
122
            $storePath = $this->store[$file] ?? "{$file}";
123
124
            // We get property value then store file in $storePath
125
            // A PHP Code for upload as a string will be created here
126
            $str .= $this->makeTab(2).'if($this->getPropertyValue(\''.$file.'\') and is_object($this->'.$file.')) {'.$this->makeTab(3);
127
            $str .= '$this->'.$file.' = $this->getPropertyValue(\''.$file.'\')->store(\''.$storePath.'\');'.$this->makeTab(2);
128
            $str .= '}'.PHP_EOL;
129
        }
130
131
        return $str;
132
    }
133
134
    /**
135
     * parse values for mount method in Livewire
136
     */
137
    public function parseSetPropertiesValue()
138
    {
139
        $fields = array_keys($this->inputs);
140
        $str = '';
141
        $action = $this->inputName;
142
        foreach ($fields as $field) {
143
            $str .= '$this->'.$field.' = $this->'.$action.'->'.$field.';';
144
            $str .= $this->makeTab(2, end($fields) != $field);
145
        }
146
147
        return $str;
148
    }
149
150
    /**
151
     * Parse Validation rules
152
     */
153
    public function parseValidationRules()
154
    {
155
        $str = '';
156
157
        foreach ($this->validationRules as $key => $rule) {
158
            $str .= "'$key' => '$rule',";
159
            $str .= $this->makeTab(2, $key != array_key_last($this->validationRules));
160
        }
161
162
        return $str;
163
    }
164
165
    /**
166
     * Create an array of properties in Livewire component for actions
167
     */
168
    public function parseActionInComponent()
169
    {
170
        $str = '';
171
172
        foreach ($this->inputs as $key => $field) {
173
            $newLine = ($field != end($this->inputs) or $this->hasAuth);
174
            $str .=  "'$key' => " . '$this' . "->$key,".$this->makeTab(3, $newLine);
175
        }
176
177
        if($this->hasAuth){
178
            $str .= "'user_id' => auth()->id(),";
179
        }
180
181
        return $str;
182
    }
183
184
    /**
185
     * Create Blade from stub
186
     */
187
    public function parseBlade($stub){
188
        $modelName = $this->getModelName($this->parsedModel);
189
190
        $array = [
191
            '{{ model }}' => strtolower($modelName),
192
            '{{ modelName }}' => ucfirst($modelName),
193
            '{{ data }}' => $this->parseDataInBlade(),
194
            '{{ titles }}' => $this->parseTitlesInBlade(),
195
            '{{ inputs }}' => $this->parseInputsInBlade(),
196
            '{{ routeName }}' => crud(strtolower($modelName))->route,
197
        ];
198
199
        $this->setLocaleTexts();
200
201
        return str_replace(array_keys($array), array_values($array), $stub);
202
    }
203
204
    /**
205
     * Parse <td> tags for data
206
     */
207
    public function parseDataInBlade()
208
    {
209
        $fields = $this->fields;
210
        $str = '';
211
        $modelName = strtolower($this->getModelName($this->parsedModel));
212
        foreach ($fields as $key => $field) {
213
            $normalizedField = $this->normalizeField($field);
214
            $key = is_string($field) ? $field : $key;
215
            $str .= $normalizedField->setModel($modelName)->setKey($key)->renderData();
216
217
            $str .= $this->makeTab(1, false);
218
        }
219
220
        return $str;
221
    }
222
223
    /**
224
     * Parse <td> tags for head
225
     */
226
    public function parseTitlesInBlade()
227
    {
228
        $fields = $this->fields;
229
        $modelName = $this->getModelNameInLowerCase();
230
231
        $str = '';
232
        foreach ($fields as $key => $field) {
233
            // We will normalize the field value because most of users prefer to use simple mode
234
            // And they pass string and we will change it to a Field class object
235
            $normalizedField = $this->normalizeField($field);
236
237
            // Then we set the model and key to render the stub and get the string
238
            // The returned string concatenates with previous rendered fields
239
            $key = is_string($field) ? $field : $key;
240
            $str .= $normalizedField->setModel($modelName)->setKey($key)->renderTitle();
241
242
            // To show the rendered html tag more readable and cleaner in view we make some tab
243
            $str .= $this->makeTab(7, false);
244
        }
245
246
        return $str;
247
    }
248
249
    /**
250
     * Create inputs HTML
251
     */
252
    public function parseInputsInBlade()
253
    {
254
        $str = '';
255
        foreach ($this->inputs as $key => $type) {
256
            $inputObject = $this->normalizeInput($key, $type);
257
            $str .= $inputObject->setKey($key)->setAction($this->inputName)->render();
258
        }
259
260
        return $str;
261
    }
262
263
    /**
264
     * Tab Maker (Each tabs mean 4 space)
265
     */
266
    public function makeTab($count, $newLine = true){
267
        $count = $count * 4;
268
        $tabs = str_repeat(' ', $count);
269
270
        return $newLine ? "\n".$tabs : $tabs;
271
    }
272
273
    public function getInputClassNamespace($type)
274
    {
275
        $type = is_array($type) ? array_key_first($type) : $type;
276
277
        return InputList::get($type);
278
    }
279
280
    public function normalizeField($field)
281
    {
282
        if($field instanceof Field){
283
            return $field;
284
        }
285
286
        $title = str_replace('.', ' ', $field);
287
        $title = ucwords($title);
288
        return Field::title($title);
289
    }
290
291
    public function normalizeInput($key, $input){
292
        if ($input instanceof BaseInput){
293
            return $input;
294
        }
295
296
        $type = is_array($input) ? array_key_first($input) : $input;
297
        $title = ucwords($key);
298
299
        return $this->getInputClassNamespace($type)::label($title);
300
    }
301
302
    private function getModelNameInLowerCase()
303
    {
304
        return strtolower($this->getModelName($this->parsedModel));
305
    }
306
307
}
308