3
3
namespace BeyondCode \ErdGenerator ;
4
4
5
5
use ReflectionClass ;
6
- use ReflectionMethod ;
7
- use PhpParser \NodeTraverser ;
8
- use PhpParser \ParserFactory ;
9
- use PhpParser \Node \Stmt \Class_ ;
10
6
use Illuminate \Console \Command ;
11
7
use phpDocumentor \GraphViz \Graph ;
12
8
use Illuminate \Support \Collection ;
13
- use Illuminate \Filesystem \Filesystem ;
14
- use Illuminate \Database \Eloquent \Model ;
15
- use PhpParser \NodeVisitor \NameResolver ;
16
9
use BeyondCode \ErdGenerator \Model as GraphModel ;
17
- use Illuminate \Database \Eloquent \Relations \Relation ;
18
- use Illuminate \Database \Eloquent \Relations \BelongsTo ;
19
- use Illuminate \Database \Eloquent \Relations \MorphToMany ;
20
- use Illuminate \Database \Eloquent \Relations \HasOneOrMany ;
21
- use Illuminate \Database \Eloquent \Relations \BelongsToMany ;
22
10
23
11
class GenerateDiagramCommand extends Command
24
12
{
@@ -38,20 +26,24 @@ class GenerateDiagramCommand extends Command
38
26
*/
39
27
protected $ description = 'Generate ER diagram. ' ;
40
28
41
- /** @var Filesystem */
42
- protected $ filesystem ;
29
+ /** @var ModelFinder */
30
+ protected $ modelFinder ;
31
+
32
+ /** @var RelationFinder */
33
+ protected $ relationFinder ;
43
34
44
35
/** @var Graph */
45
36
protected $ graph ;
46
37
47
38
/** @var GraphBuilder */
48
39
protected $ graphBuilder ;
49
40
50
- public function __construct (Filesystem $ filesystem , GraphBuilder $ graphBuilder )
41
+ public function __construct (ModelFinder $ modelFinder , RelationFinder $ relationFinder , GraphBuilder $ graphBuilder )
51
42
{
52
43
parent ::__construct ();
53
44
54
- $ this ->filesystem = $ filesystem ;
45
+ $ this ->relationFinder = $ relationFinder ;
46
+ $ this ->modelFinder = $ modelFinder ;
55
47
$ this ->graphBuilder = $ graphBuilder ;
56
48
}
57
49
@@ -69,7 +61,7 @@ public function handle()
69
61
return new GraphModel (
70
62
$ model ,
71
63
(new ReflectionClass ($ model ))->getShortName (),
72
- $ this ->getModelRelations ($ model )
64
+ $ this ->relationFinder -> getModelRelations ($ model )
73
65
);
74
66
});
75
67
@@ -99,114 +91,8 @@ protected function getAllModelsFromEachDirectory(array $directories): Collection
99
91
{
100
92
return collect ($ directories )
101
93
->map (function ($ directory ) {
102
- return $ this ->getModelInstancesInDirectory ($ directory )->all ();
94
+ return $ this ->modelFinder -> getModelsInDirectory ($ directory )->all ();
103
95
})
104
96
->flatten ();
105
97
}
106
-
107
- protected function getModelInstancesInDirectory (string $ directory ): Collection
108
- {
109
- return collect ($ this ->filesystem ->files ($ directory ))->map (function ($ path ) {
110
- return $ this ->getFullyQualifiedClassNameFromFile ($ path );
111
- })->filter (function (string $ className ) {
112
- return !empty ($ className );
113
- })->filter (function (string $ className ) {
114
- return is_subclass_of ($ className , Model::class);
115
- });
116
- }
117
-
118
- protected function getFullyQualifiedClassNameFromFile (string $ path ): string
119
- {
120
- $ parser = (new ParserFactory ())->create (ParserFactory::PREFER_PHP7 );
121
-
122
- $ traverser = new NodeTraverser ();
123
- $ traverser ->addVisitor (new NameResolver ());
124
-
125
- $ code = file_get_contents ($ path );
126
-
127
- $ statements = $ parser ->parse ($ code );
128
-
129
- $ statements = $ traverser ->traverse ($ statements );
130
-
131
- return collect ($ statements [0 ]->stmts )
132
- ->filter (function ($ statement ) {
133
- return $ statement instanceof Class_;
134
- })
135
- ->map (function (Class_ $ statement ) {
136
- return $ statement ->namespacedName ->toString ();
137
- })
138
- ->first () ?? '' ;
139
- }
140
-
141
- protected function getModelRelations ($ model )
142
- {
143
- $ class = new ReflectionClass ($ model );
144
-
145
- $ traitMethods = Collection::make ($ class ->getTraits ())->map (function ($ trait ) {
146
- return Collection::make ($ trait ->getMethods (ReflectionMethod::IS_PUBLIC ));
147
- })->flatten ();
148
-
149
- $ methods = Collection::make ($ class ->getMethods (ReflectionMethod::IS_PUBLIC ))
150
- ->merge ($ traitMethods )
151
- ->reject (function (ReflectionMethod $ method ) use ($ model ) {
152
- return $ method ->class !== $ model ;
153
- })->reject (function (ReflectionMethod $ method ) use ($ model ) {
154
- return $ method ->getNumberOfParameters () > 0 ;
155
- });
156
-
157
- $ relations = Collection::make ();
158
-
159
- $ methods ->map (function (ReflectionMethod $ method ) use ($ model , &$ relations ) {
160
- $ relations = $ relations ->merge ($ this ->getRelationshipFromMethodAndModel ($ method , $ model ));
161
- });
162
-
163
- $ relations = $ relations ->filter ();
164
-
165
- return $ relations ;
166
- }
167
-
168
- protected function getParentKey (string $ qualifiedKeyName )
169
- {
170
- $ segments = explode ('. ' , $ qualifiedKeyName );
171
-
172
- return end ($ segments );
173
- }
174
-
175
- protected function getRelationshipFromMethodAndModel (ReflectionMethod $ method , string $ model )
176
- {
177
- try {
178
- $ return = $ method ->invoke (app ($ model ));
179
-
180
- if ($ return instanceof Relation) {
181
- $ localKey = null ;
182
- $ foreignKey = null ;
183
-
184
- if ($ return instanceof HasOneOrMany) {
185
- $ localKey = $ this ->getParentKey ($ return ->getQualifiedParentKeyName ());
186
- $ foreignKey = $ return ->getForeignKeyName ();
187
- }
188
-
189
- if ($ return instanceof BelongsTo) {
190
- $ foreignKey = $ this ->getParentKey ($ return ->getQualifiedOwnerKeyName ());
191
- $ localKey = $ return ->getForeignKey ();
192
- }
193
-
194
- if ($ return instanceof BelongsToMany && ! $ return instanceof MorphToMany) {
195
- $ foreignKey = $ this ->getParentKey ($ return ->getQualifiedOwnerKeyName ());
196
- $ localKey = $ return ->getForeignKey ();
197
- }
198
-
199
- return [
200
- $ method ->getName () => new ModelRelation (
201
- $ method ->getShortName (),
202
- (new ReflectionClass ($ return ))->getShortName (),
203
- (new ReflectionClass ($ return ->getRelated ()))->getName (),
204
- $ localKey ,
205
- $ foreignKey
206
- )
207
- ];
208
- }
209
- } catch (\Throwable $ e ) {}
210
- return null ;
211
- }
212
98
}
0 commit comments