Issues (20)

src/Relation/Morphed/BelongsToMorphed.php (3 issues)

Labels
Severity
1
<?php
2
3
/**
4
 * Cycle ORM Schema Builder.
5
 *
6
 * @license   MIT
7
 * @author    Anton Titov (Wolfy-J)
8
 */
9
10
declare(strict_types=1);
11
12
namespace Cycle\Schema\Relation\Morphed;
13
14
use Cycle\ORM\Relation;
15
use Cycle\Schema\Exception\RelationException;
16
use Cycle\Schema\InversableInterface;
17
use Cycle\Schema\Registry;
18
use Cycle\Schema\Relation\RelationSchema;
19
use Cycle\Schema\Relation\Traits\FieldTrait;
20
use Cycle\Schema\Relation\Traits\MorphTrait;
21
use Cycle\Schema\RelationInterface;
22
23
final class BelongsToMorphed extends RelationSchema implements InversableInterface
24
{
25
    use FieldTrait;
26
    use MorphTrait;
27
28
    // internal relation type
29
    protected const RELATION_TYPE = Relation::BELONGS_TO_MORPHED;
30
31
    // relation schema options
32
    protected const RELATION_SCHEMA = [
33
        // save with parent
34
        Relation::CASCADE                => true,
35
36
        // do not pre-load relation by default
37
        Relation::LOAD                   => Relation::LOAD_PROMISE,
38
39
        // nullable by default
40
        Relation::NULLABLE               => true,
41
42
        // default field name for inner key
43
        Relation::OUTER_KEY              => '{target:primaryKey}',
44
45
        // link to parent entity primary key by default
46
        Relation::INNER_KEY              => '{relation}_{outerKey}',
47
48
        // link to parent entity primary key by default
49
        Relation::MORPH_KEY              => '{relation}_role',
50
51
        // rendering options
52
        RelationSchema::INDEX_CREATE     => true,
53
        RelationSchema::MORPH_KEY_LENGTH => 32
54
    ];
55
56
    /**
57
     * @param Registry $registry
58
     */
59
    public function compute(Registry $registry): void
60
    {
61
        // compute local key
62
        $this->options = $this->options->withContext([
63
            'source:primaryKey' => $this->getPrimary($registry->getEntity($this->source))
64
        ]);
65
66
        $source = $registry->getEntity($this->source);
67
68
        list($outerKey, $outerField) = $this->findOuterKey($registry, $this->target);
69
70
        // register primary key reference
71
        $this->options = $this->options->withContext(['target:primaryKey' => $outerKey]);
72
73
        // create target outer field
74
        $this->ensureField(
75
            $source,
76
            $this->options->get(Relation::INNER_KEY),
77
            $outerField,
78
            $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\Mo...oMorphed::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

78
            /** @scrutinizer ignore-type */ $this->options->get(Relation::NULLABLE)
Loading history...
79
        );
80
81
        $this->ensureMorphField(
82
            $source,
83
            $this->options->get(Relation::MORPH_KEY),
84
            $this->options->get(RelationSchema::MORPH_KEY_LENGTH),
0 ignored issues
show
It seems like $this->options->get(Cycl...hema::MORPH_KEY_LENGTH) can also be of type string; however, parameter $lenght of Cycle\Schema\Relation\Mo...hed::ensureMorphField() does only seem to accept integer, 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

84
            /** @scrutinizer ignore-type */ $this->options->get(RelationSchema::MORPH_KEY_LENGTH),
Loading history...
85
            $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\Mo...hed::ensureMorphField() 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

85
            /** @scrutinizer ignore-type */ $this->options->get(Relation::NULLABLE)
Loading history...
86
        );
87
    }
88
89
    /**
90
     * @param Registry $registry
91
     */
92
    public function render(Registry $registry): void
93
    {
94
        $source = $registry->getEntity($this->source);
95
96
        $innerField = $this->getField($source, Relation::INNER_KEY);
97
        $morphField = $this->getField($source, Relation::MORPH_KEY);
98
99
        $table = $registry->getTableSchema($source);
100
101
        if ($this->options->get(self::INDEX_CREATE)) {
102
            $table->index([$innerField->getColumn(), $morphField->getColumn()]);
103
        }
104
    }
105
106
    /**
107
     * @param Registry $registry
108
     * @return array
109
     */
110
    public function inverseTargets(Registry $registry): array
111
    {
112
        return iterator_to_array($this->findTargets($registry, $this->target));
113
    }
114
115
    /**
116
     * @param RelationInterface $relation
117
     * @param string            $into
118
     * @param int|null          $load
119
     * @return RelationInterface
120
     *
121
     * @throws RelationException
122
     */
123
    public function inverseRelation(RelationInterface $relation, string $into, ?int $load = null): RelationInterface
124
    {
125
        if (!$relation instanceof MorphedHasOne && !$relation instanceof MorphedHasMany) {
126
            throw new RelationException(
127
                'BelongsToMorphed relation can only be inversed into MorphedHasOne or MorphedHasMany'
128
            );
129
        }
130
131
        return $relation->withContext(
132
            $into,
133
            $this->target,
134
            $this->source,
135
            $this->options->withOptions([
136
                Relation::LOAD      => $load,
137
                Relation::INNER_KEY => $this->options->get(Relation::OUTER_KEY),
138
                Relation::OUTER_KEY => $this->options->get(Relation::INNER_KEY),
139
            ])
140
        );
141
    }
142
}
143