Passed
Push — master ( b9a837...4518ef )
by Anton
01:49
created

AbstractSchema::packSchema()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 3
nop 0
dl 0
loc 16
rs 9.9666
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
abstract class AbstractSchema implements RelationInterface
20
{
21
    // exported relation type
22
    protected const RELATION_TYPE = null;
23
24
    // name of all required relation options
25
    protected const OPTION_SCHEMA = [];
26
27
    // options to be excluded from generated schema
28
    protected const EXCLUDE = [];
29
30
    /** @var string */
31
    protected $source;
32
33
    /** @var string */
34
    protected $target;
35
36
    /** @var OptionSchema */
37
    protected $options;
38
39
    /**
40
     * @inheritdoc
41
     */
42
    public function withContext(string $name, string $source, string $target, OptionSchema $options): RelationInterface
43
    {
44
        $relation = clone $this;
45
        $relation->source = $source;
46
        $relation->target = $target;
47
48
        $relation->options = $options->withTemplate(static::OPTION_SCHEMA)->withContext([
49
            'relation'    => $name,
50
            'source:role' => $source,
51
            'target:role' => $target
52
        ]);
53
54
        return $relation;
55
    }
56
57
    /**
58
     * @param Registry $registry
59
     */
60
    public function compute(Registry $registry)
61
    {
62
        $this->options = $this->options->withContext([
63
            'source:primaryKey' => $this->getPrimary($registry->getEntity($this->source))
64
        ]);
65
66
        if ($registry->hasRole($this->target)) {
67
            $this->options = $this->options->withContext([
68
                'target:primaryKey' => $this->getPrimary($registry->getEntity($this->target))
69
            ]);
70
        }
71
    }
72
73
    /**
74
     * @return array
75
     */
76
    public function packSchema(): array
77
    {
78
        $schema = [];
79
80
        foreach (static::OPTION_SCHEMA as $option => $template) {
81
            if (in_array($option, static::EXCLUDE)) {
82
                continue;
83
            }
84
85
            $schema[$option] = $this->options->get($option);
86
        }
87
88
        return [
89
            Relation::TYPE   => static::RELATION_TYPE,
90
            Relation::TARGET => $this->target,
91
            Relation::SCHEMA => $schema
92
        ];
93
    }
94
95
    /**
96
     * @return OptionSchema
97
     */
98
    protected function getOptions(): OptionSchema
99
    {
100
        return $this->options;
101
    }
102
103
    /**
104
     * @param Entity $entity
105
     * @return string
106
     *
107
     * @throws BuilderException
108
     */
109
    protected function getPrimary(Entity $entity): string
110
    {
111
        foreach ($entity->getFields() as $name => $field) {
112
            if ($field->isPrimary()) {
113
                return $name;
114
            }
115
        }
116
117
        throw new BuilderException("Entity `{$entity->getRole()}` must have defined primary key");
118
    }
119
}