Passed
Pull Request — master (#97)
by Aleksei
02:25
created

SchemaRenderer::renderRole()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 23
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 4.0218

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 17
c 1
b 0
f 0
dl 0
loc 23
ccs 16
cts 18
cp 0.8889
rs 9.7
cc 4
nc 3
nop 1
crap 4.0218
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\SchemaInterface as 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::ORDER_BY => 'Relation::ORDER_BY',
32
        Relation::THROUGH_INNER_KEY => 'Relation::THROUGH_INNER_KEY',
33
        Relation::THROUGH_OUTER_KEY => 'Relation::THROUGH_OUTER_KEY',
34
        Relation::THROUGH_ENTITY => 'Relation::THROUGH_ENTITY',
35
        Relation::THROUGH_WHERE => 'Relation::THROUGH_WHERE',
36
        RelationSchema::INDEX_CREATE => 'RelationSchema::INDEX_CREATE',
37
        RelationSchema::FK_CREATE => 'RelationSchema::FK_CREATE',
38
        RelationSchema::FK_ACTION => 'RelationSchema::FK_ACTION',
39
        RelationSchema::INVERSE => 'RelationSchema::INVERSE',
40
        RelationSchema::MORPH_KEY_LENGTH => 'RelationSchema::MORPH_KEY_LENGTH',
41
    ];
42
    private const PREFETCH_MODE = [
43
        Relation::LOAD_PROMISE => 'Relation::LOAD_PROMISE',
44
        Relation::LOAD_EAGER => 'Relation::LOAD_EAGER',
45
    ];
46
    private const GENERAL_OPTION = [
47
        Relation::TYPE => 'Relation::TYPE',
48
        Relation::TARGET => 'Relation::TARGET',
49
        Relation::SCHEMA => 'Relation::SCHEMA',
50
        Relation::LOAD => 'Relation::LOAD',
51
    ];
52
53
    private SchemaInterface $schema;
54
55 3
    public function __construct(SchemaInterface $schema)
56
    {
57 3
        $this->schema = $schema;
58 3
    }
59
60 3
    public function render(): string
61
    {
62 3
        $arrayToString = new ArrayItemExporter(null);
63 3
        foreach ($this->schema->getRoles() as $role) {
64 3
            $arrayToString->value[] = $this->renderRole($role);
65
        }
66 3
        return (string)$arrayToString;
67
    }
68
69 3
    private function renderRole(string $role): ?ArrayItemExporter
70
    {
71 3
        $aliasOf = $this->schema->resolveAlias($role);
72 3
        if ($aliasOf !== null && $aliasOf !== $role) {
73
            // This role is an alias
74
            return null;
75
        }
76 3
        if ($this->schema->defines($role) === false) {
77
            // Role has no definition within the schema
78
            return null;
79
        }
80 3
        return new ArrayItemExporter($role, [
81 3
            $this->renderDatabase($role),
82 3
            $this->renderTable($role),
83 3
            $this->renderEntity($role),
84 3
            $this->renderMapper($role),
85 3
            $this->renderRepository($role),
86 3
            $this->renderScope($role),
87 3
            $this->renderPK($role),
88 3
            $this->renderFields($role),
89 3
            $this->renderTypecast($role),
90 3
            $this->renderRelations($role),
91 3
        ], true);
92
    }
93
94 3
    private function renderDatabase(string $role): ArrayItemExporter
95
    {
96 3
        return new ArrayItemExporter('Schema::DATABASE', $this->schema->define($role, Schema::DATABASE));
97
    }
98
99 3
    private function renderTable(string $role): ArrayItemExporter
100
    {
101 3
        return new ArrayItemExporter('Schema::TABLE', $this->schema->define($role, Schema::TABLE));
102
    }
103
104 3
    private function renderEntity(string $role): ArrayItemExporter
105
    {
106 3
        return new ArrayItemExporter('Schema::ENTITY', $this->schema->define($role, Schema::ENTITY));
107
    }
108
109 3
    private function renderMapper(string $role): ArrayItemExporter
110
    {
111 3
        return new ArrayItemExporter('Schema::MAPPER', $this->schema->define($role, Schema::MAPPER));
112
    }
113
114 3
    private function renderRepository(string $role): ArrayItemExporter
115
    {
116 3
        return new ArrayItemExporter('Schema::REPOSITORY', $this->schema->define($role, Schema::REPOSITORY));
117
    }
118
119 3
    private function renderScope(string $role): ArrayItemExporter
120
    {
121 3
        return new ArrayItemExporter('Schema::SCOPE', $this->schema->define($role, Schema::SCOPE));
122
    }
123
124 3
    private function renderPK(string $role): ArrayItemExporter
125
    {
126 3
        return new ArrayItemExporter('Schema::PRIMARY_KEY', $this->schema->define($role, Schema::PRIMARY_KEY));
127
    }
128
129 3
    private function renderFields(string $role): ArrayItemExporter
130
    {
131 3
        return new ArrayItemExporter('Schema::COLUMNS', $this->schema->define($role, Schema::COLUMNS));
132
    }
133
134 3
    private function renderTypecast(string $role): ArrayItemExporter
135
    {
136 3
        return new ArrayItemExporter('Schema::TYPECAST', $this->schema->define($role, Schema::TYPECAST));
137
    }
138
139 3
    private function renderRelations(string $role): ArrayItemExporter
140
    {
141 3
        $relations = $this->schema->define($role, Schema::RELATIONS) ?? [];
142 3
        $results = [];
143 3
        foreach ($relations as $field => $relation) {
144 1
            $relationResult = [];
145 1
            foreach ($relation as $option => $value) {
146 1
                $relationResult[] = $this->renderRelationOption($option, $value);
147
            }
148 1
            $results[] = new ArrayItemExporter($field, $relationResult, true);
149
        }
150 3
        return new ArrayItemExporter('Schema::RELATIONS', $results);
151
    }
152
153 1
    private function renderRelationOption(int $option, $value): ArrayItemExporter
154
    {
155 1
        $item = new ArrayItemExporter(self::GENERAL_OPTION[$option] ?? (string)$option, $value);
156
157
        // replace numeric keys and values with constants
158 1
        if ($option === Relation::LOAD && array_key_exists($value, self::PREFETCH_MODE)) {
159 1
            $item->value = self::PREFETCH_MODE[$value];
160 1
            $item->wrapValue = false;
161 1
        } elseif ($option === Relation::TYPE && array_key_exists($value, self::RELATION)) {
162 1
            $item->value = self::RELATION[$value];
163 1
            $item->wrapValue = false;
164 1
        } elseif ($option === Relation::SCHEMA && is_array($value)) {
165 1
            $item->value = $this->renderRelationSchemaKeys($value);
166
        }
167
168 1
        return $item;
169
    }
170
171 1
    private function renderRelationSchemaKeys(array $value): array
172
    {
173 1
        $result = [];
174 1
        foreach ($value as $listKey => $listValue) {
175 1
            $result[] = new ArrayItemExporter(
176 1
                array_key_exists($listKey, self::RELATION_OPTION) ? self::RELATION_OPTION[$listKey] : (string)$listKey,
177
                $listValue
178
            );
179
        }
180 1
        return $result;
181
    }
182
}
183