api-platform / api-platform/core
ExactFilter not working with Doctrine embeddables
- 主要语言
- 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