Passed
Push — master ( 1791d6...48fae4 )
by Anton
01:59
created

src/Relation/HasOne.php (1 issue)

Labels
Severity
1
<?php declare(strict_types=1);
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license   MIT
6
 * @author    Anton Titov (Wolfy-J)
7
 */
8
9
namespace Cycle\Schema\Relation;
10
11
use Cycle\ORM\Relation;
12
use Cycle\Schema\Exception\RelationException;
13
use Cycle\Schema\InversableInterface;
14
use Cycle\Schema\Registry;
15
use Cycle\Schema\Relation\Traits\FieldTrait;
16
use Cycle\Schema\Relation\Traits\ForeignKeyTrait;
17
use Cycle\Schema\RelationInterface;
18
19
final class HasOne extends RelationSchema implements InversableInterface
20
{
21
    use FieldTrait, ForeignKeyTrait;
22
23
    // internal relation type
24
    protected const RELATION_TYPE = Relation::HAS_ONE;
25
26
    // relation schema options
27
    protected const RELATION_SCHEMA = [
28
        // save with parent
29
        Relation::CASCADE            => true,
30
31
        // use outer entity constrain by default
32
        Relation::CONSTRAIN          => true,
33
34
        // not nullable by default
35
        Relation::NULLABLE           => false,
36
37
        // link to parent entity primary key by default
38
        Relation::INNER_KEY          => '{source:primaryKey}',
39
40
        // default field name for inner key
41
        Relation::OUTER_KEY          => '{source:role}_{innerKey}',
42
43
        // rendering options
44
        RelationSchema::INDEX_CREATE => true,
45
        RelationSchema::FK_CREATE    => true,
46
        RelationSchema::FK_ACTION    => 'CASCADE'
47
    ];
48
49
    /**
50
     * @param Registry $registry
51
     */
52
    public function compute(Registry $registry)
53
    {
54
        parent::compute($registry);
55
56
        $source = $registry->getEntity($this->source);
57
        $target = $registry->getEntity($this->target);
58
59
        // create target outer field
60
        $this->ensureField(
61
            $target,
62
            $this->options->get(Relation::OUTER_KEY),
63
            $this->getField($source, Relation::INNER_KEY),
64
            $this->options->get(Relation::NULLABLE)
0 ignored issues
show
It seems like $this->options->get(Cycle\ORM\Relation::NULLABLE) can also be of type string; however, parameter $nullable of Cycle\Schema\Relation\HasOne::ensureField() does only seem to accept boolean, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

64
            /** @scrutinizer ignore-type */ $this->options->get(Relation::NULLABLE)
Loading history...
65
        );
66
    }
67
68
    /**
69
     * @param Registry $registry
70
     */
71
    public function render(Registry $registry)
72
    {
73
        $source = $registry->getEntity($this->source);
74
        $target = $registry->getEntity($this->target);
75
76
        $innerField = $this->getField($source, Relation::INNER_KEY);
77
        $outerField = $this->getField($target, Relation::OUTER_KEY);
78
79
        $table = $registry->getTableSchema($target);
80
81
        if ($this->options->get(self::INDEX_CREATE)) {
82
            $table->index([$outerField->getColumn()]);
83
        }
84
85
        if ($this->options->get(self::FK_CREATE)) {
86
            $this->createForeignKey($registry, $source, $target, $innerField, $outerField);
87
        }
88
    }
89
90
    /**
91
     * @param Registry $registry
92
     * @return array
93
     */
94
    public function inverseTargets(Registry $registry): array
95
    {
96
        return [
97
            $registry->getEntity($this->target)
98
        ];
99
    }
100
101
    /**
102
     * @param RelationInterface $relation
103
     * @param string            $into
104
     * @return RelationInterface
105
     *
106
     * @throws RelationException
107
     */
108
    public function inverseRelation(RelationInterface $relation, string $into): RelationInterface
109
    {
110
        if (!$relation instanceof BelongsTo && !$relation instanceof RefersTo) {
111
            throw new RelationException("HasOne relation can only be inversed into BelongsTo or RefersTo");
112
        }
113
114
        return $relation->withContext(
115
            $into,
116
            $this->target,
117
            $this->source,
118
            $this->options->withOptions([
119
                Relation::INNER_KEY => $this->options->get(Relation::OUTER_KEY),
120
                Relation::OUTER_KEY => $this->options->get(Relation::INNER_KEY),
121
            ])
122
        );
123
    }
124
}