3
3
namespace Blueprint \Commands ;
4
4
5
5
use Blueprint \Blueprint ;
6
- use Blueprint \EnumType ;
7
- use Doctrine \DBAL \Types \Type ;
6
+ use Blueprint \Tracer ;
8
7
use Illuminate \Console \Command ;
9
- use Illuminate \Database \Eloquent \Model ;
10
8
use Illuminate \Filesystem \Filesystem ;
11
9
use Illuminate \Support \Str ;
12
10
@@ -29,15 +27,19 @@ class TraceCommand extends Command
29
27
/** @var Filesystem $files */
30
28
protected $ files ;
31
29
30
+ /** @var Tracer */
31
+ private $ tracer ;
32
+
32
33
/**
33
34
* @param Filesystem $files
34
- * @param \Illuminate\Contracts\View\Factory $view
35
+ * @param Tracer $tracer
35
36
*/
36
- public function __construct (Filesystem $ files )
37
+ public function __construct (Filesystem $ files, Tracer $ tracer )
37
38
{
38
39
parent ::__construct ();
39
40
40
41
$ this ->files = $ files ;
42
+ $ this ->tracer = $ tracer ;
41
43
}
42
44
43
45
/**
@@ -47,236 +49,15 @@ public function __construct(Filesystem $files)
47
49
*/
48
50
public function handle ()
49
51
{
50
- $ definitions = [];
51
- foreach ($ this ->appClasses () as $ class ) {
52
- $ model = $ this ->loadModel ($ class );
53
- if (is_null ($ model )) {
54
- continue ;
55
- }
56
-
57
- $ definitions [$ this ->relativeClassName ($ model )] = $ this ->translateColumns ($ this ->mapColumns ($ this ->extractColumns ($ model )));
58
- }
52
+ $ blueprint = resolve (Blueprint::class);
53
+ $ definitions = $ this ->tracer ->execute ($ blueprint , $ this ->files );
59
54
60
55
if (empty ($ definitions )) {
61
56
$ this ->error ('No models found ' );
62
-
63
- return ;
64
- }
65
-
66
- $ blueprint = new Blueprint ();
67
-
68
- $ cache = [];
69
- if ($ this ->files ->exists ('.blueprint ' )) {
70
- $ cache = $ blueprint ->parse ($ this ->files ->get ('.blueprint ' ));
71
- }
72
-
73
- $ cache ['models ' ] = $ definitions ;
74
-
75
- $ this ->files ->put ('.blueprint ' , $ blueprint ->dump ($ cache ));
76
-
77
- $ this ->info ('Traced ' . count ($ definitions ) . ' ' . Str::plural ('model ' , count ($ definitions )));
78
- }
79
-
80
- private function appClasses ()
81
- {
82
- $ dir = Blueprint::appPath ();
83
-
84
- if (config ('blueprint.models_namespace ' )) {
85
- $ dir .= '/ ' . str_replace ('\\' , '/ ' , config ('blueprint.models_namespace ' ));
86
- }
87
-
88
- if (!$ this ->files ->exists ($ dir )) {
89
- return [];
90
- }
91
-
92
- return array_map (function (\SplFIleInfo $ file ) {
93
- return str_replace (
94
- [Blueprint::appPath () . '/ ' , '/ ' ],
95
- [config ('blueprint.namespace ' ) . '\\' , '\\' ],
96
- $ file ->getPath () . '/ ' . $ file ->getBasename ('.php ' )
97
- );
98
- }, $ this ->files ->allFiles ($ dir ));
99
- }
100
-
101
- private function loadModel (string $ class )
102
- {
103
- if (!class_exists ($ class )) {
104
- return null ;
105
- }
106
-
107
- $ reflectionClass = new \ReflectionClass ($ class );
108
- if (
109
- !$ reflectionClass ->isSubclassOf (\Illuminate \Database \Eloquent \Model::class) ||
110
- (class_exists ('Jenssegers\Mongodb\Eloquent\Model ' ) &&
111
- $ reflectionClass ->isSubclassOf ('Jenssegers\Mongodb\Eloquent\Model ' ))
112
- ) {
113
- return null ;
114
- }
115
-
116
- return $ this ->laravel ->make ($ class );
117
- }
118
-
119
- private function extractColumns (Model $ model )
120
- {
121
- $ table = $ model ->getConnection ()->getTablePrefix () . $ model ->getTable ();
122
- $ schema = $ model ->getConnection ()->getDoctrineSchemaManager ();
123
-
124
- if (!Type::hasType ('enum ' )) {
125
- Type::addType ('enum ' , EnumType::class);
126
- $ databasePlatform = $ schema ->getDatabasePlatform ();
127
- $ databasePlatform ->registerDoctrineTypeMapping ('enum ' , 'enum ' );
128
- }
129
-
130
- $ database = null ;
131
- if (strpos ($ table , '. ' )) {
132
- [$ database , $ table ] = explode ('. ' , $ table );
133
- }
134
-
135
- $ columns = $ schema ->listTableColumns ($ table , $ database );
136
-
137
- $ uses_enums = collect ($ columns )->contains (function ($ column ) {
138
- return $ column ->getType () instanceof \Blueprint \EnumType;
139
- });
140
-
141
- if ($ uses_enums ) {
142
- $ definitions = $ model ->getConnection ()->getDoctrineConnection ()->fetchAll ($ schema ->getDatabasePlatform ()->getListTableColumnsSQL ($ table , $ database ));
143
-
144
- collect ($ columns )->filter (function ($ column ) {
145
- return $ column ->getType () instanceof \Blueprint \EnumType;
146
- })->each (function (&$ column , $ key ) use ($ definitions ) {
147
- $ definition = collect ($ definitions )->where ('Field ' , $ key )->first ();
148
-
149
- $ column ->options = \Blueprint \EnumType::extractOptions ($ definition ['Type ' ]);
150
- });
151
- }
152
-
153
- return $ columns ;
154
- }
155
-
156
- /**
157
- * @param \Doctrine\DBAL\Schema\Column[] $columns
158
- */
159
- private function mapColumns ($ columns )
160
- {
161
- return collect ($ columns )
162
- ->map ([self ::class, 'columns ' ])
163
- ->toArray ();
164
- }
165
-
166
- public static function columns (\Doctrine \DBAL \Schema \Column $ column , string $ key )
167
- {
168
- $ attributes = [];
169
-
170
- $ type = self ::translations ($ column ->getType ()->getName ());
171
-
172
- if (in_array ($ type , ['decimal ' , 'float ' ])) {
173
- if ($ column ->getPrecision ()) {
174
- $ type .= ': ' . $ column ->getPrecision ();
175
- }
176
- if ($ column ->getScale ()) {
177
- $ type .= ', ' . $ column ->getScale ();
178
- }
179
- } elseif ($ type === 'string ' && $ column ->getLength ()) {
180
- if ($ column ->getLength () !== 255 ) {
181
- $ type .= ': ' . $ column ->getLength ();
182
- }
183
- } elseif ($ type === 'text ' ) {
184
- if ($ column ->getLength () > 65535 ) {
185
- $ type = 'longtext ' ;
186
- }
187
- } elseif ($ type === 'enum ' && !empty ($ column ->options )) {
188
- $ type .= ': ' . implode (', ' , $ column ->options );
189
- }
190
-
191
- // TODO: guid/uuid
192
-
193
- $ attributes [] = $ type ;
194
-
195
- if ($ column ->getUnsigned ()) {
196
- $ attributes [] = 'unsigned ' ;
197
- }
198
-
199
- if (!$ column ->getNotnull ()) {
200
- $ attributes [] = 'nullable ' ;
201
- }
202
-
203
- if ($ column ->getAutoincrement ()) {
204
- $ attributes [] = 'autoincrement ' ;
205
- }
206
-
207
- if (!is_null ($ column ->getDefault ())) {
208
- $ attributes [] = 'default: ' . $ column ->getDefault ();
209
- }
210
-
211
- return implode (' ' , $ attributes );
212
- }
213
-
214
- private static function translations (string $ type )
215
- {
216
- static $ mappings = [
217
- 'array ' => 'string ' ,
218
- 'bigint ' => 'biginteger ' ,
219
- 'binary ' => 'binary ' ,
220
- 'blob ' => 'binary ' ,
221
- 'boolean ' => 'boolean ' ,
222
- 'date ' => 'date ' ,
223
- 'date_immutable ' => 'date ' ,
224
- 'dateinterval ' => 'date ' ,
225
- 'datetime ' => 'datetime ' ,
226
- 'datetime_immutable ' => 'datetime ' ,
227
- 'datetimetz ' => 'datetimetz ' ,
228
- 'datetimetz_immutable ' => 'datetimetz ' ,
229
- 'decimal ' => 'decimal ' ,
230
- 'enum ' => 'enum ' ,
231
- 'float ' => 'float ' ,
232
- 'guid ' => 'string ' ,
233
- 'integer ' => 'integer ' ,
234
- 'json ' => 'json ' ,
235
- 'object ' => 'string ' ,
236
- 'simple_array ' => 'string ' ,
237
- 'smallint ' => 'smallinteger ' ,
238
- 'string ' => 'string ' ,
239
- 'text ' => 'text ' ,
240
- 'time ' => 'time ' ,
241
- 'time_immutable ' => 'time ' ,
242
- ];
243
-
244
- return $ mappings [$ type ] ?? 'string ' ;
245
- }
246
-
247
- private function translateColumns (array $ columns )
248
- {
249
- if (isset ($ columns ['id ' ]) && strpos ($ columns ['id ' ], 'autoincrement ' ) !== false && strpos ($ columns ['id ' ], 'integer ' ) !== false ) {
250
- unset($ columns ['id ' ]);
251
- }
252
-
253
- if (isset ($ columns [Model::CREATED_AT ]) && isset ($ columns [Model::UPDATED_AT ])) {
254
- if (strpos ($ columns [Model::CREATED_AT ], 'datetimetz ' ) !== false ) {
255
- $ columns ['timestampstz ' ] = 'timestampsTz ' ;
256
- }
257
-
258
- unset($ columns [Model::CREATED_AT ]);
259
- unset($ columns [Model::UPDATED_AT ]);
260
- }
261
-
262
- if (isset ($ columns ['deleted_at ' ])) {
263
- if (strpos ($ columns ['deleted_at ' ], 'datetimetz ' ) !== false ) {
264
- $ columns ['softdeletestz ' ] = 'softDeletesTz ' ;
265
- }
266
-
267
- unset($ columns ['deleted_at ' ]);
268
- }
269
-
270
- return $ columns ;
271
- }
272
-
273
- private function relativeClassName ($ model )
274
- {
275
- $ name = Blueprint::relativeNamespace (get_class ($ model ));
276
- if (config ('blueprint.models_namespace ' )) {
277
- return $ name ;
57
+ } else {
58
+ $ this ->info ('Traced ' . count ($ definitions ) . ' ' . Str::plural ('model ' , count ($ definitions )));
278
59
}
279
60
280
- return ltrim ( str_replace ( config ( ' blueprint.models_namespace ' ), '' , $ name ), '\\' ) ;
61
+ return 0 ;
281
62
}
282
63
}
0 commit comments