Entity::getSource()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 2
b 0
f 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cycle\Schema\Definition;
6
7
use Cycle\ORM\MapperInterface;
8
use Cycle\ORM\RepositoryInterface;
9
use Cycle\ORM\Select\ScopeInterface;
10
use Cycle\ORM\Select\SourceInterface;
11
use Cycle\Schema\Definition\Map\FieldMap;
12
use Cycle\Schema\Definition\Map\ForeignKeyMap;
13
use Cycle\Schema\Definition\Map\OptionMap;
14
use Cycle\Schema\Definition\Map\RelationMap;
15
use Cycle\Schema\Exception\EntityException;
16
use Cycle\Schema\SchemaModifierInterface;
17
18
/**
19
 * Contains information about specific entity definition.
20
 *
21
 * @template TEntity of object
22
 */
23
final class Entity
24
{
25
    private OptionMap $options;
26
27
    /**
28
     * @var non-empty-string|null
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string|null at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string|null.
Loading history...
29
     */
30
    private ?string $role = null;
31
32
    /**
33
     * @var class-string<TEntity>|null
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<TEntity>|null at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<TEntity>|null.
Loading history...
34
     */
35
    private ?string $class = null;
36
37
    /**
38
     * @var non-empty-string|null
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string|null at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string|null.
Loading history...
39
     */
40
    private ?string $database = null;
41
42
    /**
43
     * @var non-empty-string|null
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string|null at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string|null.
Loading history...
44
     */
45
    private ?string $tableName = null;
46
47
    /**
48
     * @var class-string<MapperInterface>|null
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<MapperInterface>|null at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<MapperInterface>|null.
Loading history...
49 1438
     */
50
    private ?string $mapper = null;
51 1438
52 1438
    /**
53 1438
     * @var class-string<SourceInterface>|null
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<SourceInterface>|null at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<SourceInterface>|null.
Loading history...
54 1438
     */
55 1438
    private ?string $source = null;
56
57
    /**
58
     * @var class-string<ScopeInterface>|null
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<ScopeInterface>|null at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<ScopeInterface>|null.
Loading history...
59
     */
60 56
    private ?string $scope = null;
61
62 56
    /**
63 56
     * @var class-string<RepositoryInterface<TEntity>>|null
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<RepositoryInterface<TEntity>>|null at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<RepositoryInterface<TEntity>>|null.
Loading history...
64 56
     */
65 56
    private ?string $repository = null;
66 56
67
    /**
68 16
     * @var class-string|class-string[]|non-empty-string|non-empty-string[]|null
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string|class-strin...non-empty-string[]|null at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string|class-string[]|non-empty-string|non-empty-string[]|null.
Loading history...
69
     */
70 16
    private array|string|null $typecast = null;
71
72
    private array $schema = [];
73 1356
    private FieldMap $fields;
74
    private RelationMap $relations;
75 1356
    private FieldMap $primaryFields;
76
    private array $schemaModifiers = [];
77 1356
    private ?Inheritance $inheritance = null;
78
79
    /** @var class-string|null */
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string|null at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string|null.
Loading history...
80 1364
    private ?string $stiParent = null;
81
82 1364
    private ForeignKeyMap $foreignKeys;
83
84
    public function __construct()
85 1318
    {
86
        $this->options = new OptionMap();
87 1318
        $this->fields = new FieldMap();
88
        $this->primaryFields = new FieldMap();
89 1318
        $this->relations = new RelationMap();
90
        $this->foreignKeys = new ForeignKeyMap();
91
    }
92 1250
93
    public function getOptions(): OptionMap
94 1250
    {
95
        return $this->options;
96
    }
97 2
98
    /**
99 2
     * @param non-empty-string $role
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string.
Loading history...
100
     */
101 2
    public function setRole(string $role): self
102
    {
103
        $this->role = $role;
104 790
105
        return $this;
106 790
    }
107
108
    /**
109 2
     * @return non-empty-string|null
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string|null at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string|null.
Loading history...
110
     */
111 2
    public function getRole(): ?string
112
    {
113 2
        return $this->role;
114
    }
115
116 790
    /**
117
     * @param class-string<TEntity> $class
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<TEntity> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<TEntity>.
Loading history...
118 790
     */
119
    public function setClass(string $class): self
120
    {
121 2
        $this->class = $class;
122
123 2
        return $this;
124
    }
125 2
126
    /**
127
     * @return class-string<TEntity>|null
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<TEntity>|null at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<TEntity>|null.
Loading history...
128 790
     */
129
    public function getClass(): ?string
130 790
    {
131
        return $this->class;
132
    }
133 2
134
    /**
135 2
     * @param class-string<MapperInterface>|null $mapper
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<MapperInterface>|null at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<MapperInterface>|null.
Loading history...
136
     */
137 2
    public function setMapper(?string $mapper): self
138
    {
139
        $this->mapper = $mapper;
140 790
141
        return $this;
142 790
    }
143
144
    /**
145
     * @return class-string<MapperInterface>|null
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<MapperInterface>|null at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<MapperInterface>|null.
Loading history...
146
     */
147
    public function getMapper(): ?string
148
    {
149
        return $this->normalizeClass($this->mapper);
150 598
    }
151
152 598
    /**
153
     * @param class-string<SourceInterface>|null $source
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<SourceInterface>|null at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<SourceInterface>|null.
Loading history...
154 598
     */
155
    public function setSource(?string $source): self
156
    {
157
        $this->source = $source;
158
159
        return $this;
160 794
    }
161
162 794
    /**
163
     * @return class-string<SourceInterface>|null
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<SourceInterface>|null at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<SourceInterface>|null.
Loading history...
164
     */
165 1328
    public function getSource(): ?string
166
    {
167 1328
        return $this->normalizeClass($this->source);
168
    }
169
170 1252
    /**
171
     * @param class-string<ScopeInterface>|null $scope
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<ScopeInterface>|null at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<ScopeInterface>|null.
Loading history...
172 1252
     */
173
    public function setScope(?string $scope): self
174
    {
175 16
        $this->scope = $scope;
176
177 16
        return $this;
178 16
    }
179
180
    /**
181
     * @return class-string<ScopeInterface>|null
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<ScopeInterface>|null at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<ScopeInterface>|null.
Loading history...
182
     */
183
    public function getScope(): ?string
184 794
    {
185
        return $this->normalizeClass($this->scope);
186
    }
187 794
188 784
    /**
189
     * @param class-string<RepositoryInterface<TEntity>>|null $repository
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<RepositoryInterface<TEntity>>|null at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<RepositoryInterface<TEntity>>|null.
Loading history...
190 2
     */
191
    public function setRepository(?string $repository): self
192 2
    {
193
        $this->repository = $repository;
194 2
195
        return $this;
196
    }
197 790
198
    /**
199 790
     * @return class-string<RepositoryInterface<TEntity>>|null
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<RepositoryInterface<TEntity>>|null at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<RepositoryInterface<TEntity>>|null.
Loading history...
200
     */
201
    public function getRepository(): ?string
202
    {
203
        return $this->normalizeClass($this->repository);
204
    }
205 10
206
    /**
207 10
     * @param class-string|class-string[]|non-empty-string|non-empty-string[]|null $typecast
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string|class-strin...non-empty-string[]|null at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string|class-string[]|non-empty-string|non-empty-string[]|null.
Loading history...
208 2
     *
209 2
     * @return $this
210
     */
211
    public function setTypecast(array|string|null $typecast): self
212
    {
213 10
        $this->typecast = $typecast;
214 10
215 10
        return $this;
216
    }
217
218 10
    /**
219
     * @return class-string|class-string[]|non-empty-string|non-empty-string[]|null
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string|class-strin...non-empty-string[]|null at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string|class-string[]|non-empty-string|non-empty-string[]|null.
Loading history...
220
     */
221
    public function getTypecast(): array|string|null
222
    {
223 794
        return $this->typecast;
224
    }
225 794
226 2
    public function getFields(): FieldMap
227
    {
228
        return $this->fields;
229 792
    }
230 792
231 790
    public function getRelations(): RelationMap
232
    {
233
        return $this->relations;
234
    }
235 36
236
    public function getForeignKeys(): ForeignKeyMap
237
    {
238
        return $this->foreignKeys;
239
    }
240
241
    public function addSchemaModifier(SchemaModifierInterface $modifier): self
242
    {
243 6
        $this->schemaModifiers[] = $modifier->withRole($this->role ?? throw new EntityException(
244
            'Entity must have a `role` to be able to add a modifier.',
245 6
        ));
246
247 6
        return $this;
248 6
    }
249 4
250
    /**
251 4
     * @return \Traversable<array-key, SchemaModifierInterface>
252
     */
253
    public function getSchemaModifiers(): \Traversable
254
    {
255
        yield from $this->schemaModifiers;
256 1236
    }
257
258 1236
    public function setSchema(array $schema): self
259
    {
260 1236
        $this->schema = $schema;
261 1236
262 1184
        return $this;
263
    }
264
265
    public function getSchema(): array
266 1236
    {
267 1184
        return $this->schema;
268
    }
269
270
    /**
271 94
     * Merge entity relations and fields.
272 94
     */
273
    public function merge(self $entity): void
274
    {
275 2
        foreach ($entity->getRelations() as $name => $relation) {
276
            if (!$this->relations->has($name)) {
277
                $this->relations->set($name, $relation);
278 92
            }
279
        }
280
281 796
        foreach ($entity->getFields() as $name => $field) {
282
            if (!$this->fields->has($name)) {
283 796
                $this->fields->set($name, $field);
284 788
            }
285
        }
286
287 8
        foreach ($entity->getForeignKeys() as $foreignKey) {
288
            if (!$this->foreignKeys->has($foreignKey)) {
289
                $this->foreignKeys->set($foreignKey);
290 18
            }
291
        }
292 18
    }
293 18
294
    /**
295 792
     * Check if entity has primary key
296
     */
297 792
    public function hasPrimaryKey(): bool
298
    {
299
        if ($this->primaryFields->count() > 0) {
300
            return true;
301
        }
302
303 782
        foreach ($this->getFields() as $field) {
304
            if ($field->isPrimary()) {
305 782
                return true;
306
            }
307
        }
308
309
        return false;
310
    }
311 4
312
    /**
313 4
     * Set primary key using column list
314 4
     *
315
     * @param string[] $columns
316 2
     */
317
    public function setPrimaryColumns(array $columns): void
318 2
    {
319
        $this->primaryFields = new FieldMap();
320
321 2
        foreach ($columns as $column) {
322
            $name = $this->fields->getKeyByColumnName($column);
323 2
            $this->primaryFields->set($name, $this->fields->get($name));
324 2
        }
325
    }
326 2
327
    /**
328 2
     * Get entity primary key property names
329
     */
330
    public function getPrimaryFields(): FieldMap
331 2
    {
332
        $map = new FieldMap();
333 2
334 2
        foreach ($this->getFields() as $name => $field) {
335
            if ($field->isPrimary()) {
336
                $map->set($name, $field);
337
            }
338
        }
339
340
        if ($this->primaryFields->count() === 0 xor $map->count() === 0) {
341
            return $map->count() === 0 ? $this->primaryFields : $map;
342
        }
343
344
        if (
345
            $this->primaryFields->count() !== $map->count()
346
            || array_diff($map->getColumnNames(), $this->primaryFields->getColumnNames()) !== []
347
        ) {
348
            // todo make friendly exception
349
            throw new EntityException("Ambiguous primary key definition for `{$this->getRole()}`.");
350
        }
351
352
        return $this->primaryFields;
353
    }
354
355
    public function setInheritance(Inheritance $inheritance): void
356
    {
357
        $this->inheritance = $inheritance;
358
    }
359
360
    public function getInheritance(): ?Inheritance
361
    {
362
        return $this->inheritance;
363
    }
364
365
    /**
366
     * Check if entity is a child of STI
367
     */
368
    public function isChildOfSingleTableInheritance(): bool
369
    {
370
        return $this->stiParent !== null;
371
    }
372
373
    /**
374
     * @param class-string|null $parentClass
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string|null at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string|null.
Loading history...
375
     */
376
    public function markAsChildOfSingleTableInheritance(?string $parentClass): void
377
    {
378
        $this->stiParent = $parentClass;
379
    }
380
381
    public function getDatabase(): ?string
382
    {
383
        return $this->database;
384
    }
385
386
    /**
387
     * @param non-empty-string|null $database
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string|null at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string|null.
Loading history...
388
     */
389
    public function setDatabase(?string $database): void
390
    {
391
        $this->database = $database;
392
    }
393
394
    public function getTableName(): ?string
395
    {
396
        return $this->tableName;
397
    }
398
399
    /**
400
     * @param non-empty-string $tableName
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string.
Loading history...
401
     */
402
    public function setTableName(string $tableName): void
403
    {
404
        $this->tableName = $tableName;
405
    }
406
407
    /**
408
     * Full entity copy.
409
     */
410
    public function __clone()
411
    {
412
        $this->options = clone $this->options;
413
        $this->fields = clone $this->fields;
414
        $this->primaryFields = clone $this->primaryFields;
415
        $this->relations = clone $this->relations;
416
        $this->foreignKeys = clone $this->foreignKeys;
417
    }
418
419
    /**
420
     * @template T of object
421
     *
422
     * @param class-string<T>|null $class
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<T>|null at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<T>|null.
Loading history...
423
     *
424
     * @return ($class is class-string<T> ? class-string<T> : null)
0 ignored issues
show
Documentation Bug introduced by
The doc comment ($class at position 1 could not be parsed: Unknown type name '$class' at position 1 in ($class.
Loading history...
425
     */
426
    private function normalizeClass(?string $class = null): ?string
427
    {
428
        if ($class === null) {
429
            return null;
430
        }
431
432
        /** @var class-string<T> $class */
433
        $class = \ltrim($class, '\\');
434
435
        return $class;
436
    }
437
}
438