Passed
Pull Request — master (#19)
by
unknown
03:08
created

MergePrimaryKey::run()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 5
c 1
b 0
f 0
dl 0
loc 11
rs 10
cc 4
nc 3
nop 1
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 $primaryKeyMeta */
71
            $primaryKeyMeta = $this->reader->firstClassMetadata($class, Table\PrimaryKey::class);
72
        } catch (\Exception $e) {
73
            throw new AnnotationException($e->getMessage(), $e->getCode(), $e);
74
        }
75
76
        $primaryKey = $tableMeta->getPrimary() ?? $primaryKeyMeta;
77
78
        if (!$primaryKey) {
0 ignored issues
show
introduced by
$primaryKey is of type Cycle\Annotated\Annotation\Table\PrimaryKey, thus it always evaluated to true.
Loading history...
79
            return;
80
        }
81
82
        $this->renderPrimaryKey($table, $entity, $primaryKey);
83
    }
84
85
    /**
86
     * @param AbstractTable $table
87
     * @param Entity        $entity
88
     * @param Table\Index[] $indexes
89
     */
90
    public function renderPrimaryKey(AbstractTable $table, Entity $entity, Table\PrimaryKey $primaryKey): void
91
    {
92
        if ($primaryKey->getColumns() === []) {
93
            throw new AnnotationException(
94
                "Primary key definition must have columns set on `{$entity->getClass()}`"
95
            );
96
        }
97
98
        $columns = $this->mapColumns($entity, $primaryKey->getColumns());
99
100
        $table->setPrimaryKeys($columns);
101
    }
102
103
    /**
104
     * @param Entity $entity
105
     * @param array  $columns
106
     * @return array
107
     */
108
    protected function mapColumns(Entity $entity, array $columns): array
109
    {
110
        $result = [];
111
112
        foreach ($columns as $expression) {
113
            [$column,] = AbstractIndex::parseColumn($expression);
114
115
            if ($entity->getFields()->has($column)) {
116
                $mappedName = $entity->getFields()->get($column)->getColumn();
117
            } else {
118
                $mappedName = $column;
119
            }
120
121
            $result[] = $mappedName;
122
        }
123
124
        return $result;
125
    }
126
}
127