Completed
Push — master ( d027d5...afbe30 )
by
unknown
01:11
created

GraphBuilder::addNodeToGraph()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.9
c 0
b 0
f 0
cc 2
nc 2
nop 3
1
<?php
2
3
namespace BeyondCode\ErdGenerator;
4
5
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
6
use phpDocumentor\GraphViz\Graph;
7
use Illuminate\Support\Collection;
8
use phpDocumentor\GraphViz\Node;
9
use \Illuminate\Database\Eloquent\Model as EloquentModel;
10
11
class GraphBuilder
12
{
13
    /** @var Graph */
14
    private $graph;
15
16
    /**
17
     * @param $models
18
     * @return Graph
19
     */
20
    public function buildGraph(Collection $models) : Graph
21
    {
22
        $this->graph = new Graph();
23
24
        foreach (config('erd-generator.graph') as $key => $value) {
25
            $this->graph->{"set${key}"}($value);
26
        }
27
28
        $this->addModelsToGraph($models);
29
30
        return $this->graph;
31
    }
32
33
    protected function getTableColumnsFromModel(EloquentModel $model)
34
    {
35
        try {
36
37
            $table = $model->getConnection()->getTablePrefix() . $model->getTable();
38
            $schema = $model->getConnection()->getDoctrineSchemaManager($table);
0 ignored issues
show
Unused Code introduced by
The call to Connection::getDoctrineSchemaManager() has too many arguments starting with $table.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
39
            $databasePlatform = $schema->getDatabasePlatform();
40
            $databasePlatform->registerDoctrineTypeMapping('enum', 'string');
41
42
            $database = null;
43
44
            if (strpos($table, '.')) {
45
                list($database, $table) = explode('.', $table);
46
            }
47
48
            return $schema->listTableColumns($table, $database);
49
        } catch (\Throwable $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
50
        }
51
52
        return [];
53
    }
54
55
    protected function getModelLabel(EloquentModel $model, string $label)
56
    {
57
58
        $table = '<<table width="100%" height="100%" border="0" margin="0" cellborder="1" cellspacing="0" cellpadding="10">' . PHP_EOL;
59
        $table .= '<tr width="100%"><td width="100%" bgcolor="'.config('erd-generator.table.header_background_color').'"><font color="'.config('erd-generator.table.header_font_color').'">' . $label . '</font></td></tr>' . PHP_EOL;
60
61
        if (config('erd-generator.use_db_schema')) {
62
            $columns = $this->getTableColumnsFromModel($model);
63
            foreach ($columns as $column) {
64
                $label = $column->getName();
65
                if (config('erd-generator.use_column_types')) {
66
                    $label .= ' ('.$column->getType()->getName().')';
67
                }
68
                $table .= '<tr width="100%"><td port="' . $column->getName() . '" align="left" width="100%"  bgcolor="'.config('erd-generator.table.row_background_color').'"><font color="'.config('erd-generator.table.row_font_color').'" >' . $label . '</font></td></tr>' . PHP_EOL;
69
            }
70
        }
71
72
        $table .= '</table>>';
73
74
        return $table;
75
    }
76
77
    protected function addModelsToGraph(Collection $models)
78
    {
79
        // Add models to graph
80
        $models->map(function (Model $model) {
81
            $eloquentModel = app($model->getModel());
82
            $this->addNodeToGraph($eloquentModel, $model->getNodeName(), $model->getLabel());
83
        });
84
85
        // Create relations
86
        $models->map(function ($model) {
87
            $this->addRelationToGraph($model);
88
        });
89
    }
90
91
    protected function addNodeToGraph(EloquentModel $eloquentModel, string $nodeName, string $label)
92
    {
93
        $node = Node::create($nodeName);
94
        $node->setLabel($this->getModelLabel($eloquentModel, $label));
95
96
        foreach (config('erd-generator.node') as $key => $value) {
97
            $node->{"set${key}"}($value);
98
        }
99
100
        $this->graph->setNode($node);
101
    }
102
103
    protected function addRelationToGraph(Model $model)
104
    {
105
106
        $modelNode = $this->graph->findNode($model->getNodeName());
107
108
        /** @var ModelRelation $relation */
109
        foreach ($model->getRelations() as $relation) {
110
            $relatedModelNode = $this->graph->findNode($relation->getModelNodeName());
111
112
            if ($relatedModelNode !== null) {
113
                $this->connectByRelation($model, $relation, $modelNode, $relatedModelNode);
114
            }
115
        }
116
    }
117
118
    /**
119
     * @param Node $modelNode
120
     * @param Node $relatedModelNode
121
     * @param ModelRelation $relation
122
     */
123
    protected function connectNodes(Node $modelNode, Node $relatedModelNode, ModelRelation $relation): void
124
    {
125
        $edge = Edge::create($modelNode, $relatedModelNode);
126
        $edge->setFromPort($relation->getLocalKey());
127
        $edge->setToPort($relation->getForeignKey());
128
        $edge->setLabel(' ');
129
        $edge->setXLabel($relation->getType() . PHP_EOL . $relation->getName());
130
131
        foreach (config('erd-generator.edge') as $key => $value) {
132
            $edge->{"set${key}"}($value);
133
        }
134
135
        foreach (config('erd-generator.relations.' . $relation->getType(), []) as $key => $value) {
136
            $edge->{"set${key}"}($value);
137
        }
138
139
        $this->graph->link($edge);
140
    }
141
142
    /**
143
     * @param Model $model
144
     * @param ModelRelation $relation
145
     * @param Node $modelNode
146
     * @param Node $relatedModelNode
147
     * @return void
148
     */
149
    protected function connectBelongsToMany(
150
        Model $model,
151
        ModelRelation $relation,
152
        Node $modelNode,
153
        Node $relatedModelNode
154
    ): void {
155
        $relationName = $relation->getName();
156
        $eloquentModel = app($model->getModel());
157
158
        /** @var BelongsToMany $eloquentRelation */
159
        $eloquentRelation = $eloquentModel->$relationName();
160
161
        if (!$eloquentRelation instanceof BelongsToMany) {
162
            return;
163
        }
164
165
        $pivotClass = $eloquentRelation->getPivotClass();
166
167
        try {
168
            /** @var EloquentModel $relationModel */
169
            $pivotModel = app($pivotClass);
170
            $pivotModel->setTable($eloquentRelation->getTable());
171
            $label = (new \ReflectionClass($pivotClass))->getShortName();
172
            $pivotTable = $eloquentRelation->getTable();
173
            $this->addNodeToGraph($pivotModel, $pivotTable, $label);
174
175
            $pivotModelNode = $this->graph->findNode($pivotTable);
176
177
            $relation = new ModelRelation(
178
                $relationName,
179
                'BelongsToMany',
180
                $model->getModel(),
181
                $eloquentRelation->getParent()->getKeyName(),
182
                $eloquentRelation->getForeignPivotKeyName()
183
            );
184
185
            $this->connectNodes($modelNode, $pivotModelNode, $relation);
186
187
            $relation = new ModelRelation(
188
                $relationName,
189
                'BelongsToMany',
190
                $model->getModel(),
191
                $eloquentRelation->getRelatedPivotKeyName(),
192
                $eloquentRelation->getRelated()->getKeyName()
193
            );
194
195
            $this->connectNodes($pivotModelNode, $relatedModelNode, $relation);
196
        } catch (\ReflectionException $e){}
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
197
    }
198
199
    /**
200
     * @param Model $model
201
     * @param ModelRelation $relation
202
     * @param Node $modelNode
203
     * @param Node $relatedModelNode
204
     */
205
    protected function connectByRelation(
206
        Model $model,
207
        ModelRelation $relation,
208
        Node $modelNode,
209
        Node $relatedModelNode
210
    ): void {
211
212
        if ($relation->getType() === 'BelongsToMany') {
213
            $this->connectBelongsToMany($model, $relation, $modelNode, $relatedModelNode);
214
            return;
215
        }
216
217
        $this->connectNodes($modelNode, $relatedModelNode, $relation);
218
    }
219
}