Passed
Push — master ( d8a269...27cede )
by Alexander
02:46 queued 01:01
created

SchemaToPHP::renderRelations()   B

Complexity

Conditions 10
Paths 6

Size

Total Lines 30
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 110

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 10
eloc 22
c 1
b 0
f 0
nc 6
nop 1
dl 0
loc 30
ccs 0
cts 29
cp 0
crap 110
rs 7.6666

How to fix   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 Yiisoft\Yii\Cycle\Helper;
6
7
use Cycle\ORM\Relation;
8
use Cycle\ORM\Schema;
9
use Cycle\ORM\SchemaInterface;
10
11
final class SchemaToPHP
12
{
13
    private SchemaInterface $schema;
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::CASCADE => 'Relation::CASCADE',
26
        Relation::NULLABLE => 'Relation::NULLABLE',
27
        Relation::OUTER_KEY => 'Relation::OUTER_KEY',
28
        Relation::INNER_KEY => 'Relation::INNER_KEY',
29
        Relation::WHERE => 'Relation::WHERE',
30
        Relation::THROUGH_INNER_KEY => 'Relation::THROUGH_INNER_KEY',
31
        Relation::THROUGH_OUTER_KEY => 'Relation::THROUGH_OUTER_KEY',
32
        Relation::THROUGH_ENTITY => 'Relation::THROUGH_ENTITY',
33
        Relation::THROUGH_WHERE => 'Relation::THROUGH_WHERE',
34
    ];
35
    private const PREFETCH_MODE = [
36
        Relation::LOAD_PROMISE => 'Relation::LOAD_PROMISE',
37
        Relation::LOAD_EAGER => 'Relation::LOAD_EAGER',
38
    ];
39
    private const GENERAL_OPTION = [
40
        Relation::TYPE => 'Relation::TYPE',
41
        Relation::TARGET => 'Relation::TARGET',
42
        Relation::SCHEMA => 'Relation::SCHEMA',
43
        Relation::LOAD => 'Relation::LOAD',
44
    ];
45
    private const USE_LIST = [
46
        Schema::class,
47
        Relation::class,
48
    ];
49
50
    public function __construct(SchemaInterface $schema)
51
    {
52
        $this->schema = $schema;
53
    }
54
    public function __toString(): string
55
    {
56
        return $this->render();
57
    }
58
    public function render(): string
59
    {
60
        $items = new ArrayItem(null);
61
        foreach ($this->schema->getRoles() as $role) {
62
            $items->value[] = $this->renderRole($role);
63
        }
64
65
        $result = "<?php\n\n";
66
        foreach (self::USE_LIST as $use) {
67
            $result .= "use {$use};\n";
68
        }
69
        $result .= "\nreturn {$items};\n";
70
        return $result;
71
    }
72
73
    private function renderRole(string $role): ?ArrayItem
74
    {
75
        $aliasOf = $this->schema->resolveAlias($role);
76
        if ($aliasOf !== null && $aliasOf !== $role) {
77
            // This role is an alias
78
            return null;
79
        }
80
        if ($this->schema->defines($role) === false) {
81
            // Role has not a definition within the schema
82
            return null;
83
        }
84
        $declaration = new ArrayItem($role, [
85
            $this->renderDatabase($role),
86
            $this->renderTable($role),
87
            $this->renderEntity($role),
88
            $this->renderMapper($role),
89
            $this->renderRepository($role),
90
            $this->renderScope($role),
91
            $this->renderPK($role),
92
            $this->renderFields($role),
93
            $this->renderTypecast($role),
94
            $this->renderRelations($role),
95
        ], true);
96
97
        return $declaration;
98
    }
99
    private function renderDatabase(string $role): ArrayItem
100
    {
101
        return new ArrayItem('Schema::DATABASE', $this->schema->define($role, Schema::DATABASE));
102
    }
103
    private function renderTable(string $role): ArrayItem
104
    {
105
        return new ArrayItem('Schema::TABLE', $this->schema->define($role, Schema::TABLE));
106
    }
107
    private function renderEntity(string $role): ArrayItem
108
    {
109
        return new ArrayItem('Schema::ENTITY', $this->schema->define($role, Schema::ENTITY));
110
    }
111
    private function renderMapper(string $role): ArrayItem
112
    {
113
        return new ArrayItem('Schema::MAPPER', $this->schema->define($role, Schema::MAPPER));
114
    }
115
    private function renderRepository(string $role): ArrayItem
116
    {
117
        return new ArrayItem('Schema::REPOSITORY', $this->schema->define($role, Schema::REPOSITORY));
118
    }
119
    private function renderScope(string $role): ArrayItem
120
    {
121
        return new ArrayItem('Schema::CONSTRAIN', $this->schema->define($role, Schema::CONSTRAIN));
122
    }
123
    private function renderPK(string $role): ArrayItem
124
    {
125
        return new ArrayItem('Schema::PRIMARY_KEY', $this->schema->define($role, Schema::PRIMARY_KEY));
126
    }
127
    private function renderFields(string $role): ArrayItem
128
    {
129
        return new ArrayItem('Schema::COLUMNS', $this->schema->define($role, Schema::COLUMNS));
130
    }
131
    private function renderTypecast(string $role): ArrayItem
132
    {
133
        return new ArrayItem('Schema::TYPECAST', $this->schema->define($role, Schema::TYPECAST));
134
    }
135
    private function renderRelations(string $role): ArrayItem
136
    {
137
        $relations = $this->schema->define($role, Schema::RELATIONS);
138
        $results = [];
139
        foreach ($relations as $field => $relation) {
140
            $relationResult = [];
141
            // replace numeric keys and values to constants
142
            foreach ($relation as $option => $value) {
143
                $item = new ArrayItem(self::GENERAL_OPTION[$option] ?? $option, $value);
144
                if ($option === Relation::LOAD && isset(self::RELATION[$value])) {
145
                    $item->value = self::PREFETCH_MODE[$value];
146
                    $item->wrapValue = false;
147
                } elseif ($option === Relation::TYPE && isset(self::RELATION[$value])) {
148
                    $item->value = self::RELATION[$value];
149
                    $item->wrapValue = false;
150
                } elseif ($option === Relation::SCHEMA) {
151
                    $resultList = [];
152
                    foreach ($value as $listKey => $listValue) {
153
                        $resultList[] = new ArrayItem(
154
                            array_key_exists($listKey, self::RELATION_OPTION) ? self::RELATION_OPTION[$listKey] : $listKey,
155
                            $listValue
156
                        );
157
                    }
158
                    $item->value = $resultList;
159
                }
160
                $relationResult[] = $item;
161
            }
162
            $results[] = new ArrayItem($field, $relationResult, true);
163
        }
164
        return new ArrayItem('Schema::RELATIONS', $results);
165
    }
166
}
167