Completed
Pull Request — master (#5)
by George
03:37
created

Scaffold::resolve()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
namespace Ghaskell\Scaffold;
4
5
use Ghaskell\Scaffold\Facades\Vibro;
6
use Illuminate\Database\Eloquent\Collection;
7
use Illuminate\Filesystem\Filesystem;
8
use Illuminate\Support\Facades\App;
9
use Illuminate\Support\Str;
10
11
class Scaffold
12
{
13
    protected $model;
14
    protected $rules;
15
    protected $migration;
16
    protected $columns;
17
    protected $variables;
18
    protected $migrationFileName;
19
    protected $template;
20
    protected $blade;
21
22
    public $messages = [];
23
    public $created = [];
24
25
26
27
    public function __construct($migration)
28
    {
29
        $this->model = new \stdClass();
30
        $this->migration = $migration;
31
        $this->files = new Filesystem();
0 ignored issues
show
Bug Best Practice introduced by
The property files does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
32
        $this->requireFiles();
33
        $migrationInstance = $this->resolve(
34
            $name = $this->getMigrationName($this->migration)
35
        );
36
        $this->migration = $migrationInstance;
37
38
        $reflector = new \ReflectionClass($migrationInstance);
39
        $this->migrationFileName = $reflector->getFileName();
40
41
        $this->migration = $this->files->get($this->migrationFileName);
42
        $this->model->name = $this->parseModelNameFromMigration();
43
        $this->columns = $this->parseColumnsFromMigration();
44
        $this->setTemplateVariables();
45
46
47
//        GenerateModel::make($migrationInstance)->save();
48
//        GenerateRequest::make($migrationInstance)->save();
49
//        GenerateApiController::make($migrationInstance)->save();
50
    }
51
52
    public static function create($migration)
53
    {
54
        return new Scaffold($migration);
55
    }
56
57
58
    /**
59
     * Resolve a migration instance from a file.
60
     *
61
     * @param  string  $file
62
     * @return object
63
     */
64
    public function resolve($file)
65
    {
66
        $class = Str::studly(implode('_', array_slice(explode('_', $file), 4)));
67
68
        return new $class;
69
    }
70
71
    /**
72
     * Get the name of the migration.
73
     *
74
     * @param  string  $path
75
     * @return string
76
     */
77
    public function getMigrationName($path)
78
    {
79
        return str_replace('.php', '', basename($path));
80
    }
81
82
    /**
83
     * Get all of the migration files in a given path.
84
     *
85
     * @param  string|array  $paths
86
     * @return array
87
     */
88
    public function getMigrationFiles($paths)
89
    {
90
        return Collection::make($paths)->flatMap(function ($path) {
91
            return $this->files->glob($path.'/*_*.php');
92
        })->filter()->sortBy(function ($file) {
93
            return $this->getMigrationName($file);
94
        })->values()->keyBy(function ($file) {
95
            return $this->getMigrationName($file);
96
        })->all();
97
    }
98
99
    /**
100
     * Require in all the migration files in a given path.
101
     *
102
     * @return void
103
     */
104
    public function requireFiles()
105
    {
106
        $files = new Filesystem;
107
        $files->requireOnce($this->migration);
108
    }
109
110
    private function parseModelNameFromMigration()
111
    {
112
        preg_match("/(?<=create\(\')(.*)(?=\')/", $this->migration, $result);
113
        return str_singular(studly_case($result[0]));
114
    }
115
116
    private function parseColumnsFromMigration()
117
    {
118
        preg_match_all('/(?<=\$table\-\>)(.*)(?=\;)/', $this->migration, $lines);
119
        $columns = [];
120
        foreach ($lines[0] as $line) {
121
            preg_match("([^\(]+)", $line, $type);
122
            switch ($type[0]) {
123
                case 'timestamps':
124
                    $columns[] = $this->addColumn('created_at', 'timestamp');
125
                    $columns[] = $this->addColumn('updated_at', 'timestamp');
126
                    break;
127
                case 'softDeletes':
128
                    $this->model->softDeletes = true;
129
                    $columns[] = $this->addColumn('deleted_at', 'timestamp');
130
                    break;
131
                default:
132
                    preg_match("/['](.*?)[']/", $line, $name);
133
                    $columns[] = $this->addColumn($name[1], $type[0]);
134
            }
135
        }
136
        return $columns;
137
    }
138
139
    private function setTemplateVariables()
140
    {
141
        $this->variables['modelName'] = $this->model->name;
142
143
        $this->variables['studlyName'] = Str::studly($this->model->name);
144
        $this->variables['studlyNamePlural'] = Str::plural(Str::studly($this->model->name));
145
146
        $this->variables['modelVariable'] = "$" . Str::camel($this->model->name);
147
        $this->variables['modelVariablePlural'] = "$" . Str::plural(Str::camel($this->model->name));
148
149
        $this->variables['modelNameLower'] = Str::camel($this->model->name);
150
        $this->variables['modelNameLowerPlural'] = Str::plural(Str::camel($this->model->name));
151
152
153
        if ($this->rules) {
154
            $this->variables['rules'] = self::arrayStringify($this->rules);
155
        } else {
156
            $this->variables['rules'] = "[]";
157
        }
158
159
        if (!empty($this->model->fillable)) {
160
            $this->variables['fillable'] = self::arrayStringify($this->model->fillable);
161
        } else {
162
            $this->variables['fillable'] = "[]";
163
        }
164
165
        if (!empty($this->model->dates)) {
166
            $this->variables['dates'] = self::arrayStringify($this->model->dates);
167
        } else {
168
            $this->variables['dates'] = "[]";
169
        }
170
171
        if (!empty($this->model->touches)) {
172
            $this->variables['touches'] = self::arrayStringify($this->model-touches);
0 ignored issues
show
Bug introduced by
The constant Ghaskell\Scaffold\touches was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
$this->model - Ghaskell\Scaffold\touches of type integer is incompatible with the type array expected by parameter $array of Ghaskell\Scaffold\Scaffold::arrayStringify(). ( Ignorable by Annotation )

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

172
            $this->variables['touches'] = self::arrayStringify(/** @scrutinizer ignore-type */ $this->model-touches);
Loading history...
173
        } else {
174
            $this->variables['touches'] = "[]";
175
        }
176
177
        if (!empty($this->model->casts)) {
178
            $this->variables['casts'] = self::arrayStringify($this->model->casts);
179
        } else {
180
            $this->variables['casts'] = "[]";
181
        }
182
        if (!empty($this->model->softDeletes)) {
183
            $this->variables['softDeletes'] = 'use SoftDeletes;';
184
        }
185
    }
186
187
    protected function addColumn($name, $type)
188
    {
189
        $column = new \stdClass(); // todo: make proper class for this
190
        $column->name = $name;
191
        $column->type = $type;
192
193
        $columnConfig = config("scaffold.columnTypes.$type");
194
195
        if (!empty($columnConfig['fillable'])) {
196
            $this->model->fillable[] = $name;
197
        }
198
199
        if (!empty($columnConfig['dates'])) {
200
            $this->model->dates[] = $name;
201
        }
202
203
        if (!empty($columnConfig['touches'])) {
204
            $this->model->touches[] = $name;
205
        }
206
207
        if (!empty($columnConfig['casts'])) {
208
            $this->model->casts[$name] = $columnConfig['casts'];
209
        }
210
        if (!empty($columnConfig['rules'])) {
211
            $this->rules[$name] = $columnConfig['rules'];
212
        }
213
214
        return $column;
215
    }
216
217
    public static function arrayStringify(array $array)
218
    {
219
        $export = str_replace(['array (', ')', '&#40', '&#41'], ['[', ']', '(', ')'], var_export($array, true));
220
        $export = preg_replace("/ => \n[^\S\n]*\[/m", ' => [', $export);
221
        $export = preg_replace("/ => \[\n[^\S\n]*\]/m", ' => []', $export);
222
        $export = preg_replace('/[\r\n]+/', "\n", $export);
223
        $export = preg_replace('/[ \t]+/', ' ', $export);
224
        return $export; //don't fear the trailing comma
225
    }
226
227
    public function build($stub)
228
    {
229
        $path = $this->getStubPath($stub);
230
        return Vibro::compileFile($path, $this->variables );
0 ignored issues
show
Bug introduced by
The method compileFile() does not exist on Ghaskell\Scaffold\Facades\Vibro. Since you implemented __callStatic, consider adding a @method annotation. ( Ignorable by Annotation )

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

230
        return Vibro::/** @scrutinizer ignore-call */ compileFile($path, $this->variables );
Loading history...
231
    }
232
233
    public function __call($method, $arguments)
234
    {
235
        if (starts_with($method, 'build')) {
236
            $target = Str::camel(str_replace('build', '', $method));
237
            $config = config("scaffold.files.$target");
238
            $pathPrefix = $config['path'];
239
            $fileName = Vibro::compileFileName($config['fileNamePattern'], $this->variables);
0 ignored issues
show
Bug introduced by
The method compileFileName() does not exist on Ghaskell\Scaffold\Facades\Vibro. Since you implemented __callStatic, consider adding a @method annotation. ( Ignorable by Annotation )

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

239
            /** @scrutinizer ignore-call */ 
240
            $fileName = Vibro::compileFileName($config['fileNamePattern'], $this->variables);
Loading history...
240
241
            $path = app_path("$pathPrefix/$fileName");
242
                if($this->files->exists("$path")) {
243
                    $this->messages[] = "File '$path' exists and was not overwritten.";
244
                    return $this;
245
                }
246
247
            if(!$this->files->isDirectory(app_path($pathPrefix))) {
248
                $this->files->makeDirectory(app_path("$pathPrefix"));
249
            }
250
251
            $content = $this->build($target);
252
                if($content) {
253
                    $this->files->put("$path", $content);
254
                    $this->created[] = $path;
255
                } else {
256
                    $this->messages[] = "File stub $target not found.";
257
                }
258
259
                return $this;
260
        }
261
    }
262
263
    protected function getStub($stub)
264
    {
265
        $stub = Str::camel($stub);
266
        if($this->files->exists(app_path("Scaffold/stubs/$stub.stub"))) {
267
                return $this->files->get(app_path("Scaffold/stubs/$stub.stub"));
268
        } else {
269
            return false;
270
        }
271
    }
272
273
    protected function getStubPath($stub)
274
    {
275
        $stub = Str::camel($stub);
276
        return app_path("Scaffold/stubs/$stub.stub");
277
    }
278
279
    public function addRoutes()
280
    {
281
        foreach(config('scaffold.routes') as $key => $route)
282
        {
283
            $namespace = Str::studly($key);
284
            $routeContent = $this->files->get($route['fileName']);
285
            $uri = Str::plural(strtolower(preg_replace(
286
                '/([a-zA-Z])(?=[A-Z])/',
287
                '$1-', $this->model->name
288
            )));
289
            if($key = 'web') {
0 ignored issues
show
Unused Code introduced by
The assignment to $key is dead and can be removed.
Loading history...
290
                $routeString = "\n\nRoute::resource('$uri', '$namespace\\{$this->model->name}Controller')->only(['index', 'show']);";
291
            } else {
292
                $routeString = "\n\nRoute::apiResource('$uri', '$namespace\\{$this->model->name}Controller');";
293
            }
294
295
            if (!str_contains($routeContent, $routeString)) {
296
                $this->files->append($route['fileName'], $routeString);
297
            }
298
        }
299
        return $this;
300
    }
301
302
303
304
}