Completed
Push — master ( ba81e3...c30ee0 )
by George
05:42
created

Scaffold::addRoutes()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

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

168
            $this->variables['touches'] = self::arrayStringify(/** @scrutinizer ignore-type */ $this->model-touches);
Loading history...
169
        } else {
170
            $this->variables['touches'] = "[]";
171
        }
172
173
        if (!empty($this->model->casts)) {
174
            $this->variables['casts'] = self::arrayStringify($this->model->casts);
175
        } else {
176
            $this->variables['casts'] = "[]";
177
        }
178
        if (!empty($this->model->softDeletes)) {
179
            $this->variables['softDeletes'] = 'use SoftDeletes;';
180
        }
181
    }
182
183
    protected function addColumn($name, $type)
184
    {
185
        $column = new \stdClass(); // todo: make proper class for this
186
        $column->name = $name;
187
        $column->type = $type;
188
189
        $columnConfig = config("scaffold.columnTypes.$type");
190
191
        if (!empty($columnConfig['fillable'])) {
192
            $this->model->fillable[] = $name;
193
        }
194
195
        if (!empty($columnConfig['dates'])) {
196
            $this->model->dates[] = $name;
197
        }
198
199
        if (!empty($columnConfig['touches'])) {
200
            $this->model->touches[] = $name;
201
        }
202
203
        if (!empty($columnConfig['casts'])) {
204
            $this->model->casts[$name] = $columnConfig['casts'];
205
        }
206
        if (!empty($columnConfig['rules'])) {
207
            $this->rules[$name] = $columnConfig['rules'];
208
        }
209
210
        return $column;
211
    }
212
213
    public static function arrayStringify(array $array)
214
    {
215
        $export = str_replace(['array (', ')', '&#40', '&#41'], ['[', ']', '(', ')'], var_export($array, true));
216
        $export = preg_replace("/ => \n[^\S\n]*\[/m", ' => [', $export);
217
        $export = preg_replace("/ => \[\n[^\S\n]*\]/m", ' => []', $export);
218
        $export = preg_replace('/[\r\n]+/', "\n", $export);
219
        $export = preg_replace('/[ \t]+/', ' ', $export);
220
        return $export; //don't fear the trailing comma
221
    }
222
223
    public function build($stub)
224
    {
225
        return $this->template
226
            ->render(
227
                $this->getStub($stub),
228
                $this->variables
229
            );
230
    }
231
232
    public function __call($method, $arguments)
233
    {
234
        if (starts_with($method, 'build')) {
235
            if (str_contains($method, "Model")) {
236
                $path = app_path($this->model->name);
237
                if($this->files->exists($path)) {
238
                    $this->messages[] = "File {$this->model->name} already exists.";
239
                    return $this;
240
                }
241
            } elseif (str_contains($method, "ApiController")) {
242
                $path = app_path("Http/Controllers/Api/".$this->model->name."Controller");
243
                $this->files->makeDirectory(app_path("Http/Controllers/Api"), 0755, false, true);
244
                $this->files->makeDirectory(app_path("Http/Controllers/Web"), 0755, false, true);
245
            } elseif (str_contains($method, "Request")) {
246
                $path = app_path("Http/Requests/".$this->model->name."Request");
247
            } else {
248
                $path = app_path();
249
            }
250
251
            if($this->files->exists($path)) {
252
                $this->messages[] = "File {$this->model->name}Controller already exists.";
253
                return $this;
254
            }
255
            $target = substr($method, 5);
256
            $content = $this->build($target);
257
            $this->files->put("$path.php", $content);
258
        }
259
        return $this;
260
    }
261
262
    protected function getStub($stub)
263
    {
264
265
266
        return $this->files->get(app_path("Scaffold/stubs/$stub.stub"));
267
    }
268
269
    public function addRoutes()
270
    {
271
        $apiRoutes = $this->files->get(base_path("routes/api.php"));
272
        $webRoutes = $this->files->get(base_path("routes/web.php"));
273
        $uri = Str::plural(strtolower(preg_replace(
274
            '/([a-zA-Z])(?=[A-Z])/',
275
            '$1-', $this->model->name
276
        )));
277
        $apiRouteString = "\n\nRoute::apiResource('$uri', 'api/{$this->model->name}Controller');";
278
279
        $webRouteString = "\n\nRoute::resource('$uri', 'web/{$this->model->name}Controller')->only(['index', 'show']);";
280
281
        if (!str_contains($apiRoutes, $apiRouteString)) {
282
            $this->files->append(base_path("routes/api.php"), $apiRouteString);
283
        }
284
285
        if (!str_contains($webRoutes, $webRouteString)) {
286
            $this->files->append(base_path("routes/web.php"), $webRouteString);
287
        }
288
    }
289
290
291
292
}