Passed
Push — master ( 7ffd5f...e12b56 )
by Anton
01:42
created

Registry::getRelations()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 7
rs 10
c 0
b 0
f 0
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 array
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] = $this->dbal->database($database)->table($table)->getSchema();
164
165
        return $this;
166
    }
167
168
    /**
169
     * @param Entity $entity
170
     * @return bool
171
     *
172
     * @throws BuilderException
173
     */
174
    public function hasTable(Entity $entity): bool
175
    {
176
        if (!$this->hasEntity($entity)) {
177
            throw new BuilderException("Undefined entity `{$entity->getRole()}`");
178
        }
179
180
        return $this->tables[$entity] !== null;
181
    }
182
183
    /**
184
     * @param Entity $entity
185
     * @return AbstractTable
186
     *
187
     * @throws BuilderException
188
     */
189
    public function getTable(Entity $entity): AbstractTable
190
    {
191
        if (!$this->hasTable($entity)) {
192
            throw new BuilderException("Entity `{$entity->getRole()}` has no assigned table");
193
        }
194
195
        return $this->tables[$entity];
196
    }
197
198
    /**
199
     * Create entity relation.
200
     *
201
     * @param Entity            $entity
202
     * @param string            $name
203
     * @param RelationInterface $relation
204
     *
205
     * @throws BuilderException
206
     */
207
    public function registerRelation(Entity $entity, string $name, RelationInterface $relation)
208
    {
209
        if (!$this->hasEntity($entity)) {
210
            throw new BuilderException("Undefined entity `{$entity->getRole()}`");
211
        }
212
213
        $this->relations[$entity][$name] = $relation;
214
    }
215
216
    /**
217
     * @param Entity $entity
218
     * @param string $name
219
     * @return bool
220
     *
221
     * @throws BuilderException
222
     */
223
    public function hasRelation(Entity $entity, string $name): bool
224
    {
225
        if (!$this->hasEntity($entity)) {
226
            throw new BuilderException("Undefined entity `{$entity->getRole()}`");
227
        }
228
229
        return isset($this->relations[$entity][$name]);
230
    }
231
232
    /**
233
     * @param Entity $entity
234
     * @param string $name
235
     * @return RelationInterface
236
     */
237
    public function getRelation(Entity $entity, string $name): RelationInterface
238
    {
239
        if (!$this->hasRelation($entity, $name)) {
240
            throw new BuilderException("Undefined relation `{$entity->getRole()}`.`{$name}`");
241
        }
242
243
        return $this->relations[$entity][$name];
244
    }
245
246
    /**
247
     * Get all relations assigned with given entity.
248
     *
249
     * @param Entity $entity
250
     * @return RelationInterface[]
251
     */
252
    public function getRelations(Entity $entity): array
253
    {
254
        if (!$this->hasEntity($entity)) {
255
            throw new BuilderException("Undefined entity `{$entity->getRole()}`");
256
        }
257
258
        return $this->relations[$entity];
259
    }
260
261
    /**
262
     * Iterate over all entities in order to fill missed data,
263
     * inverse relations and do other pre-calculations.
264
     *
265
     * @param CompilerInterface $visitor
266
     * @return Registry
267
     */
268
    public function compute(CompilerInterface $visitor): Registry
269
    {
270
        foreach ($this->entities as $entity) {
271
            $visitor->compute($this, $entity);
272
        }
273
274
        return $this;
275
    }
276
}