Issues (590)

src/Relations/MorphTo.php (1 issue)

Labels
Severity
1
<?php
2
3
namespace Bdf\Prime\Relations;
4
5
use Bdf\Prime\Collection\Indexer\EntityIndexer;
6
use Bdf\Prime\Collection\Indexer\EntityIndexerInterface;
7
use Bdf\Prime\Query\Contract\EntityJoinable;
8
use Bdf\Prime\Query\Contract\ReadOperation;
9
use Bdf\Prime\Query\Contract\WriteOperation;
10
use Bdf\Prime\Query\ReadCommandInterface;
11
use InvalidArgumentException;
12
use LogicException;
13
14
/**
15
 * MorphTo
16
 */
17
class MorphTo extends BelongsTo
18
{
19
    /**
20
     * {@inheritdoc}
21
     *
22
     * The alias should have #[sub entity] at its end
23
     */
24 17
    public function join(EntityJoinable $query, string $alias): void
25
    {
26 17
        $parts = explode('#', $alias);
27
28 17
        if (!isset($parts[1])) {
29 3
            throw new LogicException('Joins are not supported on polymorph without discriminator');
30
        }
31
32 14
        $this->loadDistantFromType(end($parts));
33
34
        //TODO should be in join clause
35 14
        $query->where($this->getLocalAlias($query).$this->discriminator, $this->discriminatorValue);
36
37
        // Join to the real alias (i.e. without the discriminator)
38 14
        parent::join($query, $parts[0]);
39
    }
40
41
    /**
42
     * {@inheritdoc}
43
     */
44 14
    public function joinRepositories(EntityJoinable $query, string $alias, $discriminator = null): array
45
    {
46 14
        if ($discriminator === null) {
47
            throw new LogicException('Joins are not supported on polymorph without discriminator');
48
        }
49
50 14
        $this->loadDistantFromType($discriminator);
51
52 14
        return [
53 14
            $alias => $this->relationRepository()
54 14
        ];
55
    }
56
57
    /**
58
     * {@inheritdoc}
59
     */
60
    #[ReadOperation]
61 105
    public function load(EntityIndexerInterface $collection, array $with = [], $constraints = [], array $without = []): void
62
    {
63 105
        if ($collection->empty()) {
64 21
            return;
65
        }
66
67 96
        $with = $this->rearrangeWith($with);
68 96
        $without = $this->rearrangeWithout($without);
69
70 96
        foreach ($collection->by($this->discriminator) as $type => $chunk) {
71 96
            $this->loadDistantFromType($type);
72
73
            // Relation fk or discriminator is null : ignore the relation (same behavior as other relations)
74 96
            if ($this->distant === null || $this->distantKey === null) {
75 1
                continue;
76
            }
77
78 96
            parent::load(
79 96
                EntityIndexer::fromArray($this->local->mapper(), $chunk),
80 96
                $with[$type],
81 96
                $constraints,
82 96
                $without[$type]
83 96
            );
84
        }
85
    }
86
87
    /**
88
     * {@inheritdoc}
89
     *
90
     * @fixme Do not works with EntityCollection
91
     */
92 7
    public function link($owner): ReadCommandInterface
93
    {
94 7
        if (is_array($owner)) {
95
            throw new InvalidArgumentException('MorphTo relation do not supports querying on collection');
96
        }
97
98 7
        $this->loadDistantFrom($owner);
99
100 7
        if ($this->discriminatorValue === null) {
101 1
            throw new InvalidArgumentException('The discriminator is missing on the owner entity');
102
        }
103
104 7
        return parent::link($owner);
105
    }
106
107
    /**
108
     * {@inheritdoc}
109
     */
110 4
    public function associate($owner, $entity)
111
    {
112 4
        $this->loadDistantFromType($this->discriminator(get_class($entity)));
113
114 4
        return parent::associate($owner, $entity);
115
    }
116
117
    /**
118
     * {@inheritdoc}
119
     */
120
    #[WriteOperation]
121 13
    public function saveAll($owner, array $relations = []): int
122
    {
123 13
        $relations = $this->rearrangeWith($relations);
124 13
        $this->loadDistantFrom($owner);
125
126
        // No discriminator on the owner : there is no relation
127 13
        if ($this->discriminatorValue === null) {
128 1
            return 0;
129
        }
130
131 13
        return parent::saveAll($owner, $relations[$this->discriminatorValue]);
132
    }
133
134
    /**
135
     * {@inheritdoc}
136
     */
137
    #[WriteOperation]
138 13
    public function deleteAll($owner, array $relations = []): int
139
    {
140 13
        $relations = $this->rearrangeWith($relations);
141 13
        $this->loadDistantFrom($owner);
142
143
        // No discriminator on the owner : there is no relation
144 13
        if ($this->discriminatorValue === null) {
145 1
            return 0;
146
        }
147
148 13
        return parent::deleteAll($owner, $relations[$this->discriminatorValue]);
149
    }
150
151
    /**
152
     * Change the current discriminator value
153
     * and update the distant repository of this relation
154
     *
155
     * @param mixed $type
156
     *
157
     * @return void
158
     */
159 113
    protected function loadDistantFromType($type): void
160
    {
161 113
        $this->discriminatorValue = $type;
162
163 113
        $this->updateDistantInfos();
164
    }
165
166
    /**
167
     * Change the current discriminator value from the entity
168
     * and update the distant repository of this relation
169
     *
170
     * @param object $entity
171
     *
172
     * @return void
173
     */
174 31
    protected function loadDistantFrom($entity): void
175
    {
176 31
        $this->updateDiscriminatorValue($entity);
177
178 31
        $this->updateDistantInfos();
179
    }
180
181
    /**
182
     * Update the distant repository of this relation
183
     *
184
     * @return void
185
     */
186 119
    protected function updateDistantInfos(): void
187
    {
188 119
        $infos = $this->map($this->discriminatorValue);
189
190 119
        if ($infos) {
191 119
            $this->distant = $this->local->repository($infos['entity']);
192 119
            $this->distantKey = $infos['distantKey'];
193 119
            $this->setConstraints($infos['constraints'] ?? []);
194
        } else {
195 1
            $this->distant = null;
196 1
            $this->distantKey = null;
197
        }
198
    }
199
200
    /**
201
     * {@inheritdoc}
202
     */
203 96
    protected function relationQuery($keys, $constraints): ReadCommandInterface
204
    {
205 96
        return $this->query($keys, $constraints)->by($this->distantKey);
0 ignored issues
show
The method by() does not exist on Bdf\Prime\Query\QueryInterface. It seems like you code against a sub-type of said class. However, the method does not exist in Bdf\Prime\Query\SqlQueryInterface. Are you sure you never get one of those? ( Ignorable by Annotation )

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

205
        return $this->query($keys, $constraints)->/** @scrutinizer ignore-call */ by($this->distantKey);
Loading history...
206
    }
207
}
208