Skip to content

Commit 1bddff8

Browse files
authored
fix(doctrine): inject nameConverter into AbstractFilter via QueryParameter (#7877)
Fixes #7866
1 parent fff8213 commit 1bddff8

15 files changed

Lines changed: 320 additions & 873 deletions

File tree

filters.md

Lines changed: 0 additions & 869 deletions
This file was deleted.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <dunglas@gmail.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Doctrine\Common\Filter;
15+
16+
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
17+
18+
interface NameConverterAwareInterface
19+
{
20+
public function hasNameConverter(): bool;
21+
22+
public function getNameConverter(): ?NameConverterInterface;
23+
24+
public function setNameConverter(NameConverterInterface $nameConverter): void;
25+
}

src/Doctrine/Common/ParameterExtensionTrait.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@
1515

1616
use ApiPlatform\Doctrine\Common\Filter\LoggerAwareInterface;
1717
use ApiPlatform\Doctrine\Common\Filter\ManagerRegistryAwareInterface;
18+
use ApiPlatform\Doctrine\Common\Filter\NameConverterAwareInterface;
1819
use ApiPlatform\Doctrine\Common\Filter\PropertyAwareFilterInterface;
1920
use ApiPlatform\Metadata\Parameter;
2021
use Doctrine\Persistence\ManagerRegistry;
2122
use Psr\Container\ContainerInterface;
2223
use Psr\Log\LoggerInterface;
24+
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
2325

2426
trait ParameterExtensionTrait
2527
{
@@ -28,6 +30,7 @@ trait ParameterExtensionTrait
2830
protected ContainerInterface $filterLocator;
2931
protected ?ManagerRegistry $managerRegistry = null;
3032
protected ?LoggerInterface $logger = null;
33+
protected ?NameConverterInterface $nameConverter = null;
3134

3235
/**
3336
* @param object $filter the filter instance to configure
@@ -43,6 +46,10 @@ private function configureFilter(object $filter, Parameter $parameter): void
4346
$filter->setLogger($this->logger);
4447
}
4548

49+
if ($this->nameConverter && $filter instanceof NameConverterAwareInterface && !$filter->hasNameConverter()) {
50+
$filter->setNameConverter($this->nameConverter);
51+
}
52+
4653
if ($filter instanceof PropertyAwareFilterInterface) {
4754
$properties = [];
4855
// Check if the filter has getProperties method (e.g., if it's an AbstractFilter)

src/Doctrine/Odm/Extension/ParameterExtension.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use Doctrine\ODM\MongoDB\Aggregation\Builder;
2323
use Psr\Container\ContainerInterface;
2424
use Psr\Log\LoggerInterface;
25+
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
2526

2627
/**
2728
* Reads operation parameters and execute its filter.
@@ -36,10 +37,12 @@ public function __construct(
3637
ContainerInterface $filterLocator,
3738
?ManagerRegistry $managerRegistry = null,
3839
?LoggerInterface $logger = null,
40+
?NameConverterInterface $nameConverter = null,
3941
) {
4042
$this->filterLocator = $filterLocator;
4143
$this->managerRegistry = $managerRegistry;
4244
$this->logger = $logger;
45+
$this->nameConverter = $nameConverter;
4346
}
4447

4548
/**

src/Doctrine/Odm/Filter/AbstractFilter.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
namespace ApiPlatform\Doctrine\Odm\Filter;
1515

1616
use ApiPlatform\Doctrine\Common\Filter\ManagerRegistryAwareInterface;
17+
use ApiPlatform\Doctrine\Common\Filter\NameConverterAwareInterface;
1718
use ApiPlatform\Doctrine\Common\Filter\PropertyAwareFilterInterface;
1819
use ApiPlatform\Doctrine\Common\PropertyHelperTrait;
1920
use ApiPlatform\Doctrine\Odm\PropertyHelperTrait as MongoDbOdmPropertyHelperTrait;
@@ -32,7 +33,7 @@
3233
*
3334
* @author Alan Poulain <contact@alanpoulain.eu>
3435
*/
35-
abstract class AbstractFilter implements FilterInterface, PropertyAwareFilterInterface, ManagerRegistryAwareInterface
36+
abstract class AbstractFilter implements FilterInterface, PropertyAwareFilterInterface, ManagerRegistryAwareInterface, NameConverterAwareInterface
3637
{
3738
use MongoDbOdmPropertyHelperTrait;
3839
use PropertyHelperTrait;
@@ -85,6 +86,21 @@ public function setManagerRegistry(ManagerRegistry $managerRegistry): void
8586
$this->managerRegistry = $managerRegistry;
8687
}
8788

89+
public function hasNameConverter(): bool
90+
{
91+
return $this->nameConverter instanceof NameConverterInterface;
92+
}
93+
94+
public function getNameConverter(): ?NameConverterInterface
95+
{
96+
return $this->nameConverter;
97+
}
98+
99+
public function setNameConverter(NameConverterInterface $nameConverter): void
100+
{
101+
$this->nameConverter = $nameConverter;
102+
}
103+
88104
/**
89105
* @return array<string, mixed>|null
90106
*/

src/Doctrine/Odm/Tests/Extension/ParameterExtensionTest.php

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use ApiPlatform\Doctrine\Common\Filter\LoggerAwareTrait;
1818
use ApiPlatform\Doctrine\Common\Filter\ManagerRegistryAwareInterface;
1919
use ApiPlatform\Doctrine\Common\Filter\ManagerRegistryAwareTrait;
20+
use ApiPlatform\Doctrine\Common\Filter\NameConverterAwareInterface;
2021
use ApiPlatform\Doctrine\Odm\Extension\ParameterExtension;
2122
use ApiPlatform\Doctrine\Odm\Filter\FilterInterface;
2223
use ApiPlatform\Metadata\BackwardCompatibleFilterDescriptionTrait;
@@ -30,6 +31,7 @@
3031
use PHPUnit\Framework\TestCase;
3132
use Psr\Container\ContainerInterface;
3233
use Psr\Log\LoggerInterface;
34+
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
3335

3436
class ParameterExtensionTest extends TestCase
3537
{
@@ -123,6 +125,62 @@ public function apply(Builder $aggregationBuilder, string $resourceClass, ?Opera
123125
$this->assertNotNull($filter->getManagerRegistry());
124126
}
125127

128+
public function testApplyToCollectionWithNameConverter(): void
129+
{
130+
$aggregationBuilder = $this->createMock(Builder::class);
131+
$nameConverter = $this->createMock(NameConverterInterface::class);
132+
133+
$filter = new class($nameConverter) implements FilterInterface, NameConverterAwareInterface {
134+
use BackwardCompatibleFilterDescriptionTrait;
135+
136+
private ?NameConverterInterface $nameConverter = null;
137+
138+
public function __construct(private readonly NameConverterInterface $expectedNameConverter)
139+
{
140+
}
141+
142+
public function hasNameConverter(): bool
143+
{
144+
return $this->nameConverter instanceof NameConverterInterface;
145+
}
146+
147+
public function getNameConverter(): ?NameConverterInterface
148+
{
149+
return $this->nameConverter;
150+
}
151+
152+
public function setNameConverter(NameConverterInterface $nameConverter): void
153+
{
154+
$this->nameConverter = $nameConverter;
155+
}
156+
157+
public function apply(Builder $aggregationBuilder, string $resourceClass, ?Operation $operation = null, array &$context = []): void
158+
{
159+
Assert::assertTrue($this->hasNameConverter());
160+
Assert::assertSame($this->expectedNameConverter, $this->getNameConverter());
161+
Assert::assertSame('SomeClass', $resourceClass);
162+
}
163+
};
164+
165+
$operation = (new GetCollection())
166+
->withParameters([
167+
(new QueryParameter(
168+
key: 'param1',
169+
filter: $filter,
170+
))->setValue(1),
171+
]);
172+
173+
$extension = new ParameterExtension(
174+
$this->createNonCalledFilterLocator(),
175+
nameConverter: $nameConverter,
176+
);
177+
$context = [];
178+
$extension->applyToCollection($aggregationBuilder, 'SomeClass', $operation, $context);
179+
180+
$this->assertSame([], $context);
181+
$this->assertSame($nameConverter, $filter->getNameConverter());
182+
}
183+
126184
public function testApplyToCollectionPassesContext(): void
127185
{
128186
$aggregationBuilder = $this->createMock(Builder::class);

src/Doctrine/Odm/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
],
2626
"require": {
2727
"php": ">=8.2",
28-
"api-platform/doctrine-common": "^4.2.9",
28+
"api-platform/doctrine-common": "^4.2.23",
2929
"api-platform/metadata": "^4.2",
3030
"api-platform/state": "^4.2.4",
3131
"doctrine/mongodb-odm": "^2.10",

src/Doctrine/Orm/Extension/ParameterExtension.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use Doctrine\Persistence\ManagerRegistry;
2323
use Psr\Container\ContainerInterface;
2424
use Psr\Log\LoggerInterface;
25+
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
2526

2627
/**
2728
* Reads operation parameters and execute its filter.
@@ -36,10 +37,12 @@ public function __construct(
3637
ContainerInterface $filterLocator,
3738
?ManagerRegistry $managerRegistry = null,
3839
?LoggerInterface $logger = null,
40+
?NameConverterInterface $nameConverter = null,
3941
) {
4042
$this->filterLocator = $filterLocator;
4143
$this->managerRegistry = $managerRegistry;
4244
$this->logger = $logger;
45+
$this->nameConverter = $nameConverter;
4346
}
4447

4548
/**

src/Doctrine/Orm/Filter/AbstractFilter.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
namespace ApiPlatform\Doctrine\Orm\Filter;
1515

1616
use ApiPlatform\Doctrine\Common\Filter\ManagerRegistryAwareInterface;
17+
use ApiPlatform\Doctrine\Common\Filter\NameConverterAwareInterface;
1718
use ApiPlatform\Doctrine\Common\Filter\PropertyAwareFilterInterface;
1819
use ApiPlatform\Doctrine\Common\PropertyHelperTrait;
1920
use ApiPlatform\Doctrine\Orm\PropertyHelperTrait as OrmPropertyHelperTrait;
@@ -26,7 +27,7 @@
2627
use Psr\Log\NullLogger;
2728
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
2829

29-
abstract class AbstractFilter implements FilterInterface, PropertyAwareFilterInterface, ManagerRegistryAwareInterface
30+
abstract class AbstractFilter implements FilterInterface, PropertyAwareFilterInterface, ManagerRegistryAwareInterface, NameConverterAwareInterface
3031
{
3132
use OrmPropertyHelperTrait;
3233
use PropertyHelperTrait;
@@ -78,6 +79,21 @@ public function setManagerRegistry(ManagerRegistry $managerRegistry): void
7879
$this->managerRegistry = $managerRegistry;
7980
}
8081

82+
public function hasNameConverter(): bool
83+
{
84+
return $this->nameConverter instanceof NameConverterInterface;
85+
}
86+
87+
public function getNameConverter(): ?NameConverterInterface
88+
{
89+
return $this->nameConverter;
90+
}
91+
92+
public function setNameConverter(NameConverterInterface $nameConverter): void
93+
{
94+
$this->nameConverter = $nameConverter;
95+
}
96+
8197
public function getProperties(): ?array
8298
{
8399
return $this->properties;

src/Doctrine/Orm/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
],
2525
"require": {
2626
"php": ">=8.2",
27-
"api-platform/doctrine-common": "^4.2.9",
27+
"api-platform/doctrine-common": "^4.2.23",
2828
"api-platform/metadata": "^4.2",
2929
"api-platform/state": "^4.2.4",
3030
"doctrine/orm": "^2.17 || ^3.0"

0 commit comments

Comments
 (0)