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
Bug
introduced
by
![]() |
|||
206 | } |
||
207 | } |
||
208 |