Passed
Push — master ( 875372...abb18c )
by Divine Niiquaye
07:37
created

Compiler::getPrimary()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 3
eloc 4
c 1
b 0
f 1
nc 3
nop 1
dl 0
loc 9
rs 10
1
<?php
2
3
4
declare(strict_types=1);
5
6
/*
7
 * This file is part of Biurad opensource projects.
8
 *
9
 * PHP version 7.2 and above required
10
 *
11
 * @author    Divine Niiquaye Ibok <[email protected]>
12
 * @copyright 2019 Biurad Group (https://biurad.com/)
13
 * @license   https://opensource.org/licenses/BSD-3-Clause License
14
 *
15
 * For the full copyright and license information, please view the LICENSE
16
 * file that was distributed with this source code.
17
 */
18
19
namespace Biurad\Cycle;
20
21
use Cycle\ORM\Mapper\Mapper;
22
use Cycle\ORM\Schema;
23
use Cycle\ORM\Select\Repository;
24
use Cycle\ORM\Select\Source;
25
use Cycle\Schema\Definition\Entity;
26
use Cycle\Schema\GeneratorInterface;
27
use Cycle\Schema\Registry;
28
use ReflectionClass;
29
use Spiral\Database\Exception\CompilerException;
30
31
final class Compiler
32
{
33
    /** @var array */
34
    private $result = [];
35
36
    /** @var GeneratorInterface[] */
37
    private $generators;
38
39
    /** @var array */
40
    private $defaults = [
41
        Schema::MAPPER     => Mapper::class,
42
        Schema::REPOSITORY => Repository::class,
43
        Schema::SOURCE     => Source::class,
44
        Schema::CONSTRAIN  => null,
45
    ];
46
47
    /** @var \Doctrine\Inflector\Inflector */
48
    private $inflector;
49
50
    /**
51
     * @param GeneratorInterface[] $generators
52
     * @param array                $defaults
53
     */
54
    public function __construct(array $generators = [], array $defaults = [])
55
    {
56
        $this->generators = $generators;
57
        $this->defaults   = $defaults + $this->defaults;
58
59
        $this->inflector = (new \Doctrine\Inflector\Rules\English\InflectorFactory())->build();
60
    }
61
62
    /**
63
     * Add a schema generator
64
     *
65
     * @param GeneratorInterface $generator
66
     */
67
    public function addGenerator(GeneratorInterface $generator): void
68
    {
69
        $this->generators[] = $generator;
70
    }
71
72
    /**
73
     * Compile the registry schema.
74
     *
75
     * @param Registry  $registry
76
     *
77
     * @return array
78
     */
79
    public function compile(Registry $registry): array
80
    {
81
        foreach ($this->generators as $generator) {
82
            if (!$generator instanceof GeneratorInterface) {
83
                throw new CompilerException(\sprintf(
84
                    'Invalid generator `%s`',
85
                    \is_object($generator) ? \get_class($generator) : \gettype($generator)
86
                ));
87
            }
88
89
            $registry = $generator->run($registry);
90
        }
91
92
        foreach ($registry->getIterator() as $entity) {
93
            if ($this->getPrimary($entity) === null) {
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getPrimary($entity) targeting Biurad\Cycle\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...
94
                // incomplete entity, skip
95
                continue;
96
            }
97
98
            $this->compute($registry, $entity);
99
        }
100
101
        return $this->result;
102
    }
103
104
    /**
105
     * Get compiled schema result.
106
     *
107
     * @return array
108
     */
109
    public function getSchema(): array
110
    {
111
        return $this->result;
112
    }
113
114
    /**
115
     * Compile entity and relation definitions into packed ORM schema.
116
     *
117
     * @param Registry $registry
118
     * @param Entity   $entity
119
     */
120
    protected function compute(Registry $registry, Entity $entity): void
121
    {
122
        $schema = [
123
            Schema::ENTITY       => $entity->getClass(),
124
            Schema::SOURCE       => $entity->getSource() ?? $this->defaults[Schema::SOURCE],
125
            Schema::MAPPER       => $entity->getMapper() ?? $this->defaults[Schema::MAPPER],
126
            Schema::REPOSITORY   => $entity->getRepository() ?? $this->defaults[Schema::REPOSITORY],
127
            Schema::CONSTRAIN    => $entity->getConstrain() ?? $this->defaults[Schema::CONSTRAIN],
128
            Schema::SCHEMA       => $entity->getSchema(),
129
            Schema::PRIMARY_KEY  => $this->getPrimary($entity),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getPrimary($entity) targeting Biurad\Cycle\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...
130
            Schema::COLUMNS      => $this->renderColumns($entity),
131
            Schema::FIND_BY_KEYS => $this->renderReferences($entity),
132
            Schema::TYPECAST     => $this->renderTypecast($entity),
133
            Schema::RELATIONS    => $this->renderRelations($registry, $entity),
134
        ];
135
136
        if ($registry->hasTable($entity)) {
137
            $schema[Schema::DATABASE] = $registry->getDatabase($entity);
138
            $schema[Schema::TABLE]    = $registry->getTable($entity);
139
        }
140
141
        // table inheritance
142
        foreach ($registry->getChildren($entity) as $child) {
143
            $this->result[$child->getClass()]                    = [Schema::ROLE => $entity->getRole()];
144
            $schema[Schema::CHILDREN][$this->childAlias($child)] = $child->getClass();
145
        }
146
147
        \ksort($schema);
148
        $this->result[$entity->getRole()] = $schema;
149
    }
150
151
    /**
152
     * @param Entity $entity
153
     *
154
     * @return array
155
     */
156
    protected function renderColumns(Entity $entity): array
157
    {
158
        $schema = [];
159
160
        foreach ($entity->getFields() as $name => $field) {
161
            $schema[$name] = $field->getColumn();
162
        }
163
164
        return $schema;
165
    }
166
167
    /**
168
     * @param Entity $entity
169
     *
170
     * @return array
171
     */
172
    protected function renderTypecast(Entity $entity): array
173
    {
174
        $schema = [];
175
176
        foreach ($entity->getFields() as $name => $field) {
177
            if ($field->hasTypecast()) {
178
                $schema[$name] = $field->getTypecast();
179
            }
180
        }
181
182
        return $schema;
183
    }
184
185
    /**
186
     * @param Entity $entity
187
     *
188
     * @return array
189
     */
190
    protected function renderReferences(Entity $entity): array
191
    {
192
        $schema = [$this->getPrimary($entity)];
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getPrimary($entity) targeting Biurad\Cycle\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...
193
194
        foreach ($entity->getFields() as $name => $field) {
195
            if ($field->isReferenced()) {
196
                $schema[] = $name;
197
            }
198
        }
199
200
        return \array_unique($schema);
201
    }
202
203
    /**
204
     * @param Registry $registry
205
     * @param Entity   $entity
206
     *
207
     * @return array
208
     */
209
    protected function renderRelations(Registry $registry, Entity $entity): array
210
    {
211
        $result = [];
212
213
        foreach ($registry->getRelations($entity) as $name => $relation) {
214
            $result[$name] = $relation->packSchema();
215
        }
216
217
        return $result;
218
    }
219
220
    /**
221
     * @param Entity $entity
222
     *
223
     * @return null|string
224
     */
225
    protected function getPrimary(Entity $entity): ?string
226
    {
227
        foreach ($entity->getFields() as $name => $field) {
228
            if ($field->isPrimary()) {
229
                return $name;
230
            }
231
        }
232
233
        return null;
234
    }
235
236
    /**
237
     * Return the unique alias for the child entity.
238
     *
239
     * @param Entity $entity
240
     *
241
     * @return string
242
     */
243
    protected function childAlias(Entity $entity): string
244
    {
245
        $r = new ReflectionClass($entity->getClass());
246
247
        return $this->inflector->classify($r->getShortName());
248
    }
249
}
250