api-platform / api-platform/core

ExactFilter not working with Doctrine embeddables

已關閉
#8,390 1 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視
stale
主要語言
PHP
星號
2.6k
分支
980
平均合併
2 天 4 小時
30 天內合併 PR
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 摘要。