Passed
Push — master ( 384538...4f7dc7 )
by Anton
02:27
created

src/Relation/HasMany.php (1 issue)

Labels
Severity
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\Exception\RelationException;
14
use Cycle\Schema\InversableInterface;
15
use Cycle\Schema\Registry;
16
use Cycle\Schema\Relation\Traits\FieldTrait;
17
use Cycle\Schema\Relation\Traits\ForeignKeyTrait;
18
use Cycle\Schema\RelationInterface;
19
20
class HasMany extends RelationSchema implements InversableInterface
21
{
22
    use FieldTrait, ForeignKeyTrait;
23
24
    // internal relation type
25
    protected const RELATION_TYPE = Relation::HAS_MANY;
26
27
    // relation schema options
28
    protected const RELATION_SCHEMA = [
29
        // save with parent
30
        Relation::CASCADE            => true,
31
32
        // custom where condition
33
        Relation::WHERE              => [],
34
35
        // not nullable by default
36
        Relation::NULLABLE           => false,
37
38
        // link to parent entity primary key by default
39
        Relation::INNER_KEY          => '{source:primaryKey}',
40
41
        // default field name for inner key
42
        Relation::OUTER_KEY          => '{source:role}_{innerKey}',
43
44
        // rendering options
45
        RelationSchema::INDEX_CREATE => true,
46
        RelationSchema::FK_CREATE    => true,
47
        RelationSchema::FK_ACTION    => 'CASCADE'
48
    ];
49
50
    /**
51
     * @param Registry $registry
52
     */
53
    public function compute(Registry $registry)
54
    {
55
        parent::compute($registry);
56
57
        $source = $registry->getEntity($this->source);
58
        $target = $registry->getEntity($this->target);
59
60
        // create target outer field
61
        $this->ensureField(
62
            $target,
63
            $this->options->get(Relation::OUTER_KEY),
64
            $this->getField($source, Relation::INNER_KEY),
65
            $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\HasMany::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

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