Completed
Pull Request — master (#66)
by
unknown
01:44
created

ResourceCommand::hasSoftDeletes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php namespace Wn\Generators\Commands;
2
3
4
use InvalidArgumentException;
5
6
class ResourceCommand extends BaseCommand {
7
8
    protected $signature = 'wn:resource
9
        {name : Name of the resource.}
10
        {fields : fields description.}
11
        {--has-many= : hasMany relationships.}
12
        {--has-one= : hasOne relationships.}
13
        {--belongs-to= : belongsTo relationships.}
14
        {--belongs-to-many= : belongsToMany relationships.}
15
        {--has-many-through= : hasManyThrough relationships.}
16
        {--morph-to= : morphTo relationships.}
17
        {--morph-many= : morphMany relationships.}
18
        {--morph-to-many= : morphToMany relationships.}
19
        {--morphed-by-many= : morphedByMany relationships.}
20
        {--migration-file= : the migration file name.}
21
        {--add= : specifies additional columns like timestamps, softDeletes, rememberToken and nullableTimestamps.}
22
        {--path=app : where to store the model file.}
23
        {--routes= : where to store the routes.}
24
        {--no-routes : do not add routes.}
25
        {--controller= : where to store the controllers file.}
26
        {--no-controller : do not generate controllers.}
27
        {--parsed : tells the command that arguments have been already parsed. To use when calling the command from an other command and passing the parsed arguments and options}
28
        {--force= : override the existing files}
29
        {--laravel= : Use Laravel style route definitions}
30
    ';
31
32
    protected $description = 'Generates a model, migration, controller and routes for RESTful resource';
33
34
    protected $fields;
35
36
    public function handle()
37
    {
38
        $this->parseFields();
39
40
        $resourceName = $this->argument('name');
41
        $modelName = ucwords(camel_case($resourceName));
0 ignored issues
show
Bug introduced by
It seems like $resourceName defined by $this->argument('name') on line 40 can also be of type array or null; however, camel_case() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
42
        $tableName = snake_case(str_plural($resourceName));
0 ignored issues
show
Bug introduced by
It seems like $resourceName defined by $this->argument('name') on line 40 can also be of type array or null; however, str_plural() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
43
44
        // generating the model
45
        $this->call('wn:model', [
46
            'name' => $modelName,
47
            '--fillable' => $this->fieldsHavingTag('fillable'),
48
            '--dates' => $this->fieldsHavingTag('date'),
49
            '--has-many' => $this->option('has-many'),
50
            '--has-one' => $this->option('has-one'),
51
            '--belongs-to' => $this->option('belongs-to'),
52
            '--belongs-to-many' => $this->option('belongs-to-many'),
53
            '--has-many-through' => $this->option('has-many-through'),
54
            '--morph-to' => $this->option('morph-to'),
55
            '--morph-many' => $this->option('morph-many'),
56
            '--morph-to-many' => $this->option('morph-to-many'),
57
            '--morphed-by-many' => $this->option('morphed-by-many'),
58
            '--rules' => $this->rules(),
59
            '--path' => $this->option('path'),
60
            '--force' => $this->option('force'),
61
            '--timestamps' => $this->hasTimestamps() ? 'true' : 'false',
62
            '--soft-deletes' => $this->hasSoftDeletes() ? 'true' : 'false',
63
            '--parsed' => true
64
        ]);
65
66
        // generating the migration
67
        $this->call('wn:migration', [
68
            'table' => $tableName,
69
            '--schema' => $this->schema(),
70
            '--keys' => $this->migrationKeys(),
71
            '--file' => $this->option('migration-file'),
72
            '--force' => $this->option('force'),
73
            '--add' => $this->option('add'),
74
            '--parsed' => true
75
        ]);
76
77
        if (! $this->option('no-controller')) {
78
            // generating REST actions trait if doesn't exist
79
            if(! $this->fs->exists('./app/Http/Controllers/RESTActions.php')){
80
                $this->call('wn:controller:rest-actions');
81
            }
82
83
            // generating the controller and routes
84
            $controllerOptions = [
85
                'model' => $modelName,
86
                '--force' => $this->option('force'),
87
                '--no-routes' => $this->option('no-routes'),
88
            ];
89
            if ($this->option('laravel')) {
90
                $controllerOptions['--laravel'] = true;
91
            }
92
            if ($this->option('routes')) {
93
                $controllerOptions['--routes'] = $this->option('routes');
94
            }
95
            if ($this->option('controller')) {
96
                $controllerOptions['--path'] = $this->option('controller');
97
            }
98
            $this->call('wn:controller', $controllerOptions);
99
        }
100
101
        // generating model factory
102
        $this->call('wn:factory', [
103
            'model' => $this->getNamespace().'\\'.$modelName,
104
            '--file' => './database/factories/'.str_plural($modelName).'.php',
105
            '--fields' => $this->factoryFields(),
106
            '--force' => $this->option('force'),
107
            '--parsed' => true
108
        ]);
109
110
        // generating database seeder
111
        // $this->call('wn:seeder', [
112
        //     'model' => 'App\\' . $modelName
113
        // ]);
114
115
    }
116
117
    protected function parseFields()
118
    {
119
        $fields = $this->argument('fields');
120
        if($this->option('parsed')){
121
            $this->fields = $fields;
122
        } else {
123
            if(! $fields){
124
                $this->fields = [];
125
            } else {
126
                $this->fields = $this->getArgumentParser('fields')
127
                    ->parse($fields);
128
            }
129
            $this->fields = array_merge($this->fields, array_map(function($name) {
130
                $return = [
131
                    'name' => $name['name'],
132
                    'schema' => [],
133
                    'rules' => '',
134
                    'tags' => ['fillable', 'key'],
135
                    'factory' => ''
136
                ];
137
138
                if ($name['type'] == 'morphTo') {
139
                    if (substr($name['name'], -3) == "_id") {
140
                        $return['schema'] = [
141
                            ['name' => 'integer', 'args' => []],
142
                            ['name' => 'unsigned', 'args' => []]
143
                        ];
144
                        $return['rules'] = 'numeric';
145
                        $return['factory'] = 'key';
146
                    } else {
147
                        $return['schema'] = [
148
                            ['name' => 'string', 'args' => ['50']]
149
                        ];
150
                    }
151
                    if ($name['nullable']) {
152
                        $return['schema'][] = ['name' => 'nullable', 'args' => []];
153
                    } else {
154
                        $return['rules'] = 'required'.(!empty($return['rules'])?'|'.$return['rules']:'');
155
                    }
156
                } else {
157
                    $return['schema'] = [
158
                        ['name' => 'integer', 'args' => []],
159
                        ['name' => 'unsigned', 'args' => []]
160
                    ];
161
                    $return['rules'] = 'required|numeric';
162
                    $return['factory'] = 'key';
163
                }
164
165
                return $return;
166
            }, $this->foreignKeys()));
167
        }
168
169
    }
170
171
    protected function fieldsHavingTag($tag)
172
    {
173
        return array_map(function($field){
174
            return $field['name'];
175
        }, array_filter($this->fields, function($field) use($tag){
176
            return in_array($tag, $field['tags']);
177
        }));
178
    }
179
180 View Code Duplication
    protected function rules()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
181
    {
182
        return array_map(function($field){
183
            return [
184
                'name' => $field['name'],
185
                'rule' => $field['rules']
186
            ];
187
        }, array_filter($this->fields, function($field){
188
            return !empty($field['rules']);
189
        }));
190
    }
191
192
    protected function schema()
193
    {
194
        return array_map(function($field){
195
            return array_merge([[
196
                'name' => $field['name'],
197
                'args' => []
198
            ]], $field['schema']);
199
        }, $this->fields);
200
    }
201
202
    protected function getBaseModel($path) {
203
        $index = strrpos($path, "\\");
204
        if($index) {
205
            return substr($path, $index + 1);
206
        }
207
        return $path;
208
    }
209
210
    protected function foreignKeys($withMorph = true)
211
    {
212
        $belongsTo = $this->option('belongs-to');
213
        $morphTo = $this->option('morph-to');
214
215
        if(! $belongsTo && (! $withMorph || ! $morphTo)) {
216
            return [];
217
        }
218
219
        $belongsTo = $belongsTo ? $this->getArgumentParser('relations')->parse($belongsTo) : [];
220
221
        $belongsTo = array_map(function($relation){
222
            return array("model" => camel_case(str_singular($this->getBaseModel($relation['model'] ? $relation['model'] : $relation['name']))), "name" => snake_case(str_singular($this->getBaseModel($relation['name']))) . '_id', "type" => "belongsTo");
223
        }, $belongsTo);
224
225
        if ($withMorph) {
226
            $morphTo = $morphTo ? $this->getArgumentParser('relations-morphTo')->parse($morphTo) : [];
227
            $morphTo = array_map(function($relation){
228
                $name = snake_case(str_singular($relation['name']));
229
                return array(array("name" => $name . '_id', "type" => "morphTo", "nullable" => $relation['nullable']), array("name" => $name . '_type', "type" => "morphTo", "nullable" => $relation['nullable']));
230
            }, $morphTo);
231
232
            // $morphed = [];
233
            // array_walk_recursive($morphTo, function($a) use (&$morphed) { $morphed[] = $a; });
234
            $morphed = !empty($morphTo) ? call_user_func_array('array_merge', $morphTo) : array();
235
236
            return array_merge($belongsTo, $morphed);
237
        }
238
239
        return $belongsTo;
240
    }
241
242
    protected function migrationKeys() {
243
        return array_map(function($name) {
244
            return [
245
                'name' => snake_case($name['name']),
246
                'column' => '',
247
                'table' => snake_case(str_plural($name['model'])),
248
                'on_delete' => '',
249
                'on_update' => ''
250
            ];
251
        }, $this->foreignKeys(false));
252
    }
253
254 View Code Duplication
    protected function factoryFields()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
255
    {
256
        return array_map(function($field){
257
            return [
258
                'name' => $field['name'],
259
                'type' => $field['factory']
260
            ];
261
        }, array_filter($this->fields, function($field){
262
            return isset($field['factory']) && $field['factory'];
263
        }));
264
    }
265
266
    protected function hasTimestamps()
267
    {
268
        $additionals = explode(',', $this->option('add'));
269
        return in_array('nullableTimestamps', $additionals)
270
            || in_array('timestamps', $additionals)
271
            || in_array('timestampsTz', $additionals);
272
    }
273
274
    protected function hasSoftDeletes()
275
    {
276
        $additionals = explode(',', $this->option('add'));
277
        return in_array('softDeletes', $additionals);
278
    }
279
280
}
281