Passed
Push — master ( 4fd39d...85385a )
by Anton
01:54
created

Registry::hasRole()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 4
nc 3
nop 1
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license   MIT
6
 * @author    Anton Titov (Wolfy-J)
7
 */
8
9
namespace Cycle\Schema;
10
11
use Cycle\Schema\Definition\Entity;
12
use Cycle\Schema\Exception\RegistryException;
13
use Cycle\Schema\Exception\RelationException;
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 Entity role of class.
62
     * @return bool
63
     */
64
    public function hasEntity(string $role): bool
65
    {
66
        foreach ($this->entities as $entity) {
67
            if ($entity->getRole() === $role || $entity->getClass() === $role) {
68
                return true;
69
            }
70
        }
71
72
        return false;
73
    }
74
75
    /**
76
     * Get entity by it's role.
77
     *
78
     * @param string $role Entity role or class name.
79
     * @return Entity
80
     *
81
     * @throws RegistryException
82
     */
83
    public function getEntity(string $role): Entity
84
    {
85
        foreach ($this->entities as $entity) {
86
            if ($entity->getRole() == $role || $entity->getClass() === $role) {
87
                return $entity;
88
            }
89
        }
90
91
        throw new RegistryException("Undefined entity `{$role}`");
92
    }
93
94
    /**
95
     * @return Entity[]|\Traversable
96
     */
97
    public function getIterator()
98
    {
99
        return new \ArrayIterator($this->entities);
100
    }
101
102
    /**
103
     * Assign child entity to parent entity.
104
     *
105
     * @param Entity $parent
106
     * @param Entity $child
107
     *
108
     * @throws RegistryException
109
     */
110
    public function registerChild(Entity $parent, Entity $child)
111
    {
112
        if (!$this->hasInstance($parent)) {
113
            throw new RegistryException("Undefined entity `{$parent->getRole()}`");
114
        }
115
116
        $children = $this->children[$parent];
117
        $children[] = $child;
118
        $this->children[$parent] = $children;
119
120
        // merge parent and child schema
121
        $parent->merge($child);
122
    }
123
124
    /**
125
     * Get all assigned children entities.
126
     *
127
     * @param Entity $entity
128
     * @return Entity[]
129
     */
130
    public function getChildren(Entity $entity): array
131
    {
132
        if (!$this->hasInstance($entity)) {
133
            throw new RegistryException("Undefined entity `{$entity->getRole()}`");
134
        }
135
136
        return $this->children[$entity];
137
    }
138
139
    /**
140
     * Associate entity with table.
141
     *
142
     * @param Entity      $entity
143
     * @param string|null $database
144
     * @param string      $table
145
     * @return Registry
146
     *
147
     * @throws RegistryException
148
     * @throws DBALException
149
     */
150
    public function linkTable(Entity $entity, ?string $database, string $table): Registry
151
    {
152
        if (!$this->hasInstance($entity)) {
153
            throw new RegistryException("Undefined entity `{$entity->getRole()}`");
154
        }
155
156
        $this->tables[$entity] = [
157
            'database' => $database,
158
            'table'    => $table,
159
            'schema'   => $this->dbal->database($database)->table($table)->getSchema()
160
        ];
161
162
        return $this;
163
    }
164
165
    /**
166
     * @param Entity $entity
167
     * @return bool
168
     *
169
     * @throws RegistryException
170
     */
171
    public function hasTable(Entity $entity): bool
172
    {
173
        if (!$this->hasInstance($entity)) {
174
            throw new RegistryException("Undefined entity `{$entity->getRole()}`");
175
        }
176
177
        return $this->tables[$entity] !== null;
178
    }
179
180
    /**
181
     * @param Entity $entity
182
     * @return string
183
     *
184
     * @throws RegistryException
185
     */
186
    public function getDatabase(Entity $entity): string
187
    {
188
        if (!$this->hasTable($entity)) {
189
            throw new RegistryException("Entity `{$entity->getRole()}` has no assigned table");
190
        }
191
192
        return $this->tables[$entity]['database'];
193
    }
194
195
    /**
196
     * @param Entity $entity
197
     * @return string
198
     *
199
     * @throws RegistryException
200
     */
201
    public function getTable(Entity $entity): string
202
    {
203
        if (!$this->hasTable($entity)) {
204
            throw new RegistryException("Entity `{$entity->getRole()}` has no assigned table");
205
        }
206
207
        return $this->tables[$entity]['table'];
208
    }
209
210
    /**
211
     * @param Entity $entity
212
     * @return AbstractTable
213
     *
214
     * @throws RegistryException
215
     */
216
    public function getTableSchema(Entity $entity): AbstractTable
217
    {
218
        if (!$this->hasTable($entity)) {
219
            throw new RegistryException("Entity `{$entity->getRole()}` has no assigned table");
220
        }
221
222
        return $this->tables[$entity]['schema'];
223
    }
224
225
    /**
226
     * Create entity relation.
227
     *
228
     * @param Entity            $entity
229
     * @param string            $name
230
     * @param RelationInterface $relation
231
     *
232
     * @throws RegistryException
233
     * @throws RelationException
234
     */
235
    public function registerRelation(Entity $entity, string $name, RelationInterface $relation)
236
    {
237
        if (!$this->hasInstance($entity)) {
238
            throw new RegistryException("Undefined entity `{$entity->getRole()}`");
239
        }
240
241
        $relations = $this->relations[$entity];
242
        $relations[$name] = $relation;
243
        $this->relations[$entity] = $relations;
244
    }
245
246
    /**
247
     * @param Entity $entity
248
     * @param string $name
249
     * @return bool
250
     *
251
     * @throws RegistryException
252
     */
253
    public function hasRelation(Entity $entity, string $name): bool
254
    {
255
        if (!$this->hasInstance($entity)) {
256
            throw new RegistryException("Undefined entity `{$entity->getRole()}`");
257
        }
258
259
        return isset($this->relations[$entity][$name]);
260
    }
261
262
    /**
263
     * @param Entity $entity
264
     * @param string $name
265
     * @return RelationInterface
266
     */
267
    public function getRelation(Entity $entity, string $name): RelationInterface
268
    {
269
        if (!$this->hasRelation($entity, $name)) {
270
            throw new RegistryException("Undefined relation `{$entity->getRole()}`.`{$name}`");
271
        }
272
273
        return $this->relations[$entity][$name];
274
    }
275
276
    /**
277
     * Get all relations assigned with given entity.
278
     *
279
     * @param Entity $entity
280
     * @return RelationInterface[]
281
     */
282
    public function getRelations(Entity $entity): array
283
    {
284
        if (!$this->hasInstance($entity)) {
285
            throw new RegistryException("Undefined entity `{$entity->getRole()}`");
286
        }
287
288
        return $this->relations[$entity];
289
    }
290
291
    /**
292
     * @param Entity $entity
293
     * @return bool
294
     */
295
    protected function hasInstance(Entity $entity): bool
296
    {
297
        return array_search($entity, $this->entities, true) !== false;
298
    }
299
}