Passed
Push — master ( 2ce9af...08fb94 )
by Anton
03:30
created

Compiler::getSchema()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Cycle ORM Schema Builder.
5
 *
6
 * @license   MIT
7
 * @author    Anton Titov (Wolfy-J)
8
 */
9
10
declare(strict_types=1);
11
12
namespace Cycle\Schema;
13
14
use Cycle\ORM\Mapper\Mapper;
15
use Cycle\ORM\Schema;
16
use Cycle\ORM\Select\Repository;
17
use Cycle\ORM\Select\Source;
18
use Cycle\Schema\Definition\Entity;
19
use Spiral\Database\Exception\CompilerException;
20
21
final class Compiler
22
{
23
    /** @var array */
24
    private $result = [];
25
26
    /** @var array */
27
    private $defaults = [
28
        Schema::MAPPER => Mapper::class,
29
        Schema::REPOSITORY => Repository::class,
30
        Schema::SOURCE => Source::class,
31
        Schema::CONSTRAIN => null,
32
    ];
33
34
    /** @var \Doctrine\Inflector\Inflector */
35
    private $inflector;
36
37
    public function __construct( )
38
    {
39
        $this->inflector = (new \Doctrine\Inflector\Rules\English\InflectorFactory())->build();
40
    }
41
42
    /**
43
     * Compile the registry schema.
44
     *
45
     * @param Registry $registry
46
     * @param GeneratorInterface[] $generators
47
     * @param array $defaults
48
     * @return array
49
     *
50
     */
51
    public function compile(Registry $registry, array $generators = [], array $defaults = []): array
52
    {
53
        $this->defaults = $defaults + $this->defaults;
54
55
        foreach ($generators as $generator) {
56
            if (!$generator instanceof GeneratorInterface) {
57
                throw new CompilerException(sprintf(
58
                    'Invalid generator `%s`',
59
                    is_object($generator) ? get_class($generator) : gettype($generator)
60
                ));
61
            }
62
63
            $registry = $generator->run($registry);
64
        }
65
66
        foreach ($registry->getIterator() as $entity) {
67
            if ($this->getPrimary($entity) === null) {
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getPrimary($entity) targeting Cycle\Schema\Compiler::getPrimary() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
68
                // incomplete entity, skip
69
                continue;
70
            }
71
72
            $this->compute($registry, $entity);
73
        }
74
75
        return $this->result;
76
    }
77
78
    /**
79
     * Get compiled schema result.
80
     *
81
     * @return array
82
     */
83
    public function getSchema(): array
84
    {
85
        return $this->result;
86
    }
87
88
    /**
89
     * Compile entity and relation definitions into packed ORM schema.
90
     *
91
     * @param Registry $registry
92
     * @param Entity   $entity
93
     */
94
    protected function compute(Registry $registry, Entity $entity): void
95
    {
96
        $schema = [
97
            Schema::ENTITY       => $entity->getClass(),
98
            Schema::SOURCE       => $entity->getSource() ?? $this->defaults[Schema::SOURCE],
99
            Schema::MAPPER       => $entity->getMapper() ?? $this->defaults[Schema::MAPPER],
100
            Schema::REPOSITORY   => $entity->getRepository() ?? $this->defaults[Schema::REPOSITORY],
101
            Schema::CONSTRAIN    => $entity->getConstrain() ?? $this->defaults[Schema::CONSTRAIN],
102
            Schema::SCHEMA       => $entity->getSchema(),
103
            Schema::PRIMARY_KEY  => $this->getPrimary($entity),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getPrimary($entity) targeting Cycle\Schema\Compiler::getPrimary() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
104
            Schema::COLUMNS      => $this->renderColumns($entity),
105
            Schema::FIND_BY_KEYS => $this->renderReferences($entity),
106
            Schema::TYPECAST     => $this->renderTypecast($entity),
107
            Schema::RELATIONS    => $this->renderRelations($registry, $entity)
108
        ];
109
110
        if ($registry->hasTable($entity)) {
111
            $schema[Schema::DATABASE] = $registry->getDatabase($entity);
112
            $schema[Schema::TABLE] = $registry->getTable($entity);
113
        }
114
115
        // table inheritance
116
        foreach ($registry->getChildren($entity) as $child) {
117
            $this->result[$child->getClass()] = [Schema::ROLE => $entity->getRole()];
118
            $schema[Schema::CHILDREN][$this->childAlias($child)] = $child->getClass();
119
        }
120
121
        ksort($schema);
122
        $this->result[$entity->getRole()] = $schema;
123
    }
124
125
    /**
126
     * @param Entity $entity
127
     * @return array
128
     */
129
    protected function renderColumns(Entity $entity): array
130
    {
131
        $schema = [];
132
        foreach ($entity->getFields() as $name => $field) {
133
            $schema[$name] = $field->getColumn();
134
        }
135
136
        return $schema;
137
    }
138
139
    /**
140
     * @param Entity $entity
141
     * @return array
142
     */
143
    protected function renderTypecast(Entity $entity): array
144
    {
145
        $schema = [];
146
        foreach ($entity->getFields() as $name => $field) {
147
            if ($field->hasTypecast()) {
148
                $schema[$name] = $field->getTypecast();
149
            }
150
        }
151
152
        return $schema;
153
    }
154
155
    /**
156
     * @param Entity $entity
157
     * @return array
158
     */
159
    protected function renderReferences(Entity $entity): array
160
    {
161
        $schema = [$this->getPrimary($entity)];
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getPrimary($entity) targeting Cycle\Schema\Compiler::getPrimary() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
162
163
        foreach ($entity->getFields() as $name => $field) {
164
            if ($field->isReferenced()) {
165
                $schema[] = $name;
166
            }
167
        }
168
169
        return array_unique($schema);
170
    }
171
172
    /**
173
     * @param Registry $registry
174
     * @param Entity   $entity
175
     * @return array
176
     */
177
    protected function renderRelations(Registry $registry, Entity $entity): array
178
    {
179
        $result = [];
180
        foreach ($registry->getRelations($entity) as $name => $relation) {
181
            $result[$name] = $relation->packSchema();
182
        }
183
184
        return $result;
185
    }
186
187
    /**
188
     * @param Entity $entity
189
     * @return string|null
190
     */
191
    protected function getPrimary(Entity $entity): ?string
192
    {
193
        foreach ($entity->getFields() as $name => $field) {
194
            if ($field->isPrimary()) {
195
                return $name;
196
            }
197
        }
198
199
        return null;
200
    }
201
202
    /**
203
     * Return the unique alias for the child entity.
204
     *
205
     * @param Entity $entity
206
     * @return string
207
     */
208
    protected function childAlias(Entity $entity): string
209
    {
210
        $r = new \ReflectionClass($entity->getClass());
211
212
        return $this->inflector->classify($r->getShortName());
213
    }
214
}
215