Passed
Push — master ( b23be7...384538 )
by Anton
03:44
created

RelationSchema::withContext()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

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