MergeColumns   A
last analyzed

Complexity

Total Complexity 17

Size/Duplication

Total Lines 94
Duplicated Lines 0 %

Test Coverage

Coverage 87.88%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 47
c 1
b 0
f 0
dl 0
loc 94
ccs 29
cts 33
cp 0.8788
rs 10
wmc 17

4 Methods

Rating   Name   Duplication   Size   Complexity  
A run() 0 21 5
B copy() 0 34 6
A getColumns() 0 18 5
A __construct() 0 5 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cycle\Annotated;
6
7
use Cycle\Annotated\Annotation\Column;
8
use Cycle\Annotated\Annotation\Table;
9
use Cycle\Annotated\Exception\AnnotationException;
10
use Cycle\Annotated\Utils\EntityUtils;
11
use Cycle\Schema\Definition\Entity as EntitySchema;
12
use Cycle\Schema\GeneratorInterface;
13
use Cycle\Schema\Registry;
14
use Doctrine\Common\Annotations\Reader as DoctrineReader;
15
use Spiral\Attributes\ReaderInterface;
16
17
/**
18
 * Copy column definitions from Mapper/Repository to Entity.
19
 */
20
final class MergeColumns implements GeneratorInterface
21
{
22
    private ReaderInterface $reader;
23
24
    private Configurator $generator;
25 976
    private EntityUtils $utils;
26
27 976
    public function __construct(DoctrineReader|ReaderInterface $reader = null, ?EntityUtils $utils = null)
28 976
    {
29 976
        $this->reader = ReaderFactory::create($reader);
30
        $this->generator = new Configurator($this->reader);
31 928
        $this->utils = $utils ?? new EntityUtils($this->reader);
32
    }
33 928
34 928
    public function run(Registry $registry): Registry
35 72
    {
36
        foreach ($registry as $e) {
37
            if ($e->getClass() === null || !$registry->hasTable($e)) {
38 928
                continue;
39
            }
40
41 922
            $this->copy($e, $e->getClass());
42 922
43 922
            // copy from related classes
44 922
            $this->copy($e, $e->getMapper());
45
            $this->copy($e, $e->getRepository());
46 922
            $this->copy($e, $e->getSource());
47 608
            $this->copy($e, $e->getScope());
48
49
            foreach ($registry->getChildren($e) as $child) {
50
                $this->copy($child, $child->getClass());
51 922
            }
52
        }
53
54
        return $registry;
55
    }
56
57 928
    /**
58
     * @param class-string|null  $class
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...
59 928
     */
60 922
    private function copy(EntitySchema $e, ?string $class): void
61
    {
62
        if ($class === null) {
63
            return;
64 928
        }
65
66
        try {
67
            $class = new \ReflectionClass($class);
68
        } catch (\ReflectionException) {
69
            return;
70
        }
71 928
72
        try {
73 928
            $columns = [];
74
            foreach ($this->utils->findParents($class->getName()) as $parent) {
75
                $columns = \array_merge($columns, $this->getColumns($parent));
76
            }
77
            $columns = \array_merge($columns, $this->getColumns($class));
78 928
        } catch (\Exception $e) {
79 928
            throw new AnnotationException($e->getMessage(), $e->getCode(), $e);
80 434
        }
81
82
        $columns = \array_filter(
83 928
            $columns,
84 872
            static fn (string $field): bool => !$e->getFields()->has($field),
85
            \ARRAY_FILTER_USE_KEY
86
        );
87
88 472
        if ($columns === []) {
89 466
            return;
90
        }
91
92
        // additional columns (mapped to local fields automatically)
93
        $this->generator->initColumns($e, $columns, $class);
94
    }
95
96
    private function getColumns(\ReflectionClass $class): array
97
    {
98
        $columns = [];
99
100
        /** @var Table|null $table */
101
        $table = $this->reader->firstClassMetadata($class, Table::class);
102
        foreach ($table === null ? [] : $table->getColumns() as $name => $column) {
103
            if (\is_numeric($name)) {
104
                $name = $column->getProperty() ?? $column->getColumn();
105
            }
106
            $columns[$name] = $column;
107
        }
108
109
        foreach ($this->reader->getClassMetadata($class, Column::class) as $column) {
110
            $columns[$column->getProperty() ?? $column->getColumn()] = $column;
111
        }
112
113
        return $columns;
114
    }
115
}
116