Issues (20)

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

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

75
            /** @scrutinizer ignore-type */ $this->options->get(Relation::NULLABLE)
Loading history...
76
        );
77
78
        $this->ensureMorphField(
79
            $source,
80
            $this->options->get(Relation::MORPH_KEY),
81
            $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

81
            /** @scrutinizer ignore-type */ $this->options->get(RelationSchema::MORPH_KEY_LENGTH),
Loading history...
82
            $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

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