Completed
Branch feature/pre-split (f1ffcf)
by Anton
03:59
created

RecordSchema::getTable()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 0
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * components
4
 *
5
 * @author    Wolfy-J
6
 */
7
namespace Spiral\ORM\Schemas;
8
9
use Doctrine\Common\Inflector\Inflector;
10
use Spiral\Database\Schemas\Prototypes\AbstractTable;
11
use Spiral\Models\Reflections\ReflectionEntity;
12
use Spiral\ORM\Configs\MutatorsConfig;
13
use Spiral\ORM\Entities\RecordInstantiator;
14
use Spiral\ORM\Exceptions\DefinitionException;
15
use Spiral\ORM\Helpers\ColumnRenderer;
16
use Spiral\ORM\Record;
17
use Spiral\ORM\Schemas\Definitions\IndexDefinition;
18
19
class RecordSchema implements SchemaInterface
20
{
21
    /**
22
     * @var ReflectionEntity
23
     */
24
    private $reflection;
25
26
    /**
27
     * @invisible
28
     * @var MutatorsConfig
29
     */
30
    private $mutatorsConfig;
31
32
    /**
33
     * @var ColumnRenderer
34
     */
35
    private $renderer;
36
37
    /**
38
     * @param ReflectionEntity    $reflection
39
     * @param MutatorsConfig      $mutators
40
     * @param ColumnRenderer|null $rendered
41
     */
42
    public function __construct(
43
        ReflectionEntity $reflection,
44
        MutatorsConfig $mutators,
45
        ColumnRenderer $rendered = null
46
    ) {
47
        $this->reflection = $reflection;
48
        $this->mutatorsConfig = $mutators;
49
        $this->renderer = $rendered ?? new ColumnRenderer();
50
    }
51
52
    /**
53
     * {@inheritdoc}
54
     */
55
    public function getClass(): string
56
    {
57
        return $this->reflection->getName();
58
    }
59
60
    /**
61
     * @return ReflectionEntity
62
     */
63
    public function getReflection(): ReflectionEntity
64
    {
65
        return $this->reflection;
66
    }
67
68
    /**
69
     * {@inheritdoc}
70
     */
71
    public function getInstantiator(): string
72
    {
73
        return $this->reflection->getProperty('instantiator') ?? RecordInstantiator::class;
74
    }
75
76
    /**
77
     * {@inheritdoc}
78
     */
79
    public function getDatabase()
80
    {
81
        $database = $this->reflection->getProperty('database');
82
        if (empty($database)) {
83
            //Empty database to be used
84
            return null;
85
        }
86
87
        return $database;
88
    }
89
90
    /**
91
     * {@inheritdoc}
92
     */
93
    public function getTable(): string
94
    {
95
        $table = $this->reflection->getProperty('table');
96
        if (empty($table)) {
97
            //Generate collection using short class name
98
            $table = Inflector::camelize($this->reflection->getShortName());
99
            $table = Inflector::pluralize($table);
100
        }
101
102
        return $table;
103
    }
104
105
    /**
106
     * Returns set of declared indexes.
107
     *
108
     * Example:
109
     * const INDEXES = [
110
     *      [self::UNIQUE, 'email'],
111
     *      [self::INDEX, 'status', 'balance'],
112
     *      [self::INDEX, 'public_id']
113
     * ];
114
     *
115
     * @do generator
116
     *
117
     * @return \Generator|IndexDefinition[]
118
     *
119
     * @throws DefinitionException
120
     */
121
    public function getIndexes(): \Generator
122
    {
123
        $definitions = $this->reflection->getProperty('indexes') ?? [];
124
125
        foreach ($definitions as $definition) {
126
            yield $this->castIndex($definition);
127
        }
128
    }
129
130
    /**
131
     * {@inheritdoc}
132
     */
133
    public function renderTable(AbstractTable $table): AbstractTable
134
    {
135
        return $this->renderer->renderColumns(
136
            $this->getFields(),
137
            $this->createDefaults(),
138
            $table
139
        );
140
    }
141
142
    /**
143
     * {@inheritdoc}
144
     */
145
    public function getRelations(): array
146
    {
147
        return [];
148
    }
149
150
    /**
151
     * {@inheritdoc}
152
     */
153
    public function packSchema(SchemaBuilder $builder, AbstractTable $table = null): array
154
    {
155
        return [];
156
    }
157
158
    /**
159
     * {@inheritdoc}
160
     */
161
    protected function getFields(): array
162
    {
163
        $fields = $this->reflection->getSchema();
164
165
        foreach ($fields as $field => $type) {
166
            if ($this->isRelation($type)) {
167
                unset($fields[$field]);
168
            }
169
        }
170
171
        return $fields;
172
    }
173
174
    /**
175
     * Check if field schema/type defines relation.
176
     *
177
     * @param mixed $type
178
     *
179
     * @return bool
180
     */
181
    protected function isRelation($type): bool
182
    {
183
        if (is_array($type)) {
184
            return true;
185
        }
186
187
        return false;
188
    }
189
190
    /**
191
     * @param array $definition
192
     *
193
     * @return IndexDefinition
194
     *
195
     * @throws DefinitionException
196
     */
197
    protected function castIndex(array $definition)
198
    {
199
        $unique = null;
200
        $columns = [];
201
202
        foreach ($definition as $chunk) {
203
            if ($chunk == Record::INDEX || $chunk == Record::UNIQUE) {
204
                $unique = $chunk === Record::UNIQUE;
205
                continue;
206
            }
207
208
            $columns[] = $chunk;
209
        }
210
211
        if (is_null($unique)) {
212
            throw new DefinitionException(
213
                "Record '{$this}' has index definition with unspecified index type"
214
            );
215
        }
216
217
        if (empty($columns)) {
218
            throw new DefinitionException(
219
                "Record '{$this}' has index definition without any column associated to"
220
            );
221
        }
222
223
        return new IndexDefinition($columns, $unique);
224
    }
225
226
    /**
227
     * Default defined values.
228
     *
229
     * @return array
230
     */
231
    protected function createDefaults(): array
232
    {
233
        //Process defaults
234
        return $this->reflection->getProperty('defaults') ?? [];
235
    }
236
}