Passed
Pull Request — 1.x (#13)
by
unknown
12:35
created

MermaidRenderer::render()   F

Complexity

Conditions 22
Paths 426

Size

Total Lines 154
Code Lines 98

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 98
c 1
b 0
f 0
dl 0
loc 154
rs 0.7972
cc 22
nc 426
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cycle\Schema\Renderer\MermaidRenderer;
6
7
use Cycle\ORM\Relation as SchemaRelation;
8
use Cycle\ORM\SchemaInterface;
9
use Cycle\Schema\Renderer\MermaidRenderer\Entity\EntityRelation;
10
use Cycle\Schema\Renderer\MermaidRenderer\Entity\EntityTable;
11
use Cycle\Schema\Renderer\MermaidRenderer\Method\BelongsToMethod;
12
use Cycle\Schema\Renderer\MermaidRenderer\Method\BelongsToMorphedMethod;
13
use Cycle\Schema\Renderer\MermaidRenderer\Method\EmbeddedMethod;
14
use Cycle\Schema\Renderer\MermaidRenderer\Method\HasManyMethod;
15
use Cycle\Schema\Renderer\MermaidRenderer\Method\HasOneMethod;
16
use Cycle\Schema\Renderer\MermaidRenderer\Method\ManyToManyMethod;
17
use Cycle\Schema\Renderer\MermaidRenderer\Method\MorphedHasManyMethod;
18
use Cycle\Schema\Renderer\MermaidRenderer\Method\MorphedHasOneMethod;
19
use Cycle\Schema\Renderer\MermaidRenderer\Method\RefersToMethod;
20
use Cycle\Schema\Renderer\MermaidRenderer\Relation\BelongsToMorphedRelation;
21
use Cycle\Schema\Renderer\MermaidRenderer\Relation\BelongsToRelation;
22
use Cycle\Schema\Renderer\MermaidRenderer\Relation\EmbeddedRelation;
23
use Cycle\Schema\Renderer\MermaidRenderer\Relation\HasManyRelation;
24
use Cycle\Schema\Renderer\MermaidRenderer\Relation\HasOneRelation;
25
use Cycle\Schema\Renderer\MermaidRenderer\Relation\JoinedInheritanceRelation;
26
use Cycle\Schema\Renderer\MermaidRenderer\Relation\ManyToManyRelation;
27
use Cycle\Schema\Renderer\MermaidRenderer\Relation\MorphedHasManyRelation;
28
use Cycle\Schema\Renderer\MermaidRenderer\Relation\MorphedHasOneRelation;
29
use Cycle\Schema\Renderer\MermaidRenderer\Relation\RefersToRelation;
30
use Cycle\Schema\Renderer\MermaidRenderer\Relation\SingleInheritanceRelation;
31
use Cycle\Schema\Renderer\MermaidRenderer\Schema\ClassDiagram;
32
use Cycle\Schema\Renderer\SchemaRenderer;
33
34
final class MermaidRenderer implements SchemaRenderer
35
{
36
    public function render(array $schema): string
37
    {
38
        $class = new ClassDiagram();
39
        $roleAliasCollection = new RoleAliasCollection($schema);
40
41
        foreach ($schema as $key => $value) {
42
            if (!isset($value[SchemaInterface::COLUMNS])) {
43
                continue;
44
            }
45
46
            $role = $roleAliasCollection->getAlias($key);
47
48
            $entityTable = new EntityTable($role);
49
            $entityRelation = new EntityRelation();
50
51
            if (\strpos($key, ':') !== false) {
52
                $entityTable->addAnnotation(
53
                    new Annotation($key)
54
                );
55
            }
56
57
            foreach ($value[SchemaInterface::COLUMNS] as $column) {
58
                $typecast = $this->formatTypecast($value[SchemaInterface::TYPECAST][$column] ?? 'string');
59
60
                $entityTable->addRow(
61
                    new Row($typecast, $column)
62
                );
63
            }
64
65
            foreach ($value[SchemaInterface::RELATIONS] ?? [] as $relationKey => $relation) {
66
                if (!isset($relation[SchemaRelation::TARGET], $relation[SchemaRelation::SCHEMA])) {
67
                    continue;
68
                }
69
70
                $target = $roleAliasCollection->getAlias($relation[SchemaRelation::TARGET]);
71
72
                if (\class_exists($target)) {
73
                    $target = \lcfirst($this->getClassShortName($target));
74
                }
75
76
                $isNullable = $relation[SchemaRelation::SCHEMA][SchemaRelation::NULLABLE] ?? false;
77
78
                switch ($relation[SchemaRelation::TYPE]) {
79
                    case SchemaRelation::HAS_ONE:
80
                        $entityTable->addMethod(
81
                            new HasOneMethod($relationKey, $target)
82
                        );
83
                        $entityRelation->addRelation(
84
                            new HasOneRelation($role, $target, $relationKey, $isNullable)
85
                        );
86
                        break;
87
                    case SchemaRelation::HAS_MANY:
88
                        $entityTable->addMethod(
89
                            new HasManyMethod($relationKey, $target)
90
                        );
91
                        $entityRelation->addRelation(
92
                            new HasManyRelation($role, $target, $relationKey, $isNullable)
93
                        );
94
                        break;
95
                    case SchemaRelation::BELONGS_TO:
96
                        $entityTable->addMethod(
97
                            new BelongsToMethod($relationKey, $target)
98
                        );
99
                        $entityRelation->addRelation(
100
                            new BelongsToRelation($role, $target, $relationKey, $isNullable)
101
                        );
102
                        break;
103
                    case SchemaRelation::MANY_TO_MANY:
104
                        $throughEntity = $relation[SchemaRelation::SCHEMA][SchemaRelation::THROUGH_ENTITY] ?? null;
105
106
                        if ($throughEntity !== null) {
107
                            if (\class_exists($throughEntity)) {
108
                                $throughEntity = \lcfirst($this->getClassShortName($throughEntity));
109
                            }
110
111
                            $entityTable->addMethod(
112
                                new ManyToManyMethod($relationKey, $target)
113
                            );
114
                            $entityRelation->addRelation(
115
                                new ManyToManyRelation($role, $target, $relationKey, $isNullable)
116
                            );
117
                            $entityRelation->addRelation(
118
                                new Relation($throughEntity, $role, "$role.$relationKey", '..>', $isNullable)
119
                            );
120
                            $entityRelation->addRelation(
121
                                new Relation($throughEntity, $target, "$role.$relationKey", '..>', $isNullable)
122
                            );
123
                        }
124
                        break;
125
                    case SchemaRelation::REFERS_TO:
126
                        $entityTable->addMethod(
127
                            new RefersToMethod($relationKey, $target)
128
                        );
129
                        $entityRelation->addRelation(
130
                            new RefersToRelation($role, $target, $relationKey, $isNullable)
131
                        );
132
                        break;
133
                    case SchemaRelation::MORPHED_HAS_MANY:
134
                        $entityTable->addMethod(
135
                            new MorphedHasManyMethod($relationKey, $target)
136
                        );
137
                        $entityRelation->addRelation(
138
                            new MorphedHasManyRelation($role, $target, $relationKey, $isNullable)
139
                        );
140
                        break;
141
                    case SchemaRelation::MORPHED_HAS_ONE:
142
                        $entityTable->addMethod(
143
                            new MorphedHasOneMethod($relationKey, $target)
144
                        );
145
                        $entityRelation->addRelation(
146
                            new MorphedHasOneRelation($role, $target, $relationKey, $isNullable)
147
                        );
148
                        break;
149
                    case SchemaRelation::BELONGS_TO_MORPHED:
150
                        $entityTable->addMethod(
151
                            new BelongsToMorphedMethod($relationKey, $target)
152
                        );
153
                        $entityRelation->addRelation(
154
                            new BelongsToMorphedRelation($role, $target, $relationKey, $isNullable)
155
                        );
156
                        break;
157
                    case SchemaRelation::EMBEDDED:
158
                        $methodTarget = \explode('_', $target);
159
                        $prop = isset($methodTarget[2]) ? $methodTarget[2] . '_prop' : $target;
160
161
                        $entityTable->addMethod(
162
                            new EmbeddedMethod($prop, $relation[SchemaRelation::TARGET])
163
                        );
164
                        $entityRelation->addRelation(
165
                            new EmbeddedRelation($role, $target, $prop, $isNullable)
166
                        );
167
                        break;
168
                    default:
169
                        throw new \ErrorException(\sprintf('Relation `%s` not found.', $relation[SchemaRelation::TYPE]));
170
                }
171
            }
172
173
            foreach ($value[SchemaInterface::CHILDREN] ?? [] as $children) {
174
                $entityRelation->addRelation(
175
                    new SingleInheritanceRelation($role, $children, false)
176
                );
177
            }
178
179
            if (isset($value[SchemaInterface::PARENT])) {
180
                $entityRelation->addRelation(
181
                    new JoinedInheritanceRelation($value[SchemaInterface::PARENT], $role, false)
182
                );
183
            }
184
185
            $class->addEntity($entityTable);
186
            $class->addEntity($entityRelation);
187
        }
188
189
        return (string)$class;
190
    }
191
192
    /**
193
     * @param class-string|object $class
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string|object at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string|object.
Loading history...
194
     * @return string
195
     */
196
    private function getClassShortName($class): string
197
    {
198
        $className = \is_object($class) ? \get_class($class) : $class;
199
200
        return \substr($className, \strrpos($className, '\\') + 1);
201
    }
202
203
    /**
204
     * @psalm-suppress MissingParamType
205
     */
206
    private function formatTypecast($typecast): string
207
    {
208
        if (\is_array($typecast)) {
209
            $typecast[0] = $this->getClassShortName($typecast[0]);
210
211
            return \sprintf("[%s, '%s']", "$typecast[0]::class", $typecast[1]);
212
        }
213
214
        if ($typecast instanceof \Closure) {
215
            return 'Closure';
216
        }
217
218
        if ($typecast === 'datetime') {
219
            return $typecast;
220
        }
221
222
        if (\class_exists($typecast)) {
223
            return $this->getClassShortName($typecast) . '::class';
224
        }
225
226
        return \htmlentities($typecast);
227
    }
228
}
229