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
![]() |
|||
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 |