Passed
Push — master ( 6dedbf...e08e26 )
by Anton
01:45
created

RelationSchema::compute()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
/**
4
 * Spiral Framework.
5
 *
6
 * @license   MIT
7
 * @author    Anton Titov (Wolfy-J)
8
 */
9
10
namespace Cycle\Schema\Relation;
11
12
use Cycle\ORM\Relation;
13
use Cycle\Schema\Definition\Entity;
14
use Cycle\Schema\Exception\BuilderException;
15
use Cycle\Schema\Registry;
16
use Cycle\Schema\Relation\Util\OptionSchema;
17
use Cycle\Schema\RelationInterface;
18
19
/**
20
 * Defines relation options, renders needed columns and other options.
21
 */
22
abstract class RelationSchema implements RelationInterface
23
{
24
    // relation rendering options
25
    public const FK_CREATE    = 1001;
26
    public const FK_ACTION    = 1002;
27
    public const INDEX_CREATE = 1003;
28
29
    // exported relation type
30
    protected const RELATION_TYPE = null;
31
32
    // name of all required relation options
33
    protected const OPTION_SCHEMA = [];
34
35
    // options to be excluded from generated schema
36
    protected const EXCLUDE = [
37
        self::FK_CREATE,
38
        self::FK_ACTION,
39
        self::INDEX_CREATE
40
    ];
41
42
    /** @var string */
43
    protected $source;
44
45
    /** @var string */
46
    protected $target;
47
48
    /** @var OptionSchema */
49
    protected $options;
50
51
    /**
52
     * @inheritdoc
53
     */
54
    public function withContext(string $name, string $source, string $target, OptionSchema $options): RelationInterface
55
    {
56
        $relation = clone $this;
57
        $relation->source = $source;
58
        $relation->target = $target;
59
60
        $relation->options = $options->withTemplate(static::OPTION_SCHEMA)->withContext([
61
            'relation'    => $name,
62
            'source:role' => $source,
63
            'target:role' => $target
64
        ]);
65
66
        return $relation;
67
    }
68
69
    /**
70
     * @param Registry $registry
71
     */
72
    public function compute(Registry $registry)
73
    {
74
        $this->options = $this->options->withContext([
75
            'source:primaryKey' => $this->getPrimary($registry->getEntity($this->source))
76
        ]);
77
78
        if ($registry->hasRole($this->target)) {
79
            $this->options = $this->options->withContext([
80
                'target:primaryKey' => $this->getPrimary($registry->getEntity($this->target))
81
            ]);
82
        }
83
    }
84
85
    /**
86
     * @return array
87
     */
88
    public function packSchema(): array
89
    {
90
        $schema = [];
91
92
        foreach (static::OPTION_SCHEMA as $option => $template) {
93
            if (in_array($option, static::EXCLUDE)) {
94
                continue;
95
            }
96
97
            $schema[$option] = $this->options->get($option);
98
        }
99
100
        return [
101
            Relation::TYPE   => static::RELATION_TYPE,
102
            Relation::TARGET => $this->target,
103
            Relation::SCHEMA => $schema
104
        ];
105
    }
106
107
    /**
108
     * @return OptionSchema
109
     */
110
    protected function getOptions(): OptionSchema
111
    {
112
        return $this->options;
113
    }
114
115
    /**
116
     * @param Entity $entity
117
     * @return string
118
     *
119
     * @throws BuilderException
120
     */
121
    protected function getPrimary(Entity $entity): string
122
    {
123
        foreach ($entity->getFields() as $name => $field) {
124
            if ($field->isPrimary()) {
125
                return $name;
126
            }
127
        }
128
129
        throw new BuilderException("Entity `{$entity->getRole()}` must have defined primary key");
130
    }
131
}