1 | <?php |
||||
2 | |||||
3 | namespace Bdf\Prime\Relations; |
||||
4 | |||||
5 | use Bdf\Prime\Exception\PrimeException; |
||||
6 | use Bdf\Prime\Query\Contract\Deletable; |
||||
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\Custom\KeyValue\KeyValueQuery; |
||||
11 | use Bdf\Prime\Query\QueryInterface; |
||||
12 | use Bdf\Prime\Query\ReadCommandInterface; |
||||
13 | use Bdf\Prime\Repository\EntityRepository; |
||||
14 | use Bdf\Prime\Repository\RepositoryInterface; |
||||
15 | |||||
16 | /** |
||||
17 | * BelongsToMany |
||||
18 | * |
||||
19 | * For a relation named 'relation' use the prefix 'relationThrough.' for adding constraints on through table. |
||||
20 | * ex: |
||||
21 | * |
||||
22 | * <code> |
||||
23 | * $query->with([ |
||||
24 | * 'relation' => [ |
||||
25 | * 'name :like' => '...', |
||||
26 | * 'relationThrough.status' => '...' // through constraint |
||||
27 | * ] |
||||
28 | * ]); |
||||
29 | * </code> |
||||
30 | * |
||||
31 | * @package Bdf\Prime\Relations |
||||
32 | * |
||||
33 | * @todo Voir pour gérer la table de through dynamiquement. Si cette relation est une HasManyThrough, elle doit etre en readonly |
||||
34 | * |
||||
35 | * @template L as object |
||||
36 | * @template R as object |
||||
37 | * |
||||
38 | * @extends Relation<L, R> |
||||
39 | */ |
||||
40 | class BelongsToMany extends Relation |
||||
41 | { |
||||
42 | /** |
||||
43 | * Through repository |
||||
44 | * |
||||
45 | * @var EntityRepository |
||||
46 | */ |
||||
47 | protected $through; |
||||
48 | |||||
49 | /** |
||||
50 | * Through local key |
||||
51 | * |
||||
52 | * @var string |
||||
53 | */ |
||||
54 | protected $throughLocal; |
||||
55 | |||||
56 | /** |
||||
57 | * Through distant key |
||||
58 | * |
||||
59 | * @var string |
||||
60 | */ |
||||
61 | protected $throughDistant; |
||||
62 | |||||
63 | /** |
||||
64 | * The through global constraints |
||||
65 | * |
||||
66 | * @var array |
||||
67 | */ |
||||
68 | protected $throughConstraints = []; |
||||
69 | |||||
70 | /** |
||||
71 | * Merge of all constraints |
||||
72 | * |
||||
73 | * @var array |
||||
74 | */ |
||||
75 | protected $allConstraints = []; |
||||
76 | |||||
77 | /** |
||||
78 | * {@inheritdoc} |
||||
79 | */ |
||||
80 | protected $saveStrategy = self::SAVE_STRATEGY_REPLACE; |
||||
81 | |||||
82 | //=============================== |
||||
83 | // Save queries for optimisation |
||||
84 | //=============================== |
||||
85 | |||||
86 | /** |
||||
87 | * @var KeyValueQuery |
||||
88 | */ |
||||
89 | private $throughQuery; |
||||
90 | |||||
91 | /** |
||||
92 | * @var KeyValueQuery |
||||
93 | */ |
||||
94 | private $relationQuery; |
||||
95 | |||||
96 | |||||
97 | /** |
||||
98 | * {@inheritdoc} |
||||
99 | */ |
||||
100 | 22 | public function relationRepository(): RepositoryInterface |
|||
101 | { |
||||
102 | 22 | return $this->distant; |
|||
103 | } |
||||
104 | |||||
105 | /** |
||||
106 | * Set the though infos |
||||
107 | * |
||||
108 | * @param RepositoryInterface $through |
||||
109 | * @param string $throughLocal |
||||
110 | * @param string $throughDistant |
||||
111 | * |
||||
112 | * @return void |
||||
113 | */ |
||||
114 | 32 | public function setThrough(RepositoryInterface $through, string $throughLocal, string $throughDistant): void |
|||
115 | { |
||||
116 | 32 | $this->through = $through; |
|||
0 ignored issues
–
show
|
|||||
117 | 32 | $this->throughLocal = $throughLocal; |
|||
118 | 32 | $this->throughDistant = $throughDistant; |
|||
119 | } |
||||
120 | |||||
121 | /** |
||||
122 | * {@inheritdoc} |
||||
123 | */ |
||||
124 | public function setConstraints($constraints) |
||||
125 | { |
||||
126 | $this->allConstraints = $constraints; |
||||
127 | |||||
128 | list($this->constraints, $this->throughConstraints) = $this->extractConstraints($constraints); |
||||
129 | |||||
130 | return $this; |
||||
131 | } |
||||
132 | |||||
133 | /** |
||||
134 | * Extract constraints design for through queries |
||||
135 | * |
||||
136 | * @param array|\Closure $constraints |
||||
137 | * |
||||
138 | * @return array |
||||
139 | */ |
||||
140 | 23 | protected function extractConstraints($constraints) |
|||
141 | { |
||||
142 | 23 | if (!is_array($constraints)) { |
|||
143 | return [$constraints, []]; |
||||
144 | } |
||||
145 | |||||
146 | 23 | $through = []; |
|||
147 | 23 | $global = []; |
|||
148 | 23 | $prefix = $this->attributeAim.'Through.'; |
|||
149 | 23 | $length = strlen($prefix); |
|||
150 | |||||
151 | 23 | foreach ($constraints as $column => $value) { |
|||
152 | 6 | if (strpos($column, $prefix) === 0) { |
|||
153 | 3 | $through[substr($column, $length)] = $value; |
|||
154 | } else { |
||||
155 | 3 | $global[$column] = $value; |
|||
156 | } |
||||
157 | } |
||||
158 | |||||
159 | 23 | return [$global, $through]; |
|||
160 | } |
||||
161 | |||||
162 | /** |
||||
163 | * {@inheritdoc} |
||||
164 | */ |
||||
165 | 3 | public function join(EntityJoinable $query, string $alias): void |
|||
166 | { |
||||
167 | // @fixme ?? |
||||
168 | // if ($alias === null) { |
||||
169 | // $alias = $this->attributeAim; |
||||
170 | // } |
||||
171 | |||||
172 | // TODO rechercher l'alias de through dans les tables alias du query builder |
||||
173 | |||||
174 | 3 | $query->joinEntity($this->through->entityName(), $this->throughLocal, $this->getLocalAlias($query).$this->localKey, $this->attributeAim.'Through'); |
|||
175 | 3 | $query->joinEntity($this->distant->entityName(), $this->distantKey, $this->attributeAim.'Through>'.$this->throughDistant, $alias); |
|||
176 | |||||
177 | 3 | $this->applyConstraints($query, [], $alias); |
|||
178 | 3 | $this->applyThroughConstraints($query, [], $this->attributeAim.'Through'); |
|||
179 | } |
||||
180 | |||||
181 | /** |
||||
182 | * {@inheritdoc} |
||||
183 | */ |
||||
184 | 3 | public function joinRepositories(EntityJoinable $query, string $alias, $discriminator = null): array |
|||
185 | { |
||||
186 | 3 | return [ |
|||
187 | 3 | $this->attributeAim.'Through' => $this->through, |
|||
188 | 3 | $alias => $this->distant, |
|||
189 | 3 | ]; |
|||
190 | } |
||||
191 | |||||
192 | /** |
||||
193 | * {@inheritdoc} |
||||
194 | */ |
||||
195 | 19 | public function link($owner): ReadCommandInterface |
|||
196 | { |
||||
197 | /** @var QueryInterface<\Bdf\Prime\Connection\ConnectionInterface, R>&EntityJoinable $query */ |
||||
198 | 19 | $query = $this->distant->queries()->builder(); |
|||
199 | |||||
200 | 19 | return $query |
|||
201 | 19 | ->joinEntity($this->through->entityName(), $this->throughDistant, $this->distantKey, $this->attributeAim.'Through') |
|||
0 ignored issues
–
show
The method
joinEntity() does not exist on Bdf\Prime\Query\QueryInterface . Since it exists in all sub-types, consider adding an abstract or default implementation to Bdf\Prime\Query\QueryInterface .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
202 | 19 | ->where($this->attributeAim.'Through.'.$this->throughLocal, $this->getLocalKeyValue($owner)) |
|||
203 | 19 | ->where($this->allConstraints) |
|||
204 | 19 | ; |
|||
205 | } |
||||
206 | |||||
207 | /** |
||||
208 | * Get a query from through entity repository |
||||
209 | * |
||||
210 | * @param string|array $key |
||||
211 | * @param array $constraints |
||||
212 | * |
||||
213 | * @return ReadCommandInterface&Deletable |
||||
214 | */ |
||||
215 | 28 | protected function throughQuery($key, $constraints = []): ReadCommandInterface |
|||
216 | { |
||||
217 | 28 | if (is_array($key)) { |
|||
218 | 23 | if (count($key) !== 1 || $constraints || $this->throughConstraints) { |
|||
0 ignored issues
–
show
The expression
$constraints of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() The expression
$this->throughConstraints of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||
219 | 3 | return $this->applyThroughConstraints( |
|||
220 | 3 | $this->through->where($this->throughLocal, $key), |
|||
221 | 3 | $constraints |
|||
222 | 3 | ); |
|||
223 | } |
||||
224 | |||||
225 | 20 | $key = $key[0]; |
|||
226 | } |
||||
227 | |||||
228 | 25 | if ($this->throughQuery) { |
|||
229 | 10 | return $this->throughQuery->where($this->throughLocal, $key); |
|||
230 | } |
||||
231 | |||||
232 | 15 | $this->throughQuery = $this->through->queries()->keyValue($this->throughLocal, $key); |
|||
233 | |||||
234 | 15 | if ($this->throughQuery) { |
|||
235 | 15 | return $this->throughQuery; |
|||
236 | } |
||||
237 | |||||
238 | return $this->applyThroughConstraints( |
||||
239 | $this->through->where($this->throughLocal, $key), |
||||
240 | $constraints |
||||
241 | ); |
||||
242 | } |
||||
243 | |||||
244 | /** |
||||
245 | * Build the query for find related entities |
||||
246 | */ |
||||
247 | 23 | protected function relationQuery(array $keys, $constraints): ReadCommandInterface |
|||
248 | { |
||||
249 | // Constraints can be on relation attributes : builder must be used |
||||
250 | // @todo Handle "bulk select" |
||||
251 | 23 | if (count($keys) !== 1 || $constraints || $this->constraints) { |
|||
0 ignored issues
–
show
The expression
$this->constraints of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||
252 | 14 | 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
![]() |
|||||
253 | } |
||||
254 | |||||
255 | 9 | if ($this->relationQuery) { |
|||
256 | 1 | return $this->relationQuery->where($this->distantKey, reset($keys)); |
|||
257 | } |
||||
258 | |||||
259 | 8 | $query = $this->distant->queries()->keyValue($this->distantKey, reset($keys)); |
|||
260 | |||||
261 | 8 | if (!$query) { |
|||
0 ignored issues
–
show
|
|||||
262 | return $this->query($keys, $constraints)->by($this->distantKey); |
||||
263 | } |
||||
264 | |||||
265 | 8 | return $this->relationQuery = $query->by($this->distantKey); |
|||
0 ignored issues
–
show
The method
by() does not exist on Bdf\Prime\Query\Contract...\KeyValueQueryInterface . Since it exists in all sub-types, consider adding an abstract or default implementation to Bdf\Prime\Query\Contract...\KeyValueQueryInterface .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
266 | } |
||||
267 | |||||
268 | /** |
||||
269 | * Apply the through constraints |
||||
270 | * |
||||
271 | * @param Q $query |
||||
0 ignored issues
–
show
The type
Bdf\Prime\Relations\Q was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||||
272 | * @param array $constraints |
||||
273 | * @param string|null $context |
||||
274 | * |
||||
275 | * @return Q |
||||
276 | * |
||||
277 | * @template Q as ReadCommandInterface<\Bdf\Prime\Connection\ConnectionInterface, object>&\Bdf\Prime\Query\Contract\Whereable |
||||
278 | */ |
||||
279 | 6 | protected function applyThroughConstraints(ReadCommandInterface $query, $constraints = [], ?string $context = null): ReadCommandInterface |
|||
280 | { |
||||
281 | 6 | return $query->where($this->applyContext($context, $constraints + $this->throughConstraints)); |
|||
0 ignored issues
–
show
The method
where() does not exist on Bdf\Prime\Query\ReadCommandInterface . Since it exists in all sub-types, consider adding an abstract or default implementation to Bdf\Prime\Query\ReadCommandInterface .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
282 | } |
||||
283 | |||||
284 | /** |
||||
285 | * {@inheritdoc} |
||||
286 | */ |
||||
287 | #[ReadOperation] |
||||
288 | 23 | protected function relations($keys, $with, $constraints, $without): array |
|||
289 | { |
||||
290 | 23 | list($constraints, $throughConstraints) = $this->extractConstraints($constraints); |
|||
291 | |||||
292 | 23 | $throughEntities = []; |
|||
293 | 23 | $throughDistants = []; |
|||
294 | |||||
295 | 23 | $collection = $this->throughQuery($keys, $throughConstraints)->execute([ |
|||
296 | 23 | $this->throughLocal => $this->throughLocal, |
|||
297 | 23 | $this->throughDistant => $this->throughDistant, |
|||
298 | 23 | ]); |
|||
299 | |||||
300 | 23 | foreach ($collection as $entity) { |
|||
301 | 23 | $throughLocal = $entity[$this->throughLocal]; |
|||
302 | 23 | $throughDistant = $entity[$this->throughDistant]; |
|||
303 | |||||
304 | 23 | $throughDistants[$throughDistant] = $throughDistant; |
|||
305 | 23 | $throughEntities[$throughLocal][$throughDistant] = $throughDistant; |
|||
306 | } |
||||
307 | |||||
308 | 23 | $relations = $this->relationQuery($throughDistants, $constraints) |
|||
309 | 23 | ->with($with) |
|||
0 ignored issues
–
show
The method
with() does not exist on Bdf\Prime\Query\Custom\KeyValue\KeyValueQuery . Since you implemented __call , consider adding a @method annotation.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
310 | 23 | ->without($without) |
|||
311 | 23 | ->all(); |
|||
312 | |||||
313 | 23 | return [ |
|||
314 | 23 | 'throughEntities' => $throughEntities, |
|||
315 | 23 | 'entities' => $relations, |
|||
316 | 23 | ]; |
|||
317 | } |
||||
318 | |||||
319 | /** |
||||
320 | * {@inheritdoc} |
||||
321 | */ |
||||
322 | 23 | protected function match($collection, $relations): void |
|||
323 | { |
||||
324 | 23 | foreach ($relations['throughEntities'] as $key => $throughDistants) { |
|||
325 | 23 | $entities = []; |
|||
326 | |||||
327 | 23 | foreach ($throughDistants as $throughDistant) { |
|||
328 | 23 | if (isset($relations['entities'][$throughDistant])) { |
|||
329 | 23 | $entities[] = $relations['entities'][$throughDistant]; |
|||
330 | } |
||||
331 | } |
||||
332 | |||||
333 | 23 | if (empty($entities)) { |
|||
334 | continue; |
||||
335 | } |
||||
336 | |||||
337 | 23 | foreach ($collection[$key] as $local) { |
|||
338 | 23 | $this->setRelation($local, $entities); |
|||
339 | } |
||||
340 | } |
||||
341 | } |
||||
342 | |||||
343 | /** |
||||
344 | * {@inheritdoc} |
||||
345 | * |
||||
346 | * @throws PrimeException |
||||
347 | */ |
||||
348 | #[WriteOperation] |
||||
349 | 3 | public function associate($owner, $entity) |
|||
350 | { |
||||
351 | 3 | $this->attach($owner, $entity); |
|||
352 | |||||
353 | 3 | return $owner; |
|||
354 | } |
||||
355 | |||||
356 | /** |
||||
357 | * {@inheritdoc} |
||||
358 | * |
||||
359 | * @throws PrimeException |
||||
360 | */ |
||||
361 | #[WriteOperation] |
||||
362 | 4 | public function dissociate($owner) |
|||
363 | { |
||||
364 | 4 | $this->detach($owner, $this->getRelation($owner)); |
|||
365 | |||||
366 | 4 | return $owner; |
|||
367 | } |
||||
368 | |||||
369 | /** |
||||
370 | * {@inheritdoc} |
||||
371 | * |
||||
372 | * @throws PrimeException |
||||
373 | */ |
||||
374 | 3 | public function create($owner, array $data = []) |
|||
375 | { |
||||
376 | 3 | $entity = $this->distant->entity($data); |
|||
377 | |||||
378 | 3 | $this->distant->save($entity); |
|||
379 | |||||
380 | 3 | $this->add($owner, $entity); |
|||
381 | |||||
382 | 3 | return $entity; |
|||
383 | } |
||||
384 | |||||
385 | /** |
||||
386 | * {@inheritdoc} |
||||
387 | */ |
||||
388 | #[WriteOperation] |
||||
389 | 3 | public function add($owner, $related): int |
|||
390 | { |
||||
391 | 3 | return $this->attach($owner, $related); |
|||
392 | } |
||||
393 | |||||
394 | /** |
||||
395 | * {@inheritdoc} |
||||
396 | */ |
||||
397 | #[WriteOperation] |
||||
398 | 5 | public function saveAll($owner, array $relations = []): int |
|||
399 | { |
||||
400 | //Detach all relations |
||||
401 | 5 | if ($this->saveStrategy === self::SAVE_STRATEGY_REPLACE) { |
|||
402 | 5 | $this->throughQuery($this->getLocalKeyValue($owner))->delete(); |
|||
403 | } |
||||
404 | |||||
405 | // Attach new relations |
||||
406 | 5 | return $this->attach($owner, $this->getRelation($owner)); |
|||
407 | } |
||||
408 | |||||
409 | /** |
||||
410 | * {@inheritdoc} |
||||
411 | */ |
||||
412 | #[WriteOperation] |
||||
413 | 4 | public function deleteAll($owner, array $relations = []): int |
|||
414 | { |
||||
415 | 4 | return $this->detach($owner, $this->getRelation($owner)); |
|||
416 | } |
||||
417 | |||||
418 | /** |
||||
419 | * Check whether the owner has a distant entity relation |
||||
420 | * |
||||
421 | * @param L $owner |
||||
0 ignored issues
–
show
The type
Bdf\Prime\Relations\L was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||||
422 | * @param string|R $entity |
||||
423 | * |
||||
424 | * @return boolean |
||||
425 | * @throws PrimeException |
||||
426 | */ |
||||
427 | #[ReadOperation] |
||||
428 | 3 | public function has($owner, $entity): bool |
|||
429 | { |
||||
430 | 3 | $data = [$this->throughLocal => $this->getLocalKeyValue($owner)]; |
|||
431 | |||||
432 | 3 | if (!is_object($entity)) { |
|||
433 | $data[$this->throughDistant] = $entity; |
||||
434 | } else { |
||||
435 | 3 | $data[$this->throughDistant] = $this->getDistantKeyValue($entity); |
|||
436 | } |
||||
437 | |||||
438 | 3 | return $this->through->exists($this->through->entity($data)); |
|||
439 | } |
||||
440 | |||||
441 | /** |
||||
442 | * Attach a distant entity to an entity |
||||
443 | * |
||||
444 | * @param L $owner |
||||
445 | * @param string|R[]|R $entities |
||||
446 | * |
||||
447 | * @return int |
||||
448 | * @throws PrimeException |
||||
449 | */ |
||||
450 | #[WriteOperation] |
||||
451 | 14 | public function attach($owner, $entities): int |
|||
452 | { |
||||
453 | 14 | if (empty($entities)) { |
|||
454 | return 0; |
||||
455 | } |
||||
456 | |||||
457 | 14 | $ownerId = $this->getLocalKeyValue($owner); |
|||
458 | |||||
459 | 14 | if (!is_array($entities)) { |
|||
460 | 9 | $entities = [$entities]; |
|||
461 | } |
||||
462 | |||||
463 | 14 | $nb = 0; |
|||
464 | |||||
465 | 14 | foreach ($entities as $entity) { |
|||
466 | // distant could be a object or the distant id |
||||
467 | 14 | $data = [$this->throughLocal => $ownerId]; |
|||
468 | |||||
469 | 14 | if (!is_object($entity)) { |
|||
470 | $data[$this->throughDistant] = $entity; |
||||
471 | } else { |
||||
472 | 14 | $data[$this->throughDistant] = $this->getDistantKeyValue($entity); |
|||
473 | } |
||||
474 | |||||
475 | 14 | $nb += $this->through->save($this->through->entity($data)); |
|||
476 | } |
||||
477 | |||||
478 | 14 | return $nb; |
|||
479 | } |
||||
480 | |||||
481 | /** |
||||
482 | * Detach a distant entity of an entity |
||||
483 | * |
||||
484 | * @param L $owner |
||||
485 | * @param string|R[]|R $entities |
||||
486 | * |
||||
487 | * @return int |
||||
488 | * @throws PrimeException |
||||
489 | */ |
||||
490 | #[WriteOperation] |
||||
491 | 11 | public function detach($owner, $entities): int |
|||
492 | { |
||||
493 | 11 | if (empty($entities)) { |
|||
494 | return 0; |
||||
495 | } |
||||
496 | |||||
497 | 11 | $ownerId = $this->getLocalKeyValue($owner); |
|||
498 | |||||
499 | 11 | if (!is_array($entities)) { |
|||
500 | 3 | $entities = [$entities]; |
|||
501 | } |
||||
502 | |||||
503 | 11 | $nb = 0; |
|||
504 | |||||
505 | 11 | foreach ($entities as $entity) { |
|||
506 | // distant could be a object or the distant id |
||||
507 | 11 | $data = [$this->throughLocal => $ownerId]; |
|||
508 | |||||
509 | 11 | if (!is_object($entity)) { |
|||
510 | $data[$this->throughDistant] = $entity; |
||||
511 | } else { |
||||
512 | 11 | $data[$this->throughDistant] = $this->getDistantKeyValue($entity); |
|||
513 | } |
||||
514 | |||||
515 | 11 | $nb += $this->through->delete($this->through->entity($data)); |
|||
516 | } |
||||
517 | |||||
518 | 11 | return $nb; |
|||
519 | } |
||||
520 | } |
||||
521 |
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.
Either this assignment is in error or an instanceof check should be added for that assignment.