api-platform / api-platform/core

ExactFilter not working with Doctrine embeddables

Fermée
#8,390 1 commentaire 0 réactions 0 personnes assignées Voir sur GitHub
stale
Langage dominant
PHP
Étoiles
2.6k
Forks
980
Merge moyen
2 j 4 h
PR mergées (30 j)
49

Description

**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...

Guide de contribution

Ouvrir le guide de contribution

Piste de recherche

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.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
php, symfony
Domaine
api, backend, databases
Type d'issue
Bug
Difficulté
4/5
Temps estimé
3-5 jours
Activité
Active
Clarté
Clairement spécifiée
Accessibilité débutants
64/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.