Registry   A
last analyzed

Complexity

Total Complexity 41

Size/Duplication

Total Lines 307
Duplicated Lines 0 %

Importance

Changes 5
Bugs 1 Features 1
Metric Value
eloc 81
c 5
b 1
f 1
dl 0
loc 307
rs 9.1199
wmc 41

17 Methods

Rating   Name   Duplication   Size   Complexity  
A getChildren() 0 7 2
A __construct() 0 6 1
A getIterator() 0 3 1
A getEntity() 0 9 4
A registerChild() 0 12 2
A hasEntity() 0 9 4
A register() 0 14 3
A hasInstance() 0 3 1
A hasRelation() 0 7 2
A getRelation() 0 7 2
A registerRelation() 0 9 2
A getTable() 0 7 2
A getTableSchema() 0 7 2
A getRelations() 0 7 2
A getDatabase() 0 7 2
B linkTable() 0 34 7
A hasTable() 0 7 2

How to fix   Complexity   

Complex Class

Complex classes like Registry often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Registry, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license   MIT
6
 * @author    Anton Titov (Wolfy-J)
7
 */
8
declare(strict_types=1);
9
10
namespace Cycle\Schema;
11
12
use Cycle\Schema\Definition\Entity;
13
use Cycle\Schema\Exception\RegistryException;
14
use Cycle\Schema\Exception\RelationException;
15
use Spiral\Database\DatabaseProviderInterface;
16
use Spiral\Database\Exception\DBALException;
17
use Spiral\Database\Schema\AbstractTable;
18
19
final class Registry implements \IteratorAggregate
20
{
21
    /** @var DatabaseProviderInterface */
22
    private $dbal;
23
24
    /** @var Entity[] */
25
    private $entities = [];
26
27
    /** @var \SplObjectStorage */
28
    private $tables;
29
30
    /** @var \SplObjectStorage */
31
    private $children;
32
33
    /** @var \SplObjectStorage */
34
    private $relations;
35
36
    /**
37
     * @param DatabaseProviderInterface $dbal
38
     */
39
    public function __construct(DatabaseProviderInterface $dbal)
40
    {
41
        $this->dbal = $dbal;
42
        $this->tables = new \SplObjectStorage();
43
        $this->children = new \SplObjectStorage();
44
        $this->relations = new \SplObjectStorage();
45
    }
46
47
    /**
48
     * @param Entity $entity
49
     * @return Registry
50
     */
51
    public function register(Entity $entity): Registry
52
    {
53
        foreach ($this->entities as $e) {
54
            if ($e->getRole() == $entity->getRole()) {
55
                throw new RegistryException("Duplicate entity `{$e->getRole()}`");
56
            }
57
        }
58
59
        $this->entities[] = $entity;
60
        $this->tables[$entity] = null;
61
        $this->children[$entity] = [];
62
        $this->relations[$entity] = [];
63
64
        return $this;
65
    }
66
67
    /**
68
     * @param string $role Entity role of class.
69
     * @return bool
70
     */
71
    public function hasEntity(string $role): bool
72
    {
73
        foreach ($this->entities as $entity) {
74
            if ($entity->getRole() === $role || $entity->getClass() === $role) {
75
                return true;
76
            }
77
        }
78
79
        return false;
80
    }
81
82
    /**
83
     * Get entity by it's role.
84
     *
85
     * @param string $role Entity role or class name.
86
     * @return Entity
87
     *
88
     * @throws RegistryException
89
     */
90
    public function getEntity(string $role): Entity
91
    {
92
        foreach ($this->entities as $entity) {
93
            if ($entity->getRole() == $role || $entity->getClass() === $role) {
94
                return $entity;
95
            }
96
        }
97
98
        throw new RegistryException("Undefined entity `{$role}`");
99
    }
100
101
    /**
102
     * @return Entity[]|\Traversable
103
     */
104
    public function getIterator()
105
    {
106
        return new \ArrayIterator($this->entities);
107
    }
108
109
    /**
110
     * Assign child entity to parent entity.
111
     *
112
     * @param Entity $parent
113
     * @param Entity $child
114
     *
115
     * @throws RegistryException
116
     */
117
    public function registerChild(Entity $parent, Entity $child)
118
    {
119
        if (!$this->hasInstance($parent)) {
120
            throw new RegistryException("Undefined entity `{$parent->getRole()}`");
121
        }
122
123
        $children = $this->children[$parent];
124
        $children[] = $child;
125
        $this->children[$parent] = $children;
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->hasInstance($entity)) {
140
            throw new RegistryException("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 RegistryException
155
     * @throws DBALException
156
     */
157
    public function linkTable(Entity $entity, ?string $database, string $table): Registry
158
    {
159
        if (!$this->hasInstance($entity)) {
160
            throw new RegistryException("Undefined entity `{$entity->getRole()}`");
161
        }
162
163
        $database = $this->dbal->database($database)->getName();
164
165
        $schema = null;
166
        foreach ($this->tables as $other) {
167
            $association = $this->tables[$other];
168
169
            if ($association === null) {
170
                continue;
171
            }
172
173
            // avoid schema duplication
174
            if ($association['database'] === $database && $association['table'] === $table) {
175
                $schema = $association['schema'];
176
                break;
177
            }
178
        }
179
180
        if (is_null($schema)) {
0 ignored issues
show
introduced by Wolfy-J
The condition is_null($schema) is always true.
Loading history...
181
            $schema = $this->dbal->database($database)->table($table)->getSchema();
182
        }
183
184
        $this->tables[$entity] = [
185
            'database' => $database,
186
            'table'    => $table,
187
            'schema'   => $schema
188
        ];
189
190
        return $this;
191
    }
192
193
    /**
194
     * @param Entity $entity
195
     * @return bool
196
     *
197
     * @throws RegistryException
198
     */
199
    public function hasTable(Entity $entity): bool
200
    {
201
        if (!$this->hasInstance($entity)) {
202
            throw new RegistryException("Undefined entity `{$entity->getRole()}`");
203
        }
204
205
        return $this->tables[$entity] !== null;
206
    }
207
208
    /**
209
     * @param Entity $entity
210
     * @return string
211
     *
212
     * @throws RegistryException
213
     */
214
    public function getDatabase(Entity $entity): string
215
    {
216
        if (!$this->hasTable($entity)) {
217
            throw new RegistryException("Entity `{$entity->getRole()}` has no assigned table");
218
        }
219
220
        return $this->tables[$entity]['database'];
221
    }
222
223
    /**
224
     * @param Entity $entity
225
     * @return string
226
     *
227
     * @throws RegistryException
228
     */
229
    public function getTable(Entity $entity): string
230
    {
231
        if (!$this->hasTable($entity)) {
232
            throw new RegistryException("Entity `{$entity->getRole()}` has no assigned table");
233
        }
234
235
        return $this->tables[$entity]['table'];
236
    }
237
238
    /**
239
     * @param Entity $entity
240
     * @return AbstractTable
241
     *
242
     * @throws RegistryException
243
     */
244
    public function getTableSchema(Entity $entity): AbstractTable
245
    {
246
        if (!$this->hasTable($entity)) {
247
            throw new RegistryException("Entity `{$entity->getRole()}` has no assigned table");
248
        }
249
250
        return $this->tables[$entity]['schema'];
251
    }
252
253
    /**
254
     * Create entity relation.
255
     *
256
     * @param Entity            $entity
257
     * @param string            $name
258
     * @param RelationInterface $relation
259
     *
260
     * @throws RegistryException
261
     * @throws RelationException
262
     */
263
    public function registerRelation(Entity $entity, string $name, RelationInterface $relation)
264
    {
265
        if (!$this->hasInstance($entity)) {
266
            throw new RegistryException("Undefined entity `{$entity->getRole()}`");
267
        }
268
269
        $relations = $this->relations[$entity];
270
        $relations[$name] = $relation;
271
        $this->relations[$entity] = $relations;
272
    }
273
274
    /**
275
     * @param Entity $entity
276
     * @param string $name
277
     * @return bool
278
     *
279
     * @throws RegistryException
280
     */
281
    public function hasRelation(Entity $entity, string $name): bool
282
    {
283
        if (!$this->hasInstance($entity)) {
284
            throw new RegistryException("Undefined entity `{$entity->getRole()}`");
285
        }
286
287
        return isset($this->relations[$entity][$name]);
288
    }
289
290
    /**
291
     * @param Entity $entity
292
     * @param string $name
293
     * @return RelationInterface
294
     */
295
    public function getRelation(Entity $entity, string $name): RelationInterface
296
    {
297
        if (!$this->hasRelation($entity, $name)) {
298
            throw new RegistryException("Undefined relation `{$entity->getRole()}`.`{$name}`");
299
        }
300
301
        return $this->relations[$entity][$name];
302
    }
303
304
    /**
305
     * Get all relations assigned with given entity.
306
     *
307
     * @param Entity $entity
308
     * @return RelationInterface[]
309
     */
310
    public function getRelations(Entity $entity): array
311
    {
312
        if (!$this->hasInstance($entity)) {
313
            throw new RegistryException("Undefined entity `{$entity->getRole()}`");
314
        }
315
316
        return $this->relations[$entity];
317
    }
318
319
    /**
320
     * @param Entity $entity
321
     * @return bool
322
     */
323
    protected function hasInstance(Entity $entity): bool
324
    {
325
        return array_search($entity, $this->entities, true) !== false;
326
    }
327
}
328