Passed
Pull Request — master (#67)
by Aleksei
12:07
created

SchemaRenderer   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 158
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 29
eloc 91
c 2
b 0
f 0
dl 0
loc 158
rs 10

15 Methods

Rating   Name   Duplication   Size   Complexity  
A render() 0 7 2
A renderMapper() 0 3 1
A renderRelationSchemaKeys() 0 10 3
A renderEntity() 0 3 1
A renderTypecast() 0 3 1
A renderDatabase() 0 3 1
A renderPK() 0 3 1
A renderScope() 0 3 1
A renderRole() 0 25 4
A renderFields() 0 3 1
A renderTable() 0 3 1
A renderRepository() 0 3 1
A __construct() 0 3 1
A renderRelations() 0 12 3
B renderRelationOption() 0 16 7
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Cycle\Schema\Converter\SchemaToPHP;
6
7
use Cycle\ORM\Relation;
8
use Cycle\ORM\Schema;
9
use Cycle\ORM\SchemaInterface;
10
use Cycle\Schema\Relation\RelationSchema;
11
12
final class SchemaRenderer
13
{
14
    private const RELATION = [
15
        Relation::HAS_ONE => 'Relation::HAS_ONE',
16
        Relation::HAS_MANY => 'Relation::HAS_MANY',
17
        Relation::BELONGS_TO => 'Relation::BELONGS_TO',
18
        Relation::REFERS_TO => 'Relation::REFERS_TO',
19
        Relation::MANY_TO_MANY => 'Relation::MANY_TO_MANY',
20
        Relation::BELONGS_TO_MORPHED => 'Relation::BELONGS_TO_MORPHED',
21
        Relation::MORPHED_HAS_ONE => 'Relation::MORPHED_HAS_ONE',
22
        Relation::MORPHED_HAS_MANY => 'Relation::MORPHED_HAS_MANY',
23
    ];
24
    private const RELATION_OPTION = [
25
        Relation::MORPH_KEY => 'Relation::MORPH_KEY',
26
        Relation::CASCADE => 'Relation::CASCADE',
27
        Relation::NULLABLE => 'Relation::NULLABLE',
28
        Relation::OUTER_KEY => 'Relation::OUTER_KEY',
29
        Relation::INNER_KEY => 'Relation::INNER_KEY',
30
        Relation::WHERE => 'Relation::WHERE',
31
        Relation::THROUGH_INNER_KEY => 'Relation::THROUGH_INNER_KEY',
32
        Relation::THROUGH_OUTER_KEY => 'Relation::THROUGH_OUTER_KEY',
33
        Relation::THROUGH_ENTITY => 'Relation::THROUGH_ENTITY',
34
        Relation::THROUGH_WHERE => 'Relation::THROUGH_WHERE',
35
        RelationSchema::INDEX_CREATE => 'RelationSchema::INDEX_CREATE',
36
        RelationSchema::FK_CREATE => 'RelationSchema::FK_CREATE',
37
        RelationSchema::FK_ACTION => 'RelationSchema::FK_ACTION',
38
        RelationSchema::INVERSE => 'RelationSchema::INVERSE',
39
        RelationSchema::MORPH_KEY_LENGTH => 'RelationSchema::MORPH_KEY_LENGTH',
40
    ];
41
    private const PREFETCH_MODE = [
42
        Relation::LOAD_PROMISE => 'Relation::LOAD_PROMISE',
43
        Relation::LOAD_EAGER => 'Relation::LOAD_EAGER',
44
    ];
45
    private const GENERAL_OPTION = [
46
        Relation::TYPE => 'Relation::TYPE',
47
        Relation::TARGET => 'Relation::TARGET',
48
        Relation::SCHEMA => 'Relation::SCHEMA',
49
        Relation::LOAD => 'Relation::LOAD',
50
    ];
51
52
    private SchemaInterface $schema;
53
54
    public function __construct(SchemaInterface $schema)
55
    {
56
        $this->schema = $schema;
57
    }
58
59
    public function render(): string
60
    {
61
        $arrayToString = new ArrayItemRenderer(null);
62
        foreach ($this->schema->getRoles() as $role) {
63
            $arrayToString->value[] = $this->renderRole($role);
64
        }
65
        return (string)$arrayToString;
66
    }
67
68
    private function renderRole(string $role): ?ArrayItemRenderer
69
    {
70
        $aliasOf = $this->schema->resolveAlias($role);
71
        if ($aliasOf !== null && $aliasOf !== $role) {
72
            // This role is an alias
73
            return null;
74
        }
75
        if ($this->schema->defines($role) === false) {
76
            // Role has not a definition within the schema
77
            return null;
78
        }
79
        $declaration = new ArrayItemRenderer($role, [
80
            $this->renderDatabase($role),
81
            $this->renderTable($role),
82
            $this->renderEntity($role),
83
            $this->renderMapper($role),
84
            $this->renderRepository($role),
85
            $this->renderScope($role),
86
            $this->renderPK($role),
87
            $this->renderFields($role),
88
            $this->renderTypecast($role),
89
            $this->renderRelations($role),
90
        ], true);
91
92
        return $declaration;
93
    }
94
    private function renderDatabase(string $role): ArrayItemRenderer
95
    {
96
        return new ArrayItemRenderer('Schema::DATABASE', $this->schema->define($role, Schema::DATABASE));
97
    }
98
    private function renderTable(string $role): ArrayItemRenderer
99
    {
100
        return new ArrayItemRenderer('Schema::TABLE', $this->schema->define($role, Schema::TABLE));
101
    }
102
    private function renderEntity(string $role): ArrayItemRenderer
103
    {
104
        return new ArrayItemRenderer('Schema::ENTITY', $this->schema->define($role, Schema::ENTITY));
105
    }
106
    private function renderMapper(string $role): ArrayItemRenderer
107
    {
108
        return new ArrayItemRenderer('Schema::MAPPER', $this->schema->define($role, Schema::MAPPER));
109
    }
110
    private function renderRepository(string $role): ArrayItemRenderer
111
    {
112
        return new ArrayItemRenderer('Schema::REPOSITORY', $this->schema->define($role, Schema::REPOSITORY));
113
    }
114
    private function renderScope(string $role): ArrayItemRenderer
115
    {
116
        return new ArrayItemRenderer('Schema::CONSTRAIN', $this->schema->define($role, Schema::CONSTRAIN));
117
    }
118
    private function renderPK(string $role): ArrayItemRenderer
119
    {
120
        return new ArrayItemRenderer('Schema::PRIMARY_KEY', $this->schema->define($role, Schema::PRIMARY_KEY));
121
    }
122
    private function renderFields(string $role): ArrayItemRenderer
123
    {
124
        return new ArrayItemRenderer('Schema::COLUMNS', $this->schema->define($role, Schema::COLUMNS));
125
    }
126
    private function renderTypecast(string $role): ArrayItemRenderer
127
    {
128
        return new ArrayItemRenderer('Schema::TYPECAST', $this->schema->define($role, Schema::TYPECAST));
129
    }
130
    private function renderRelations(string $role): ArrayItemRenderer
131
    {
132
        $relations = $this->schema->define($role, Schema::RELATIONS);
133
        $results = [];
134
        foreach ($relations as $field => $relation) {
135
            $relationResult = [];
136
            foreach ($relation as $option => $value) {
137
                $relationResult[] = $this->renderRelationOption($option, $value);
138
            }
139
            $results[] = new ArrayItemRenderer($field, $relationResult, true);
140
        }
141
        return new ArrayItemRenderer('Schema::RELATIONS', $results);
142
    }
143
    private function renderRelationOption(int $option, $value): ArrayItemRenderer
144
    {
145
        $item = new ArrayItemRenderer(self::GENERAL_OPTION[$option] ?? (string)$option, $value);
146
147
        // replace numeric keys and values to constants
148
        if ($option === Relation::LOAD && array_key_exists($value, self::PREFETCH_MODE)) {
149
            $item->value = self::PREFETCH_MODE[$value];
150
            $item->wrapValue = false;
151
        } elseif ($option === Relation::TYPE && array_key_exists($value, self::RELATION)) {
152
            $item->value = self::RELATION[$value];
153
            $item->wrapValue = false;
154
        } elseif ($option === Relation::SCHEMA && is_array($value)) {
155
            $item->value = $this->renderRelationSchemaKeys($value);
156
        }
157
158
        return $item;
159
    }
160
    private function renderRelationSchemaKeys(array $value): array
161
    {
162
        $result = [];
163
        foreach ($value as $listKey => $listValue) {
164
            $result[] = new ArrayItemRenderer(
165
                array_key_exists($listKey, self::RELATION_OPTION) ? self::RELATION_OPTION[$listKey] : (string)$listKey,
166
                $listValue
167
            );
168
        }
169
        return $result;
170
    }
171
}
172