HasOne   A
last analyzed

Complexity

Total Complexity 9

Size/Duplication

Total Lines 106
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 50
dl 0
loc 106
ccs 30
cts 30
cp 1
rs 10
c 1
b 0
f 0
wmc 9

4 Methods

Rating   Name   Duplication   Size   Complexity  
A compute() 0 15 1
A render() 0 22 4
A inverseRelation() 0 14 3
A inverseTargets() 0 4 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cycle\Schema\Relation;
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\Traits\FieldTrait;
13
use Cycle\Schema\Relation\Traits\ForeignKeyTrait;
14
use Cycle\Schema\RelationInterface;
15
16
final class HasOne extends RelationSchema implements InversableInterface
17
{
18
    use FieldTrait;
19
    use ForeignKeyTrait;
20
21
    // internal relation type
22
    protected const RELATION_TYPE = Relation::HAS_ONE;
23
24
    // relation schema options
25
    protected const RELATION_SCHEMA = [
26
        // save with parent
27
        Relation::CASCADE => true,
28
29
        // do not pre-load relation by default
30
        Relation::LOAD => Relation::LOAD_PROMISE,
31
32
        // not nullable by default
33
        Relation::NULLABLE => false,
34
35
        // link to parent entity primary key by default
36
        Relation::INNER_KEY => '{source:primaryKey}',
37
38
        // default field name for inner key
39
        Relation::OUTER_KEY => '{source:role}_{innerKey}',
40
41
        // rendering options
42
        RelationSchema::INDEX_CREATE => true,
43
        RelationSchema::FK_CREATE => true,
44
        RelationSchema::FK_ACTION => 'CASCADE',
45
        RelationSchema::FK_ON_DELETE => null,
46
    ];
47
48
    public function compute(Registry $registry): void
49
    {
50 248
        parent::compute($registry);
51
52 248
        $source = $registry->getEntity($this->source);
53
        $target = $registry->getEntity($this->target);
54 232
55 232
        $this->normalizeContextFields($source, $target);
56
57 232
        // create target outer field
58
        $this->createRelatedFields(
59
            $source,
60 232
            Relation::INNER_KEY,
61
            $target,
62 232
            Relation::OUTER_KEY,
63
        );
64 232
    }
65
66 224
    public function render(Registry $registry): void
67
    {
68
        $source = $registry->getEntity($this->source);
69
        $target = $registry->getEntity($this->target);
70
71 80
        $targetTable = $registry->getTableSchema($target);
72
73 80
        $innerFields = $this->getFields($source, Relation::INNER_KEY);
74 80
        $outerFields = $this->getFields($target, Relation::OUTER_KEY);
75
76 80
        if ($this->options->get(self::INDEX_CREATE) && count($outerFields) > 0) {
77
            $targetTable->index($outerFields->getColumnNames());
78 80
        }
79 80
80
        if ($this->options->get(self::FK_CREATE)) {
81 80
            $this->createForeignCompositeKey(
82 80
                $registry,
83
                $source,
84
                $target,
85 80
                $innerFields,
86 64
                $outerFields,
87
                $this->options->get(self::INDEX_CREATE),
88 80
            );
89
        }
90
    }
91
92
    /**
93
     *
94
     * @return Entity[]
95 64
     */
96
    public function inverseTargets(Registry $registry): array
97
    {
98 64
        return [
99
            $registry->getEntity($this->target),
100
        ];
101
    }
102
103
    /**
104
     *
105
     * @throws RelationException
106
     *
107
     */
108
    public function inverseRelation(RelationInterface $relation, string $into, ?int $load = null): RelationInterface
109
    {
110
        if (!$relation instanceof BelongsTo && !$relation instanceof RefersTo) {
111 64
            throw new RelationException('HasOne relation can only be inversed into BelongsTo or RefersTo');
112
        }
113 64
114 16
        return $relation->withContext(
115
            $into,
116
            $this->target,
117 48
            $this->source,
118 48
            $this->options->withOptions([
119 48
                Relation::LOAD => $load,
120 48
                Relation::INNER_KEY => $this->options->get(Relation::OUTER_KEY),
121 48
                Relation::OUTER_KEY => $this->options->get(Relation::INNER_KEY),
122 48
            ]),
123 48
        );
124 48
    }
125
}
126