BelongsToMorphed::compute()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 36
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 20
nc 4
nop 1
dl 0
loc 36
ccs 14
cts 14
cp 1
crap 3
rs 9.6
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cycle\Schema\Relation\Morphed;
6
7
use Cycle\ORM\Relation;
8
use Cycle\Schema\Definition\Entity;
9
use Cycle\Schema\Exception\RelationException;
10
use Cycle\Schema\InversableInterface;
11
use Cycle\Schema\Registry;
12
use Cycle\Schema\Relation\RelationSchema;
13
use Cycle\Schema\Relation\Traits\FieldTrait;
14
use Cycle\Schema\Relation\Traits\MorphTrait;
15
use Cycle\Schema\RelationInterface;
16
17
final class BelongsToMorphed extends RelationSchema implements InversableInterface
18
{
19
    use FieldTrait;
20
    use MorphTrait;
21
22
    // internal relation type
23
    protected const RELATION_TYPE = Relation::BELONGS_TO_MORPHED;
24
25
    // relation schema options
26
    protected const RELATION_SCHEMA = [
27
        // save with parent
28
        Relation::CASCADE => true,
29
30
        // do not pre-load relation by default
31
        Relation::LOAD => Relation::LOAD_PROMISE,
32
33
        // nullable by default
34
        Relation::NULLABLE => true,
35
36
        // default field name for inner key
37
        Relation::OUTER_KEY => '{target:primaryKey}',
38
39
        // link to parent entity primary key by default
40
        Relation::INNER_KEY => '{relation}_{outerKey}',
41
42
        // link to parent entity primary key by default
43
        Relation::MORPH_KEY => '{relation}_role',
44
45
        // rendering options
46
        RelationSchema::INDEX_CREATE => true,
47
        RelationSchema::MORPH_KEY_LENGTH => 32,
48
    ];
49
50
    public function compute(Registry $registry): void
51
    {
52 112
        // compute local key
53
        $this->options = $this->options->withContext([
54
            'source:primaryKey' => $this->getPrimaryColumns($registry->getEntity($this->source)),
55 112
        ]);
56 112
57
        $source = $registry->getEntity($this->source);
58
59 112
        [$outerKeys, $outerFields] = $this->findOuterKey($registry, $this->target);
60
61 112
        // register primary key reference
62
        $this->options = $this->options->withContext([
63
            'target:primaryKey' => $outerKeys,
64 96
        ]);
65 96
66
        $outerKeys = array_combine($outerKeys, (array) $this->options->get(Relation::INNER_KEY));
67
68 96
        // create target outer field
69
        foreach ($outerKeys as $key => $morphKey) {
70
            $outerField = $outerFields->get($key);
71 96
72 96
            $this->ensureField(
73
                $source,
74 96
                $morphKey,
75
                $outerField,
76
                $this->options->get(Relation::NULLABLE),
77
            );
78 96
        }
79
80
        foreach ((array) $this->options->get(Relation::MORPH_KEY) as $key) {
81
            $this->ensureMorphField(
82 96
                $source,
83 96
                $key,
84
                $this->options->get(RelationSchema::MORPH_KEY_LENGTH),
85
                $this->options->get(Relation::NULLABLE),
86 96
            );
87 96
        }
88
    }
89
90 96
    public function render(Registry $registry): void
91
    {
92 16
        $source = $registry->getEntity($this->source);
93
        $innerFields = $this->getFields($source, Relation::INNER_KEY);
94 16
        $morphFields = $this->getFields($source, Relation::MORPH_KEY);
95 16
96 16
        $this->mergeIndex($registry, $source, $innerFields, $morphFields);
97
    }
98 16
99 16
    /**
100
     *
101
     * @return Entity[]
102
     */
103
    public function inverseTargets(Registry $registry): array
104
    {
105
        return iterator_to_array($this->findTargets($registry, $this->target));
106 48
    }
107
108 48
    /**
109
     *
110
     * @throws RelationException
111
     *
112
     */
113
    public function inverseRelation(RelationInterface $relation, string $into, ?int $load = null): RelationInterface
114
    {
115
        if (!$relation instanceof MorphedHasOne && !$relation instanceof MorphedHasMany) {
116
            throw new RelationException(
117
                'BelongsToMorphed relation can only be inversed into MorphedHasOne or MorphedHasMany',
118
            );
119
        }
120 48
121
        return $relation->withContext(
122 48
            $into,
123 16
            $this->target,
124 16
            $this->source,
125
            $this->options->withOptions([
126
                Relation::LOAD => $load,
127
                Relation::INNER_KEY => $this->options->get(Relation::OUTER_KEY),
128 32
                Relation::OUTER_KEY => $this->options->get(Relation::INNER_KEY),
129 32
            ]),
130 32
        );
131 32
    }
132
}
133