Passed
Push — feature/mermaid ( 3d0878...031919 )
by
unknown
13:43
created

MermaidRenderer::getClassShortName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
c 0
b 0
f 0
dl 0
loc 5
rs 10
cc 1
nc 1
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cycle\Schema\Renderer\MermaidRenderer;
6
7
use Cycle\ORM\Relation;
8
use Cycle\ORM\SchemaInterface;
9
use Cycle\Schema\Renderer\MermaidRenderer\Entity\EntityArrow;
10
use Cycle\Schema\Renderer\MermaidRenderer\Entity\EntityTable;
11
use Cycle\Schema\Renderer\MermaidRenderer\Exception\RelationNotFoundException;
12
use Cycle\Schema\Renderer\MermaidRenderer\Schema\ClassDiagram;
13
use Cycle\Schema\Renderer\SchemaRenderer;
14
15
final class MermaidRenderer implements SchemaRenderer
16
{
17
    private const METHOD_FORMAT = '%s: %s';
18
19
    /**
20
     * @throws RelationNotFoundException
21
     */
22
    public function render(array $schema): string
23
    {
24
        $class = new ClassDiagram();
25
        $relationMapper = new RelationMapper();
26
27
        foreach ($schema as $key => $value) {
28
            if (!isset($value[SchemaInterface::COLUMNS])) {
29
                continue;
30
            }
31
32
            $role = $value[SchemaInterface::ROLE] ?? $key;
33
34
            if (class_exists($role)) {
35
                $role = $this->getClassShortName($key);
36
            }
37
38
            if (strpos($role, ':') !== false) {
39
                $role = $key;
40
            }
41
42
            $table = new EntityTable($role);
43
            $arrow = new EntityArrow();
44
45
            foreach ($value[SchemaInterface::COLUMNS] as $column) {
46
                $table->addRow($value[SchemaInterface::TYPECAST][$column] ?? 'string', $column);
47
            }
48
49
            foreach ($value[SchemaInterface::RELATIONS] ?? [] as $relationKey => $relation) {
50
                if (!isset($relation[Relation::TARGET], $relation[Relation::SCHEMA])) {
51
                    continue;
52
                }
53
54
                $target = $relation[Relation::TARGET];
55
56
                if (class_exists($target)) {
57
                    $target = $this->getClassShortName($target);
58
                }
59
60
                $isNullable = $relation[Relation::SCHEMA][Relation::NULLABLE] ?? false;
61
62
                $mappedRelation = $relationMapper->mapWithNode($relation[Relation::TYPE], $isNullable);
63
64
                switch ($relation[Relation::TYPE]) {
65
                    case Relation::MANY_TO_MANY:
66
                        $throughEntity = $relation[Relation::SCHEMA][Relation::THROUGH_ENTITY] ?? null;
67
68
                        if ($throughEntity) {
69
                            if (class_exists($throughEntity)) {
70
                                $throughEntity = $this->getClassShortName($throughEntity);
71
                            }
72
73
                            $table->addMethod($relationKey, sprintf(self::METHOD_FORMAT, $mappedRelation[0], $target));
74
75
                            // tag --* post : posts
76
                            $arrow->addArrow($role, $target, $relationKey, $mappedRelation[1]);
77
                            // postTag ..> tag : tag.posts
78
                            $arrow->addArrow($throughEntity, $role, "$role.$relationKey", '..>');
79
                            // postTag ..> post : tag.posts
80
                            $arrow->addArrow($throughEntity, $target, "$role.$relationKey", '..>');
81
                        }
82
                        break;
83
                    case Relation::EMBEDDED:
84
                        // explode string like user:credentials
85
                        $methodTarget = explode(':', $target);
86
87
                        $table->addMethod(
88
                            $methodTarget[1] ?? $target,
89
                            sprintf(self::METHOD_FORMAT, $mappedRelation[0], $relationKey)
90
                        );
91
92
                        $arrowTarget = str_replace(':', '&#58', $target);
93
94
                        $arrow->addArrow($role, $relationKey, $arrowTarget, $mappedRelation[1]);
95
                        break;
96
                    default:
97
                        $table->addMethod($relationKey, sprintf(self::METHOD_FORMAT, $mappedRelation[0], $target));
98
                        $arrow->addArrow($role, $target, $relationKey, $mappedRelation[1]);
99
                }
100
            }
101
102
            foreach ($value[SchemaInterface::CHILDREN] ?? [] as $children) {
103
                $arrow->addArrow($role, $children, 'STI', '--|>');
104
            }
105
106
            if (isset($value[SchemaInterface::PARENT])) {
107
                $arrow->addArrow($value[SchemaInterface::PARENT], $role, 'JTI', '--|>');
108
            }
109
110
            $class->addEntity($table);
111
            $class->addEntity($arrow);
112
        }
113
114
        return (string)$class;
115
    }
116
117
    private function getClassShortName(string $namespace): string
118
    {
119
        $ref = new \ReflectionClass($namespace);
120
121
        return lcfirst($ref->getShortName());
122
    }
123
}
124