Passed
Pull Request — master (#19)
by
unknown
02:11
created

MergePrimaryKey::render()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 26
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 14
c 2
b 0
f 0
dl 0
loc 26
rs 9.4888
cc 5
nc 6
nop 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cycle\Annotated;
6
7
use Cycle\Annotated\Annotation\Table;
8
use Cycle\Annotated\Exception\AnnotationException;
9
use Cycle\Schema\Definition\Entity;
10
use Cycle\Schema\GeneratorInterface;
11
use Cycle\Schema\Registry;
12
use Doctrine\Common\Annotations\Reader as DoctrineReader;
13
use Spiral\Attributes\ReaderInterface;
14
use Spiral\Database\Schema\AbstractIndex;
15
use Spiral\Database\Schema\AbstractTable;
16
17
/**
18
 * Set up primary key definition from Table annotations.
19
 */
20
final class MergePrimaryKey implements GeneratorInterface
21
{
22
    /** @var ReaderInterface */
23
    private $reader;
24
25
    /**
26
     * @param object<ReaderInterface|DoctrineReader>|null $reader
27
     */
28
    public function __construct(object $reader = null)
29
    {
30
        $this->reader = ReaderFactory::create($reader);
31
    }
32
33
    /**
34
     * @param Registry $registry
35
     * @return Registry
36
     */
37
    public function run(Registry $registry): Registry
38
    {
39
        foreach ($registry as $e) {
40
            if ($e->getClass() === null || !$registry->hasTable($e)) {
41
                continue;
42
            }
43
44
            $this->render($registry->getTableSchema($e), $e, $e->getClass());
45
        }
46
47
        return $registry;
48
    }
49
50
    /**
51
     * @param AbstractTable $table
52
     * @param Entity        $entity
53
     * @param string|null   $class
54
     */
55
    protected function render(AbstractTable $table, Entity $entity, ?string $class): void
56
    {
57
        if ($class === null) {
58
            return;
59
        }
60
61
        try {
62
            $class = new \ReflectionClass($class);
63
        } catch (\ReflectionException $e) {
64
            return;
65
        }
66
67
        try {
68
            /** @var Table|null $tableMeta */
69
            $tableMeta = $this->reader->firstClassMetadata($class, Table::class);
70
            /** @var Table\PrimaryKey $primaryKey */
71
            $primaryKey = $tableMeta->getPrimary() ?? $this->reader->firstClassMetadata($class, Table\PrimaryKey::class);
72
        } catch (\Exception $e) {
73
            throw new AnnotationException($e->getMessage(), $e->getCode(), $e);
74
        }
75
76
        if ($primaryKey === null) {
77
            return;
78
        }
79
80
        $this->renderPrimaryKey($table, $entity, $primaryKey);
81
    }
82
83
    /**
84
     * @param AbstractTable $table
85
     * @param Entity        $entity
86
     * @param Table\Index[] $indexes
87
     */
88
    public function renderPrimaryKey(AbstractTable $table, Entity $entity, Table\PrimaryKey $primaryKey): void
89
    {
90
        if ($primaryKey->getColumns() === []) {
91
            throw new AnnotationException(
92
                "Primary key definition must have columns set on `{$entity->getClass()}`"
93
            );
94
        }
95
96
        $columns = $this->mapColumns($entity, $primaryKey->getColumns());
97
98
        $table->setPrimaryKeys($columns);
99
    }
100
101
    /**
102
     * @param Entity $entity
103
     * @param array  $columns
104
     * @return array
105
     */
106
    protected function mapColumns(Entity $entity, array $columns): array
107
    {
108
        $result = [];
109
110
        foreach ($columns as $expression) {
111
            [$column,] = AbstractIndex::parseColumn($expression);
112
113
            if ($entity->getFields()->has($column)) {
114
                $mappedName = $entity->getFields()->get($column)->getColumn();
115
            } else {
116
                $mappedName = $column;
117
            }
118
119
            $result[] = $mappedName;
120
        }
121
122
        return $result;
123
    }
124
}
125