api-platform / api-platform/core

ExactFilter not working with Doctrine embeddables

Chiusa
#8,390 1 commento 0 reazioni 0 assegnatari Vedi su GitHub
stale
Lingua principale
PHP
Stelle
2.6k
Fork
980
Merge medio
2g 4h
PR unite (30g)
49

Descrizione

**API Platform version(s) affected**: 4.3.3

**Description**
When using the `ExactFilter` on a nested entity containing a Doctrine embeddable, to filter and only get records matching one of the embeddable properties, I've got the following error: `[Semantical Error] [...] Error: Class [...] has no field or association named [...]`.

For example:
I've got a `Foo` entity with a `$bars` property which is a 1-n association with a `Bar` entity.
The `Bar` entity has a `Baz` embeddable, which "groups" several properties, like a `$qux` property.

I want `Foo` records where `qux` is equal to `1`.
The url will look like this: `/foos?bars.baz.qux=1`.
If I hadn't an embeddable, and my entity was "flat", it would be equivalent to this: `/foos?bars.bazQux=1`.

When I query `/foos?bars.baz.qux=1`, I've got the following error (which is thrown by Doctrine btw):
`[Semantical Error] line 0, col 1210 near 'qux = :bars_baz_qux_p3)': Error: Class Foo has no field or association named bars.baz.qux`.

When I looked at the generated DQL, I noticed it uses the wrong alias: it uses the alias of the `Foo` entity instead of the `Bar` entity.
That's why Doctrine raises an exception, it looks for a `bars.baz.qux` field on the `Foo` entity, instead of looking for a `baz.qux` field on the `Bar` entity.

```php
SELECT o_a3
FROM Foo o_a3
INNER JOIN o_a3.bars bars_a4
WHERE o_a3.bars.baz.qux = :bars_baz_qux_p3
```
Here, instead of `o_a3.bars.baz.qux`, it should be `bars_a4.baz.qux`.

**How to reproduce**
The embeddable:
```php
new QueryParameter(
filter: new ExactFilter(),
),
],
)
]
)]
class Foo
{
#[ORM\Id]
#[ORM\Column(type: 'uuid', unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
public ?Uuid $id = null;

/** @var Collection */
#[ORM\OneToMany(targetEntity: Bar::class)]
public Collection $bars;

public function __construct()
{
$this->bars = new ArrayCollection();
}
}

```

**Possible Solution**
The problem probably lies in the lines `57` & `58` of the `ApiPlatform\Doctrine\Orm\Filter\ExactFilter` class.
```php
$queryBuilder
->{$context['whereClause'] ?? 'andWhere'}(\sprintf('%s.%s %s :%s', $alias, $property, $operator, $parameterName));
```
I guess one solution could be to read the doctrine metadata to detect whether the property is part of an embeddable, get the name of the parent entity, and figure out the alias used in the `JOIN`.
Easy to say I guess...

Guida per i contributori

Apri la guida per i contributori

Direzione di ricerca

Start in ApiPlatform\Doctrine\Orm\Filter\ExactFilter at the reported lines 57-58 and reproduce the `/foos?bars.baz.qux=1` query from the issue. Inspect the generated DQL and Doctrine join aliases; done means the condition uses the joined Bar alias for the embeddable property and the query no longer raises the semantic error.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
php, symfony
Ambito
api, backend, databases
Tipo di issue
Bug
Difficoltà
4/5
Tempo stimato
3-5 giorni
Stato di attività
Attiva
Chiarezza
Specificata chiaramente
Idoneità per principianti
64/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.