core
core copied to clipboard
Doctrine filter not working on itemOperations
API Platform version(s) affected: 2.6.8
Description
In a project which uses PostgreSQL and API-Platform, I need to filter all records by a locale string. A doctrine filter is my preferred choice to do so.
This is the filter:
class LocaleFilter extends SQLFilter
{
public const LOCALE_FILTER_NAME = 'locale_filter';
public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias): string
{
if (!$targetEntity->reflClass->implementsInterface(LocalizedEntityInterface::class)) {
return '';
}
return $targetTableAlias . '.locale = ' . $this->getParameter('locale');
}
}
The parameter locale
will be set on each onKernelRequest event, the locale is the value of the header X-Locale
:
public function onKernelRequest(RequestEvent $event): void
{
$locale = $event->getRequest()->headers->get('X-Locale');
$this->setFilterLocale($locale);
}
private function setFilterLocale(string $locale): void
{
if (!$this->entityManager->hasFilters()) {
return;
}
$localeFilter = $this->entityManager->getFilters()->getFilter(LocaleFilter::LOCALE_FILTER_NAME);
$localeFilter->setParameter('locale', $locale);
}
Now, when I send a request to a collectionOperations endpoint, such as http://example.com/products
with the X-Locale
header value de_DE
, the filter is working and I get a response which contains only the according data in de_DE
. When I send a request with locale fr_FR
, I get a response with data in fr_FR
.
But, when I send a request with the same X-Locale
header to a itemOperations endpoint like http://example.com/products/<a-existing-id>
I'm getting the error message The parameter "locale" is not set
which comes from doctrine.
After investigating that issue, I can say that it works when I override the default ItemDataProvider
from API-platform:
<?php
namespace App\DataProvider;
[...]
class ItemDataProvider implements ItemDataProviderInterface
{
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly RequestStack $requestStack,
) {
}
public function getItem(string $resourceClass, $id, ?string $operationName = null, array $context = []): object
{
$locale = $this->requestStack->getMainRequest()->headers->get('X-Locale');
if ($this->entityManager->hasFilters()) {
$localeFilter = $this->entityManager->getFilters()->getFilter(LocaleFilter::LOCALE_FILTER_NAME);
$localeFilter->setParameter('locale', $locale);
}
$query = $this->entityManager->getRepository($resourceClass)
->createQueryBuilder('x')
->where('x.publicId = :pubid')
->setParameter('pubid', $id)
->getQuery();
return $query->getOneOrNullResult();
}
}
But is still required to set the filter value again in "my own" ItemDataProvider. If I delete the first 7 lines of the method getItem
of the ItemDataProvider, I get the same error from above.
That doesn't make sense like that, does it? It seems like Api-Platform overrides the Doctrine filters in the default ItemDataProvider and make them useless. Howewer, I didn't found the reason for that issue.
Overriding the ItemDataProvider is a working workaround, but I don't think it's a good one, since the cause is more likely a bug and that way some features of Api-Platform are no longer present in the whole project.