Passed
Push — master ( c4e040...6ac325 )
by Anton
01:42
created

Compiler   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 170
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 56
dl 0
loc 170
rs 10
c 0
b 0
f 0
wmc 23

9 Methods

Rating   Name   Duplication   Size   Complexity  
A renderColumns() 0 8 2
A compute() 0 29 3
A getPrimary() 0 9 3
A getSchema() 0 3 1
A renderReferences() 0 11 3
A renderRelations() 0 8 2
A renderTypecast() 0 10 3
A compile() 0 18 5
A childAlias() 0 4 1
1
<?php declare(strict_types=1);
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license   MIT
6
 * @author    Anton Titov (Wolfy-J)
7
 */
8
9
namespace Cycle\Schema;
10
11
use Cycle\ORM\Schema;
12
use Cycle\Schema\Definition\Entity;
13
use Doctrine\Common\Inflector\Inflector;
14
use Spiral\Database\Exception\CompilerException;
15
16
final class Compiler
17
{
18
    /** @var array */
19
    private $result = [];
20
21
    /**
22
     * Compile the registry schema.
23
     *
24
     * @param Registry             $registry
25
     * @param GeneratorInterface[] $generators
26
     * @return array
27
     *
28
     * @throws CompilerException
29
     */
30
    public function compile(Registry $registry, array $generators = []): array
31
    {
32
        foreach ($generators as $generator) {
33
            if (!$generator instanceof GeneratorInterface) {
34
                throw new CompilerException(sprintf(
35
                    "Invalid generator `%s`",
36
                    is_object($generator) ? get_class($generator) : gettype($generator)
37
                ));
38
            }
39
40
            $registry = $generator->run($registry);
41
        }
42
43
        foreach ($registry->getIterator() as $entity) {
44
            $this->compute($registry, $entity);
45
        }
46
47
        return $this->result;
48
    }
49
50
    /**
51
     * Get compiled schema result.
52
     *
53
     * @return array
54
     */
55
    public function getSchema(): array
56
    {
57
        return $this->result;
58
    }
59
60
    /**
61
     * Compile entity and relation definitions into packed ORM schema.
62
     *
63
     * @param Registry $registry
64
     * @param Entity   $entity
65
     */
66
    protected function compute(Registry $registry, Entity $entity)
67
    {
68
        $schema = [
69
            Schema::ENTITY       => $entity->getClass(),
70
            Schema::SOURCE       => $entity->getSource(),
71
            Schema::MAPPER       => $entity->getMapper(),
72
            Schema::REPOSITORY   => $entity->getRepository(),
73
            Schema::CONSTRAIN    => $entity->getConstrain(),
74
            Schema::SCHEMA       => $entity->getSchema(),
75
            Schema::PRIMARY_KEY  => $this->getPrimary($entity),
76
            Schema::COLUMNS      => $this->renderColumns($entity),
77
            Schema::FIND_BY_KEYS => $this->renderReferences($entity),
78
            Schema::TYPECAST     => $this->renderTypecast($entity),
79
            Schema::RELATIONS    => $this->renderRelations($registry, $entity)
80
        ];
81
82
        if ($registry->hasTable($entity)) {
83
            $schema[Schema::DATABASE] = $registry->getDatabase($entity);
84
            $schema[Schema::TABLE] = $registry->getTable($entity);
85
        }
86
87
        // table inheritance
88
        foreach ($registry->getChildren($entity) as $child) {
89
            $this->result[$child->getClass()] = [Schema::ROLE => $entity->getRole()];
90
            $schema[Schema::CHILDREN][$this->childAlias($child)] = $child->getClass();
91
        }
92
93
        ksort($schema);
94
        $this->result[$entity->getRole()] = $schema;
95
    }
96
97
    /**
98
     * @param Entity $entity
99
     * @return array
100
     */
101
    protected function renderColumns(Entity $entity): array
102
    {
103
        $schema = [];
104
        foreach ($entity->getFields() as $name => $field) {
105
            $schema[$name] = $field->getColumn();
106
        }
107
108
        return $schema;
109
    }
110
111
    /**
112
     * @param Entity $entity
113
     * @return array
114
     */
115
    protected function renderTypecast(Entity $entity): array
116
    {
117
        $schema = [];
118
        foreach ($entity->getFields() as $name => $field) {
119
            if ($field->hasTypecast()) {
120
                $schema[$name] = $field->getTypecast();
121
            }
122
        }
123
124
        return $schema;
125
    }
126
127
    /**
128
     * @param Entity $entity
129
     * @return array
130
     */
131
    protected function renderReferences(Entity $entity): array
132
    {
133
        $schema = [$this->getPrimary($entity)];
134
135
        foreach ($entity->getFields() as $name => $field) {
136
            if ($field->isReferenced()) {
137
                $schema[] = $name;
138
            }
139
        }
140
141
        return array_unique($schema);
142
    }
143
144
    /**
145
     * @param Registry $registry
146
     * @param Entity   $entity
147
     * @return array
148
     */
149
    protected function renderRelations(Registry $registry, Entity $entity): array
150
    {
151
        $result = [];
152
        foreach ($registry->getRelations($entity) as $name => $relation) {
153
            $result[$name] = $relation->packSchema();
154
        }
155
156
        return $result;
157
    }
158
159
    /**
160
     * @param Entity $entity
161
     * @return string
162
     *
163
     * @throws CompilerException
164
     */
165
    protected function getPrimary(Entity $entity): string
166
    {
167
        foreach ($entity->getFields() as $name => $field) {
168
            if ($field->isPrimary()) {
169
                return $name;
170
            }
171
        }
172
173
        throw new CompilerException("Entity `{$entity->getRole()}` must have defined primary key");
174
    }
175
176
    /**
177
     * Return the unique alias for the child entity.
178
     *
179
     * @param Entity $entity
180
     * @return string
181
     */
182
    protected function childAlias(Entity $entity): string
183
    {
184
        $r = new \ReflectionClass($entity->getClass());
185
        return Inflector::classify($r->getShortName());
186
    }
187
}