api-platform / api-platform/core

ExactFilter not working with Doctrine embeddables

クローズ
#8,390 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る
stale
主要言語
PHP
スター
2.6k
フォーク
980
平均マージ
2日 4時間
マージ済み PR(30日)
49

説明

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

コントリビューションガイド

コントリビューションガイドを開く

調査の方向性

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.

索引モデルが issue の本文から書いたものです。

評価

技術スタック
php, symfony
領域
api, backend, databases
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
活発
明瞭さ
明確に書かれている
初心者へのやさしさ
64/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。