Completed
Push — master ( e12b56...1fb17f )
by Anton
01:36
created

Registry   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 291
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 66
dl 0
loc 291
rs 9.6
c 0
b 0
f 0
wmc 35

18 Methods

Rating   Name   Duplication   Size   Complexity  
A register() 0 8 1
A getIterator() 0 3 1
A getEntity() 0 9 4
A hasRole() 0 9 3
A getChildren() 0 7 2
A registerChild() 0 10 2
A hasEntity() 0 3 1
A __construct() 0 6 1
A hasRelation() 0 7 2
A getRelation() 0 7 2
A run() 0 7 2
A registerRelation() 0 7 2
A getTable() 0 7 2
A getTableSchema() 0 7 2
A getRelations() 0 7 2
A getDatabase() 0 7 2
A linkTable() 0 13 2
A hasTable() 0 7 2
1
<?php
2
declare(strict_types=1);
3
/**
4
 * Spiral Framework.
5
 *
6
 * @license   MIT
7
 * @author    Anton Titov (Wolfy-J)
8
 */
9
10
namespace Cycle\Schema;
11
12
use Cycle\Schema\Definition\Entity;
13
use Cycle\Schema\Exception\BuilderException;
14
use Spiral\Database\DatabaseManager;
15
use Spiral\Database\Exception\DBALException;
16
use Spiral\Database\Schema\AbstractTable;
17
18
final class Registry implements \IteratorAggregate
19
{
20
    /** @var DatabaseManager */
21
    private $dbal;
22
23
    /** @var Entity[] */
24
    private $entities = [];
25
26
    /** @var \SplObjectStorage */
27
    private $tables;
28
29
    /** @var \SplObjectStorage */
30
    private $children;
31
32
    /** @var \SplObjectStorage */
33
    private $relations;
34
35
    /**
36
     * @param DatabaseManager $dbal
37
     */
38
    public function __construct(DatabaseManager $dbal)
39
    {
40
        $this->dbal = $dbal;
41
        $this->tables = new \SplObjectStorage();
42
        $this->children = new \SplObjectStorage();
43
        $this->relations = new \SplObjectStorage();
44
    }
45
46
    /**
47
     * @param Entity $entity
48
     * @return Registry
49
     */
50
    public function register(Entity $entity): Registry
51
    {
52
        $this->entities[] = $entity;
53
        $this->tables[$entity] = null;
54
        $this->children[$entity] = [];
55
        $this->relations[$entity] = [];
56
57
        return $this;
58
    }
59
60
    /**
61
     * @param string $role
62
     * @return bool
63
     */
64
    public function hasRole(string $role): bool
65
    {
66
        foreach ($this->entities as $entity) {
67
            if ($entity->getRole() == $role) {
68
                return true;
69
            }
70
        }
71
72
        return false;
73
    }
74
75
    /**
76
     * @param Entity $entity
77
     * @return bool
78
     */
79
    public function hasEntity(Entity $entity): bool
80
    {
81
        return array_search($entity, $this->entities, true) !== false;
82
    }
83
84
    /**
85
     * Get entity by it's role.
86
     *
87
     * @param string $role
88
     * @return Entity
89
     *
90
     * @throws BuilderException
91
     */
92
    public function getEntity(string $role): Entity
93
    {
94
        foreach ($this->entities as $entity) {
95
            if ($entity->getRole() == $role || $entity->getClass() === $role) {
96
                return $entity;
97
            }
98
        }
99
100
        throw new BuilderException("Undefined entity `{$role}`");
101
    }
102
103
    /**
104
     * @return Entity[]|\Traversable
105
     */
106
    public function getIterator()
107
    {
108
        return new \ArrayIterator($this->entities);
109
    }
110
111
    /**
112
     * Assign child entity to parent entity.
113
     *
114
     * @param Entity $parent
115
     * @param Entity $child
116
     *
117
     * @throws BuilderException
118
     */
119
    public function registerChild(Entity $parent, Entity $child)
120
    {
121
        if (!$this->hasEntity($parent)) {
122
            throw new BuilderException("Undefined entity `{$parent->getRole()}`");
123
        }
124
125
        $this->children[$parent][] = $child;
126
127
        // merge parent and child schema
128
        $parent->merge($child);
129
    }
130
131
    /**
132
     * Get all assigned children entities.
133
     *
134
     * @param Entity $entity
135
     * @return Entity[]
136
     */
137
    public function getChildren(Entity $entity): array
138
    {
139
        if (!$this->hasEntity($entity)) {
140
            throw new BuilderException("Undefined entity `{$entity->getRole()}`");
141
        }
142
143
        return $this->children[$entity];
144
    }
145
146
    /**
147
     * Associate entity with table.
148
     *
149
     * @param Entity      $entity
150
     * @param string|null $database
151
     * @param string      $table
152
     * @return Registry
153
     *
154
     * @throws BuilderException
155
     * @throws DBALException
156
     */
157
    public function linkTable(Entity $entity, ?string $database, string $table): Registry
158
    {
159
        if (!$this->hasEntity($entity)) {
160
            throw new BuilderException("Undefined entity `{$entity->getRole()}`");
161
        }
162
163
        $this->tables[$entity] = [
164
            'database' => $database,
165
            'table'    => $table,
166
            'schema'   => $this->dbal->database($database)->table($table)->getSchema()
167
        ];
168
169
        return $this;
170
    }
171
172
    /**
173
     * @param Entity $entity
174
     * @return bool
175
     *
176
     * @throws BuilderException
177
     */
178
    public function hasTable(Entity $entity): bool
179
    {
180
        if (!$this->hasEntity($entity)) {
181
            throw new BuilderException("Undefined entity `{$entity->getRole()}`");
182
        }
183
184
        return $this->tables[$entity] !== null;
185
    }
186
187
    /**
188
     * @param Entity $entity
189
     * @return string
190
     *
191
     * @throws BuilderException
192
     */
193
    public function getDatabase(Entity $entity): string
194
    {
195
        if (!$this->hasTable($entity)) {
196
            throw new BuilderException("Entity `{$entity->getRole()}` has no assigned table");
197
        }
198
199
        return $this->tables[$entity]['database'];
200
    }
201
202
    /**
203
     * @param Entity $entity
204
     * @return string
205
     *
206
     * @throws BuilderException
207
     */
208
    public function getTable(Entity $entity): string
209
    {
210
        if (!$this->hasTable($entity)) {
211
            throw new BuilderException("Entity `{$entity->getRole()}` has no assigned table");
212
        }
213
214
        return $this->tables[$entity]['table'];
215
    }
216
217
    /**
218
     * @param Entity $entity
219
     * @return AbstractTable
220
     *
221
     * @throws BuilderException
222
     */
223
    public function getTableSchema(Entity $entity): AbstractTable
224
    {
225
        if (!$this->hasTable($entity)) {
226
            throw new BuilderException("Entity `{$entity->getRole()}` has no assigned table");
227
        }
228
229
        return $this->tables[$entity]['schema'];
230
    }
231
232
    /**
233
     * Create entity relation.
234
     *
235
     * @param Entity            $entity
236
     * @param string            $name
237
     * @param RelationInterface $relation
238
     *
239
     * @throws BuilderException
240
     */
241
    public function registerRelation(Entity $entity, string $name, RelationInterface $relation)
242
    {
243
        if (!$this->hasEntity($entity)) {
244
            throw new BuilderException("Undefined entity `{$entity->getRole()}`");
245
        }
246
247
        $this->relations[$entity][$name] = $relation;
248
    }
249
250
    /**
251
     * @param Entity $entity
252
     * @param string $name
253
     * @return bool
254
     *
255
     * @throws BuilderException
256
     */
257
    public function hasRelation(Entity $entity, string $name): bool
258
    {
259
        if (!$this->hasEntity($entity)) {
260
            throw new BuilderException("Undefined entity `{$entity->getRole()}`");
261
        }
262
263
        return isset($this->relations[$entity][$name]);
264
    }
265
266
    /**
267
     * @param Entity $entity
268
     * @param string $name
269
     * @return RelationInterface
270
     */
271
    public function getRelation(Entity $entity, string $name): RelationInterface
272
    {
273
        if (!$this->hasRelation($entity, $name)) {
274
            throw new BuilderException("Undefined relation `{$entity->getRole()}`.`{$name}`");
275
        }
276
277
        return $this->relations[$entity][$name];
278
    }
279
280
    /**
281
     * Get all relations assigned with given entity.
282
     *
283
     * @param Entity $entity
284
     * @return RelationInterface[]
285
     */
286
    public function getRelations(Entity $entity): array
287
    {
288
        if (!$this->hasEntity($entity)) {
289
            throw new BuilderException("Undefined entity `{$entity->getRole()}`");
290
        }
291
292
        return $this->relations[$entity];
293
    }
294
295
    /**
296
     * Iterate over all entities in order to fill missed data,
297
     * inverse relations and do other pre-calculations.
298
     *
299
     * @param ProcessorInterface $visitor
300
     * @return Registry
301
     */
302
    public function run(ProcessorInterface $visitor): Registry
303
    {
304
        foreach ($this->entities as $entity) {
305
            $visitor->compute($this, $entity);
306
        }
307
308
        return $this;
309
    }
310
}